diff mbox series

[v3,2/3] vhost: configure all host notifiers in a single MR transaction

Message ID 20221227072015.3134-3-longpeng2@huawei.com (mailing list archive)
State New, archived
Headers show
Series two optimizations to speed up the start time | expand

Commit Message

Zhijian Li (Fujitsu)" via Dec. 27, 2022, 7:20 a.m. UTC
From: Longpeng <longpeng2@huawei.com>

This allows the vhost device to batch the setup of all its host notifiers.
This significantly reduces the device starting time, e.g. the time spend
on enabling notifiers reduce from 376ms to 9.1ms for a VM with 64 vCPUs
and 3 vhost-vDPA generic devices (vdpa_sim_blk, 64vq per device)

Signed-off-by: Longpeng <longpeng2@huawei.com>
---
 hw/virtio/vhost.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

Comments

Philippe Mathieu-Daudé Dec. 27, 2022, 4:43 p.m. UTC | #1
On 27/12/22 08:20, Longpeng(Mike) wrote:
> From: Longpeng <longpeng2@huawei.com>
> 
> This allows the vhost device to batch the setup of all its host notifiers.
> This significantly reduces the device starting time, e.g. the time spend
> on enabling notifiers reduce from 376ms to 9.1ms for a VM with 64 vCPUs
> and 3 vhost-vDPA generic devices (vdpa_sim_blk, 64vq per device)
> 
> Signed-off-by: Longpeng <longpeng2@huawei.com>
> ---
>   hw/virtio/vhost.c | 24 ++++++++++++++++++++++++
>   1 file changed, 24 insertions(+)
> 
> diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
> index 5994559da8..064d4abe5c 100644
> --- a/hw/virtio/vhost.c
> +++ b/hw/virtio/vhost.c
> @@ -1562,16 +1562,25 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
>           return r;
>       }
>   
> +    /*
> +     * Batch all the host notifiers in a single transaction to avoid
> +     * quadratic time complexity in address_space_update_ioeventfds().
> +     */
> +    memory_region_transaction_begin();
> +
>       for (i = 0; i < hdev->nvqs; ++i) {
>           r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
>                                            true);
>           if (r < 0) {
>               error_report("vhost VQ %d notifier binding failed: %d", i, -r);
> +            memory_region_transaction_commit();
>               vhost_dev_disable_notifiers(hdev, vdev);

Could we 'break' here, ...

>               return r;
>           }
>       }
>   
> +    memory_region_transaction_commit();
> +
>       return 0;

... and return 'r' here?

>   }

Otherwise LGTM.
Michael S. Tsirkin Dec. 27, 2022, 5:54 p.m. UTC | #2
On Tue, Dec 27, 2022 at 05:43:57PM +0100, Philippe Mathieu-Daudé wrote:
> On 27/12/22 08:20, Longpeng(Mike) wrote:
> > From: Longpeng <longpeng2@huawei.com>
> > 
> > This allows the vhost device to batch the setup of all its host notifiers.
> > This significantly reduces the device starting time, e.g. the time spend
> > on enabling notifiers reduce from 376ms to 9.1ms for a VM with 64 vCPUs
> > and 3 vhost-vDPA generic devices (vdpa_sim_blk, 64vq per device)
> > 
> > Signed-off-by: Longpeng <longpeng2@huawei.com>
> > ---
> >   hw/virtio/vhost.c | 24 ++++++++++++++++++++++++
> >   1 file changed, 24 insertions(+)
> > 
> > diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
> > index 5994559da8..064d4abe5c 100644
> > --- a/hw/virtio/vhost.c
> > +++ b/hw/virtio/vhost.c
> > @@ -1562,16 +1562,25 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
> >           return r;
> >       }
> > +    /*
> > +     * Batch all the host notifiers in a single transaction to avoid
> > +     * quadratic time complexity in address_space_update_ioeventfds().
> > +     */
> > +    memory_region_transaction_begin();
> > +
> >       for (i = 0; i < hdev->nvqs; ++i) {
> >           r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
> >                                            true);
> >           if (r < 0) {
> >               error_report("vhost VQ %d notifier binding failed: %d", i, -r);
> > +            memory_region_transaction_commit();
> >               vhost_dev_disable_notifiers(hdev, vdev);
> 
> Could we 'break' here, ...
> 
> >               return r;
> >           }
> >       }
> > +    memory_region_transaction_commit();
> > +
> >       return 0;
> 
> ... and return 'r' here?


