qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH V5] fsdev: add IO throttle support to fsdev devi


From: Alberto Garcia
Subject: Re: [Qemu-devel] [PATCH V5] fsdev: add IO throttle support to fsdev devices
Date: Fri, 21 Oct 2016 17:02:29 +0200
User-agent: Notmuch/0.18.2 (http://notmuchmail.org) Emacs/24.4.1 (i586-pc-linux-gnu)

On Thu 20 Oct 2016 04:14:23 PM CEST, Pradeep Jagadeesh wrote:
> +static void fsdev_throttle_schedule_next_request(FsThrottle *fst, bool 
> is_write)
> +{
> +    bool must_wait;
> +
> +    if (qemu_co_queue_empty(&fst->throttled_reqs[is_write])) {
> +        return;
> +    }
> +    must_wait = fsdev_throttle_check_for_wait(fst, is_write);
> +    if (!must_wait) {
> +        if (qemu_in_coroutine() &&
> +            qemu_co_queue_next(&fst->throttled_reqs[is_write])) {
> +            ;
> +       } else {
> +           int64_t now = qemu_clock_get_ns(fst->tt.clock_type);
> +           timer_mod(fst->tt.timers[is_write], now + 1);
> +       }
> +   }
> +}

I think you don't need to schedule the timer here. This was added for
group throttling for disks because once a disk completes an I/O request,
the next request might be in a different disk (due to the round-robin
algorithm). So we put a timer in that disk to handle that.

In your case that cannot happen, see fsdev_throttle_request() below[1]
for a suggestion of how it can look like.

> +static void fsdev_throttle_timer_cb(FsThrottle *fst, bool is_write)
> +{
> +    bool empty_queue;
> +    empty_queue = !qemu_co_enter_next(&fst->throttled_reqs[is_write]);
> +    if (empty_queue) {
> +        fsdev_throttle_schedule_next_request(fst, is_write);
> +    }
> +}

This doesn't make any sense, if the throttled_reqs queue is empty then
you're calling fsdev_throttle_schedule_next_request(), but how can a
next request be scheduled if the queue is empty? :-)

You don't need fsdev_throttle_timer_cb() at all, but you can simply do
this instead:

> +static void fsdev_throttle_read_timer_cb(void *opaque)
> +{
       FsThrottle *fst = opaque;
       qemu_co_enter_next(&fst->throttled_reqs[false]);
> +}
> +
> +static void fsdev_throttle_write_timer_cb(void *opaque)
> +{
       FsThrottle *fst = opaque;
       qemu_co_enter_next(&fst->throttled_reqs[true]);
> +}

> +static int get_num_bytes(struct iovec *iov, int iovcnt)
> +{
> +    int index = 0;
> +    int bytes = 0;
> +
> +    while (index < iovcnt) {
> +        bytes += iov[index].iov_len;
> +        index++;
> +    }
> +    return bytes;

You're looping over the iov vector, use a for loop instead, no?:

for (i = 0; i < iovcnt; i++) {
   bytes += iov[i].iov_len;
}

> +void fsdev_throttle_request(FsThrottle *fst, bool is_write,
> +                            struct iovec *iov, int iovcnt)

First, mark the function as running in a coroutine context:

void coroutine_fn fsdev_throttle_request(FsThrottle *fst, bool is_write,
                                         struct iovec *iov, int iovcnt)

> +{
> +    int bytes;
> +
> +    if (throttle_enabled(&fst->cfg)) {

I think it's probably better to check that in the caller, but I don't
have a strong opinion. If you keep it like this, put the definition of
'bytes' inside the if block instead.

> +        bytes = get_num_bytes(iov, iovcnt);
> +        bool must_wait = fsdev_throttle_check_for_wait(fst, is_write);
> +        if (must_wait || 
> !qemu_co_queue_empty(&fst->throttled_reqs[is_write])) {
> +            qemu_co_queue_wait(&fst->throttled_reqs[is_write]);
> +       }
> +       throttle_account(&fst->ts, is_write, bytes);
> +
> +       fsdev_throttle_schedule_next_request(fst, is_write);

So this is the [1] that I mentioned earlier. In your case instead of
fsdev_throttle_schedule_next_request() I think you simply something
like:

    if (!qemu_co_queue_empty(&fst->throttled_reqs[is_write])) {
       /* If there's a timer set, don't do anything else, the timer
          callback will schedule the next request */
       if (fsdev_throttle_check_for_wait(fst, is_write)) {
           return;
       }

       /* If a timer is not set, then schedule the next request now */
       qemu_co_queue_next(&fst->throttled_reqs[is_write]);
    }

Berto



reply via email to

[Prev in Thread] Current Thread [Next in Thread]