won't this commit twice? seems ugly ...

> >   }
> 
> Otherwise LGTM.
Philippe Mathieu-Daudé Dec. 28, 2022, 1:12 p.m. UTC | #3
On 27/12/22 18:54, Michael S. Tsirkin wrote:
> On Tue, Dec 27, 2022 at 05:43:57PM +0100, Philippe Mathieu-Daudé wrote:
>> On 27/12/22 08:20, Longpeng(Mike) wrote:
>>> From: Longpeng <longpeng2@huawei.com>
>>>
>>> This allows the vhost device to batch the setup of all its host notifiers.
>>> This significantly reduces the device starting time, e.g. the time spend
>>> on enabling notifiers reduce from 376ms to 9.1ms for a VM with 64 vCPUs
>>> and 3 vhost-vDPA generic devices (vdpa_sim_blk, 64vq per device)
>>>
>>> Signed-off-by: Longpeng <longpeng2@huawei.com>
>>> ---
>>>    hw/virtio/vhost.c | 24 ++++++++++++++++++++++++
>>>    1 file changed, 24 insertions(+)
>>>
>>> diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
>>> index 5994559da8..064d4abe5c 100644
>>> --- a/hw/virtio/vhost.c
>>> +++ b/hw/virtio/vhost.c
>>> @@ -1562,16 +1562,25 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
>>>            return r;
>>>        }
>>> +    /*
>>> +     * Batch all the host notifiers in a single transaction to avoid
>>> +     * quadratic time complexity in address_space_update_ioeventfds().
>>> +     */
>>> +    memory_region_transaction_begin();
>>> +
>>>        for (i = 0; i < hdev->nvqs; ++i) {
>>>            r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
>>>                                             true);
>>>            if (r < 0) {
>>>                error_report("vhost VQ %d notifier binding failed: %d", i, -r);
>>> +            memory_region_transaction_commit();
>>>                vhost_dev_disable_notifiers(hdev, vdev);
>>
>> Could we 'break' here, ...
>>
>>>                return r;
>>>            }
>>>        }
>>> +    memory_region_transaction_commit();
>>> +
>>>        return 0;
>>
>> ... and return 'r' here?
> 
> 
> won't this commit twice? seems ugly ...

Twice? I meant keep the begin/commit() around the for() to have
only *one* commit() call instead of 2:

-- >8 --
+    memory_region_transaction_begin();
+
      for (i = 0; i < hdev->nvqs; ++i) {
          r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), 
hdev->vq_index + i,
                                           true);
          if (r < 0) {
              error_report("vhost VQ %d notifier binding failed: %d", i, 
-r);
              vhost_dev_disable_notifiers(hdev, vdev);
-            return r;
+            break;
          }
      }

+    memory_region_transaction_commit();
+
-    return 0;
+    return r;
  }
---

Anyhow,
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Zhijian Li (Fujitsu)" via Dec. 29, 2022, 5:18 a.m. UTC | #4
在 2022/12/28 21:12, Philippe Mathieu-Daudé 写道:
> On 27/12/22 18:54, Michael S. Tsirkin wrote:
>> On Tue, Dec 27, 2022 at 05:43:57PM +0100, Philippe Mathieu-Daudé wrote:
>>> On 27/12/22 08:20, Longpeng(Mike) wrote:
>>>> From: Longpeng <longpeng2@huawei.com>
>>>>
>>>> This allows the vhost device to batch the setup of all its host 
>>>> notifiers.
>>>> This significantly reduces the device starting time, e.g. the time 
>>>> spend
>>>> on enabling notifiers reduce from 376ms to 9.1ms for a VM with 64 vCPUs
>>>> and 3 vhost-vDPA generic devices (vdpa_sim_blk, 64vq per device)
>>>>
>>>> Signed-off-by: Longpeng <longpeng2@huawei.com>
>>>> ---
>>>>    hw/virtio/vhost.c | 24 ++++++++++++++++++++++++
>>>>    1 file changed, 24 insertions(+)
>>>>
>>>> diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
>>>> index 5994559da8..064d4abe5c 100644
>>>> --- a/hw/virtio/vhost.c
>>>> +++ b/hw/virtio/vhost.c
>>>> @@ -1562,16 +1562,25 @@ int vhost_dev_enable_notifiers(struct 
>>>> vhost_dev *hdev, VirtIODevice *vdev)
>>>>            return r;
>>>>        }
>>>> +    /*
>>>> +     * Batch all the host notifiers in a single transaction to avoid
>>>> +     * quadratic time complexity in address_space_update_ioeventfds().
>>>> +     */
>>>> +    memory_region_transaction_begin();
>>>> +
>>>>        for (i = 0; i < hdev->nvqs; ++i) {
>>>>            r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), 
>>>> hdev->vq_index + i,
>>>>                                             true);
>>>>            if (r < 0) {
>>>>                error_report("vhost VQ %d notifier binding failed: 
>>>> %d", i, -r);
>>>> +            memory_region_transaction_commit();
>>>>                vhost_dev_disable_notifiers(hdev, vdev);
>>>
>>> Could we 'break' here, ...
>>>
>>>>                return r;
>>>>            }
>>>>        }
>>>> +    memory_region_transaction_commit();
>>>> +
>>>>        return 0;
>>>
>>> ... and return 'r' here?
>>
>>
>> won't this commit twice? seems ugly ...
> 
> Twice? I meant keep the begin/commit() around the for() to have
> only *one* commit() call instead of 2:
> 

There's a transaction in vhost_dev_disable_notifiers() too, We must 
commit the outter transaction before invoking it, you can see the 
comment in it.

> -- >8 --
> +    memory_region_transaction_begin();
> +
>       for (i = 0; i < hdev->nvqs; ++i) {
>           r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), 
> hdev->vq_index + i,
>                                            true);
>           if (r < 0) {
>               error_report("vhost VQ %d notifier binding failed: %d", i, 
> -r);
>               vhost_dev_disable_notifiers(hdev, vdev);
> -            return r;
> +            break;
>           }
>       }
> 
> +    memory_region_transaction_commit();
> +
> -    return 0;
> +    return r;
>   }
> ---
> 
> Anyhow,
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> .
diff mbox series

Patch

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 5994559da8..064d4abe5c 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1562,16 +1562,25 @@  int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
         return r;
     }
 
+    /*
+     * Batch all the host notifiers in a single transaction to avoid
+     * quadratic time complexity in address_space_update_ioeventfds().
+     */
+    memory_region_transaction_begin();
+
     for (i = 0; i < hdev->nvqs; ++i) {
         r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
                                          true);
         if (r < 0) {
             error_report("vhost VQ %d notifier binding failed: %d", i, -r);
+            memory_region_transaction_commit();
             vhost_dev_disable_notifiers(hdev, vdev);
             return r;
         }
     }
 
+    memory_region_transaction_commit();
+
     return 0;
 }
 
@@ -1585,6 +1594,12 @@  void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
     int i, r;
 
+    /*
+     * Batch all the host notifiers in a single transaction to avoid
+     * quadratic time complexity in address_space_update_ioeventfds().
+     */
+    memory_region_transaction_begin();
+
     for (i = 0; i < hdev->nvqs; ++i) {
         r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
                                          false);
@@ -1592,6 +1607,15 @@  void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
             error_report("vhost VQ %d notifier cleanup failed: %d", i, -r);
         }
         assert (r >= 0);
+    }
+
+    /*
+     * The transaction expects the ioeventfds to be open when it
+     * commits. Do it now, before the cleanup loop.
+     */
+    memory_region_transaction_commit();
+
+    for (i = 0; i < hdev->nvqs; ++i) {
         virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i);
     }
     virtio_device_release_ioeventfd(vdev);