Bug 817427 - Libvirtd startup is slow due to QMP capabilities probing
Summary: Libvirtd startup is slow due to QMP capabilities probing
Keywords:
Status: CLOSED CURRENTRELEASE
Alias: None
Product: Virtualization Tools
Classification: Community
Component: libvirt
Version: unspecified
Hardware: x86_64
OS: Linux
unspecified
high
Target Milestone: ---
Assignee: Libvirt Maintainers
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2012-04-30 00:58 UTC by Zeeshan Ali
Modified: 2016-09-20 01:43 UTC (History)
5 users (show)

Fixed In Version: libvirt-1.2.3
Clone Of:
Environment:
Last Closed: 2015-03-16 13:10:17 UTC
Embargoed:


Attachments (Terms of Use)

Description Zeeshan Ali 2012-04-30 00:58:31 UTC
Description of problem:

virConnectGetCapabilities() is slow:

$ time virsh capabilities &> /tmp/caps 

real	0m0.663s
user	0m0.013s
sys	0m0.010s

$ time virsh capabilities &> /tmp/caps

real	0m1.064s
user	0m0.008s
sys	0m0.012s

Contents of /tmp/caps after this call:

<capabilities>

  <host>
    <uuid>cd6a24b3-46f8-01aa-bb39-c39aa2123730</uuid>
    <cpu>
      <arch>x86_64</arch>
      <model>Westmere</model>
      <vendor>Intel</vendor>
      <topology sockets='1' cores='2' threads='2'/>
      <feature name='rdtscp'/>
      <feature name='pdcm'/>
      <feature name='xtpr'/>
      <feature name='tm2'/>
      <feature name='est'/>
      <feature name='smx'/>
      <feature name='vmx'/>
      <feature name='ds_cpl'/>
      <feature name='monitor'/>
      <feature name='dtes64'/>
      <feature name='pclmuldq'/>
      <feature name='pbe'/>
      <feature name='tm'/>
      <feature name='ht'/>
      <feature name='ss'/>
      <feature name='acpi'/>
      <feature name='ds'/>
      <feature name='vme'/>
    </cpu>
    <power_management>
      <suspend_mem/>
      <suspend_disk/>
    </power_management>
    <migration_features>
      <live/>
      <uri_transports>
        <uri_transport>tcp</uri_transport>
      </uri_transports>
    </migration_features>
    <secmodel>
      <model>selinux</model>
      <doi>0</doi>
    </secmodel>
  </host>

  <guest>
    <os_type>hvm</os_type>
    <arch name='i686'>
      <wordsize>32</wordsize>
      <emulator>/home/zeenix/jhbuild/bin/qemu-system-x86_64</emulator>
      <machine>pc-1.1</machine>
      <machine canonical='pc-1.1'>pc</machine>
      <machine>pc-1.0</machine>
      <machine>pc-0.15</machine>
      <machine>pc-0.14</machine>
      <machine>pc-0.13</machine>
      <machine>pc-0.12</machine>
      <machine>pc-0.11</machine>
      <machine>pc-0.10</machine>
      <machine>isapc</machine>
      <domain type='qemu'>
      </domain>
      <domain type='kvm'>
        <emulator>/home/zeenix/jhbuild/bin/qemu-kvm</emulator>
        <machine>pc-1.1</machine>
        <machine canonical='pc-1.1'>pc</machine>
        <machine>pc-1.0</machine>
        <machine>pc-0.15</machine>
        <machine>pc-0.14</machine>
        <machine>pc-0.13</machine>
        <machine>pc-0.12</machine>
        <machine>pc-0.11</machine>
        <machine>pc-0.10</machine>
        <machine>isapc</machine>
      </domain>
    </arch>
    <features>
      <cpuselection/>
      <pae/>
      <nonpae/>
      <acpi default='on' toggle='yes'/>
      <apic default='on' toggle='no'/>
    </features>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='x86_64'>
      <wordsize>64</wordsize>
      <emulator>/home/zeenix/jhbuild/bin/qemu-system-x86_64</emulator>
      <machine>pc-1.1</machine>
      <machine canonical='pc-1.1'>pc</machine>
      <machine>pc-1.0</machine>
      <machine>pc-0.15</machine>
      <machine>pc-0.14</machine>
      <machine>pc-0.13</machine>
      <machine>pc-0.12</machine>
      <machine>pc-0.11</machine>
      <machine>pc-0.10</machine>
      <machine>isapc</machine>
      <domain type='qemu'>
      </domain>
      <domain type='kvm'>
        <emulator>/home/zeenix/jhbuild/bin/qemu-kvm</emulator>
        <machine>pc-1.1</machine>
        <machine canonical='pc-1.1'>pc</machine>
        <machine>pc-1.0</machine>
        <machine>pc-0.15</machine>
        <machine>pc-0.14</machine>
        <machine>pc-0.13</machine>
        <machine>pc-0.12</machine>
        <machine>pc-0.11</machine>
        <machine>pc-0.10</machine>
        <machine>isapc</machine>
      </domain>
    </arch>
    <features>
      <cpuselection/>
      <acpi default='on' toggle='yes'/>
      <apic default='on' toggle='no'/>
    </features>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='arm'>
      <wordsize>32</wordsize>
      <emulator>/home/zeenix/jhbuild/bin/qemu-system-arm</emulator>
      <machine>integratorcp</machine>
      <machine>collie</machine>
      <machine>nuri</machine>
      <machine>smdkc210</machine>
      <machine>connex</machine>
      <machine>verdex</machine>
      <machine>highbank</machine>
      <machine>mainstone</machine>
      <machine>musicpal</machine>
      <machine>n800</machine>
      <machine>n810</machine>
      <machine>sx1</machine>
      <machine>sx1-v1</machine>
      <machine>cheetah</machine>
      <machine>realview-eb</machine>
      <machine>realview-eb-mpcore</machine>
      <machine>realview-pb-a8</machine>
      <machine>realview-pbx-a9</machine>
      <machine>akita</machine>
      <machine>spitz</machine>
      <machine>borzoi</machine>
      <machine>terrier</machine>
      <machine>lm3s811evb</machine>
      <machine>lm3s6965evb</machine>
      <machine>tosa</machine>
      <machine>versatilepb</machine>
      <machine>versatileab</machine>
      <machine>vexpress-a9</machine>
      <machine>vexpress-a15</machine>
      <machine>xilinx-zynq-a9</machine>
      <machine>z2</machine>
      <domain type='qemu'>
      </domain>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='microblaze'>
      <wordsize>32</wordsize>
      <emulator>/home/zeenix/jhbuild/bin/qemu-system-microblaze</emulator>
      <machine>petalogix-s3adsp1800</machine>
      <machine>petalogix-ml605</machine>
      <domain type='qemu'>
      </domain>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='microblazeel'>
      <wordsize>32</wordsize>
      <emulator>/home/zeenix/jhbuild/bin/qemu-system-microblazeel</emulator>
      <machine>petalogix-s3adsp1800</machine>
      <machine>petalogix-ml605</machine>
      <domain type='qemu'>
      </domain>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='mips'>
      <wordsize>32</wordsize>
      <emulator>/home/zeenix/jhbuild/bin/qemu-system-mips</emulator>
      <machine>malta</machine>
      <machine>magnum</machine>
      <machine>pica61</machine>
      <machine>mipssim</machine>
      <machine>mips</machine>
      <domain type='qemu'>
      </domain>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='mipsel'>
      <wordsize>32</wordsize>
      <emulator>/home/zeenix/jhbuild/bin/qemu-system-mipsel</emulator>
      <machine>malta</machine>
      <machine>magnum</machine>
      <machine>pica61</machine>
      <machine>mipssim</machine>
      <machine>mips</machine>
      <domain type='qemu'>
      </domain>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='sparc'>
      <wordsize>32</wordsize>
      <emulator>/home/zeenix/jhbuild/bin/qemu-system-sparc</emulator>
      <machine>SS-5</machine>
      <machine>leon3_generic</machine>
      <machine>SS-10</machine>
      <machine>SS-600MP</machine>
      <machine>SS-20</machine>
      <machine>Voyager</machine>
      <machine>LX</machine>
      <machine>SS-4</machine>
      <machine>SPARCClassic</machine>
      <machine>SPARCbook</machine>
      <machine>SS-1000</machine>
      <machine>SS-2000</machine>
      <machine>SS-2</machine>
      <domain type='qemu'>
      </domain>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='ppc'>
      <wordsize>32</wordsize>
      <emulator>/home/zeenix/jhbuild/bin/qemu-system-ppc</emulator>
      <machine>g3beige</machine>
      <machine>ref405ep</machine>
      <machine>taihu</machine>
      <machine>bamboo</machine>
      <machine>mac99</machine>
      <machine>prep</machine>
      <machine>mpc8544ds</machine>
      <machine>virtex-ml507</machine>
      <domain type='qemu'>
      </domain>
    </arch>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='ppc64'>
      <wordsize>64</wordsize>
      <emulator>/home/zeenix/jhbuild/bin/qemu-system-ppc64</emulator>
      <machine>mac99</machine>
      <machine>ref405ep</machine>
      <machine>taihu</machine>
      <machine>bamboo</machine>
      <machine>g3beige</machine>
      <machine>prep</machine>
      <machine>mpc8544ds</machine>
      <machine>virtex-ml507</machine>
      <domain type='qemu'>
      </domain>
    </arch>
    <features>
      <cpuselection/>
    </features>
  </guest>

  <guest>
    <os_type>hvm</os_type>
    <arch name='s390x'>
      <wordsize>64</wordsize>
      <emulator>/home/zeenix/jhbuild/bin/qemu-system-s390x</emulator>
      <machine>s390-virtio</machine>
      <machine canonical='s390-virtio'>s390</machine>
      <domain type='qemu'>
      </domain>
    </arch>
  </guest>

</capabilities>

Version-Release number of selected component (if applicable): git commit 2d76fea1348123933455847855f7c2796ce08ac9.

How reproducible: always.

Comment 1 Eric Blake 2012-05-03 17:10:15 UTC
See also upstream commit 8e532d34, for another ramification of how caching qemu capabilities up front (including QMP monitor capabilities) would be desirable.

Comment 2 Zeeshan Ali 2013-01-23 13:52:54 UTC
Now this bug is even more severe for us that libvirtd checks caps on each startup:

https://bugzilla.gnome.org/show_bug.cgi?id=688791
https://www.redhat.com/archives/libvir-list/2013-January/msg00563.html

Comment 3 Dave Allan 2013-01-23 18:45:59 UTC
(In reply to comment #1)
> See also upstream commit 8e532d34, for another ramification of how caching
> qemu capabilities up front (including QMP monitor capabilities) would be
> desirable.

Did capability caching ever get committed upstream, btw?

Comment 4 Daniel Berrangé 2013-01-23 18:57:39 UTC
(In reply to comment #3)
> (In reply to comment #1)
> > See also upstream commit 8e532d34, for another ramification of how caching
> > qemu capabilities up front (including QMP monitor capabilities) would be
> > desirable.
> 
> Did capability caching ever get committed upstream, btw?

Yes, capabilities are cached as much as is possible now. Each distinct qemu binary on the host will now only ever be invoked once, unless its timestamp changes.

This complaint is about the fact that even though we're only running each QEMU binary once, this still takes non-negligable time. Approx 300ms per QEMU binary on my laptop. Multiply by anywhere between 10-20 binaries.....

The performance hit has moved from the 'virConnectGetCapabilities' command, to initial libvirtd startup instead. You'll never notice this for the systemd libvirtd since that's started on boot. You will notice it for session libvirtd if your app is what triggers it to launch.  Overall there should not have been any worsening of performance though - given that GNOMES queries capabilities, it will suffer the same delay regardless of where it occurs. And in fact starting VMs should now be 300-600ms faster, since we removed re-probing of QEMU in the VM startup path.

Comment 5 Eric Blake 2013-01-23 19:00:20 UTC
Capability caching is upstream, but done on startup; in comment 2, Zeeshan already pointed to the thread suggesting that we defer caps checks to first use instead of startup, but that has not yet been implemented upstream.

Comment 6 Eric Blake 2013-01-23 19:03:02 UTC
(In reply to comment #4)
> (In reply to comment #3)
> > (In reply to comment #1)
> > > See also upstream commit 8e532d34, for another ramification of how caching
> > > qemu capabilities up front (including QMP monitor capabilities) would be
> > > desirable.
> > 
> > Did capability caching ever get committed upstream, btw?
> 
> Yes, capabilities are cached as much as is possible now. Each distinct qemu
> binary on the host will now only ever be invoked once, unless its timestamp
> changes.
> 
> This complaint is about the fact that even though we're only running each
> QEMU binary once, this still takes non-negligable time. Approx 300ms per
> QEMU binary on my laptop. Multiply by anywhere between 10-20 binaries.....
> 
> The performance hit has moved from the 'virConnectGetCapabilities' command,
> to initial libvirtd startup instead. You'll never notice this for the
> systemd libvirtd since that's started on boot. You will notice it for
> session libvirtd if your app is what triggers it to launch.

But if we KNOW which binary we are using, we only have to probe ONE binary for the guest startup, instead of 10-20 binaries.  Caching would still allow us to avoid reprobing, but delaying the cache population until we need it, instead of probing every single binary, should make things feel faster.  Of course, that depends on whether the guest XML calls out a specific binary to use, vs. the default of leaving it up to us to choose the best binary to use by probing all of them.

Comment 7 Daniel Berrangé 2013-01-23 19:05:54 UTC
(In reply to comment #5)
> Capability caching is upstream, but done on startup; in comment 2, Zeeshan
> already pointed to the thread suggesting that we defer caps checks to first
> use instead of startup, but that has not yet been implemented upstream.

First use of capabilities is when we load configs from disk....which is during startup, so that's not going to help matters.

Comment 8 Daniel Berrangé 2013-01-23 19:08:09 UTC
(In reply to comment #6)
> (In reply to comment #4)
> > (In reply to comment #3)
> > > (In reply to comment #1)
> > > > See also upstream commit 8e532d34, for another ramification of how caching
> > > > qemu capabilities up front (including QMP monitor capabilities) would be
> > > > desirable.
> > > 
> > > Did capability caching ever get committed upstream, btw?
> > 
> > Yes, capabilities are cached as much as is possible now. Each distinct qemu
> > binary on the host will now only ever be invoked once, unless its timestamp
> > changes.
> > 
> > This complaint is about the fact that even though we're only running each
> > QEMU binary once, this still takes non-negligable time. Approx 300ms per
> > QEMU binary on my laptop. Multiply by anywhere between 10-20 binaries.....
> > 
> > The performance hit has moved from the 'virConnectGetCapabilities' command,
> > to initial libvirtd startup instead. You'll never notice this for the
> > systemd libvirtd since that's started on boot. You will notice it for
> > session libvirtd if your app is what triggers it to launch.
> 
> But if we KNOW which binary we are using, we only have to probe ONE binary
> for the guest startup, instead of 10-20 binaries.  Caching would still allow
> us to avoid reprobing, but delaying the cache population until we need it,
> instead of probing every single binary, should make things feel faster.  Of
> course, that depends on whether the guest XML calls out a specific binary to
> use, vs. the default of leaving it up to us to choose the best binary to use
> by probing all of them.

You're mixing 2 different uses of capabilities probing here. During guest startup we need to probe the specific QEMU we're about to run which is fine - we do the right thing here already. Populating a virCapabilitiesPtr struct though requires all QEMUs to be probed, and we need this struct when parsing XML on startup, hence startup requires probing all QEMUs.

Comment 9 Daniel Berrangé 2013-01-23 19:35:31 UTC
Actually I what I wrote earlier was slightly incorrect. Both new and old libvirt *would* create capabilities at startup, but old libvirt would do more work on later virConnectGetCapabilities() calls, where as new libvirt has fully cached them.

The core problem seems to be simply that creating capabilities has gone from 1.5 seconds to approx 6 seconds. 50% of this is due to the fact that new libvirt is probing 25 binaries, where as old libvirt was probing 11 binaries. I'm guessing the other 3 seconds overhead comes from using QMP to probe instead of parsing -help.

Comment 10 Eric Blake 2013-01-23 20:06:17 UTC
Can we use the file system to our advantage, and persistently store capabilities and timestamps of each known qemu binary somewhere under /etc/libvirt/, so that we can reread that file at startup instead of connecting to qemu all over again, in the common case where the file still has the same timestamp?

Comment 11 Daniel Berrangé 2013-01-23 20:40:46 UTC
I'd like to focus on improving our impl before we resort to adding in yet more layers of caching.

Comment 12 Daniel Berrangé 2013-01-23 20:45:49 UTC
Looking at libvirt 0.10.2.1, hacked to print out timing info on caps probing:

2013-01-23 20:41:05.049+0000: 2725: info : libvirt version: 0.10.2.1
2013-01-23 20:41:05.049+0000: 2725: error : qemuCreateCapabilities:334 : CAPS start
2013-01-23 20:41:05.301+0000: 2725: error : qemuCapsInit:1057 : qemu-system-i386: 202ms
2013-01-23 20:41:05.499+0000: 2725: error : qemuCapsInit:1057 : qemu-system-x86_64: 198ms
2013-01-23 20:41:05.586+0000: 2725: error : qemuCapsInit:1057 : qemu-system-arm: 87ms
2013-01-23 20:41:05.669+0000: 2725: error : qemuCapsInit:1057 : qemu-system-microblaze: 83ms
2013-01-23 20:41:05.750+0000: 2725: error : qemuCapsInit:1057 : qemu-system-microblazeel: 81ms
2013-01-23 20:41:05.835+0000: 2725: error : qemuCapsInit:1057 : qemu-system-mips: 85ms
2013-01-23 20:41:05.919+0000: 2725: error : qemuCapsInit:1057 : qemu-system-mipsel: 84ms
2013-01-23 20:41:06.002+0000: 2725: error : qemuCapsInit:1057 : qemu-system-sparc: 83ms
2013-01-23 20:41:06.087+0000: 2725: error : qemuCapsInit:1057 : qemu-system-ppc: 85ms
2013-01-23 20:41:06.202+0000: 2725: error : qemuCapsInit:1057 : qemu-system-ppc64: 115ms
2013-01-23 20:41:06.202+0000: 2725: error : qemuCapsInit:1057 : qemu-system-ia64: 0ms
2013-01-23 20:41:06.284+0000: 2725: error : qemuCapsInit:1057 : qemu-system-s390x: 82ms
2013-01-23 20:41:06.284+0000: 2725: error : qemuCreateCapabilities:339 : CAPS end

The reason i386/x86_64 take twice as long is because they (stupidly) probe the same binary twice - once for qemu mode and once for kvm mode! Each probe launches qemu at least 3 times (for -help, -M ? and -device ? and optionally -cpu ?) It is impressive it is only 85 ms for this.

Now compare libvirt GIT 1.0.1

2013-01-23 20:43:39.357+0000: 3082: info : libvirt version: 1.0.1
2013-01-23 20:43:39.357+0000: 3082: error : qemuCreateCapabilities:424 : Caps start
2013-01-23 20:43:39.405+0000: 3082: error : qemuCapsInit:930 : none: 0ms
2013-01-23 20:43:39.473+0000: 3082: error : qemuCapsInit:930 : alpha: 68ms
2013-01-23 20:43:39.729+0000: 3082: error : qemuCapsInit:930 : armv7l: 256ms
2013-01-23 20:43:39.978+0000: 3082: error : qemuCapsInit:930 : cris: 249ms
2013-01-23 20:43:40.496+0000: 3082: error : qemuCapsInit:930 : i686: 518ms
2013-01-23 20:43:40.497+0000: 3082: error : qemuCapsInit:930 : ia64: 0ms
2013-01-23 20:43:40.736+0000: 3082: error : qemuCapsInit:930 : lm32: 239ms
2013-01-23 20:43:40.994+0000: 3082: error : qemuCapsInit:930 : m68k: 258ms
2013-01-23 20:43:41.240+0000: 3082: error : qemuCapsInit:930 : microblaze: 245ms
2013-01-23 20:43:41.489+0000: 3082: error : qemuCapsInit:930 : microblazeel: 249ms
2013-01-23 20:43:41.746+0000: 3082: error : qemuCapsInit:930 : mips: 257ms
2013-01-23 20:43:42.005+0000: 3082: error : qemuCapsInit:930 : mipsel: 259ms
2013-01-23 20:43:42.019+0000: 3054: error : qemuMonitorIORead:502 : Unable to read from monitor: Connection reset by peer
2013-01-23 20:43:42.111+0000: 3082: error : qemuCapsInit:930 : mips64: 106ms
2013-01-23 20:43:42.367+0000: 3082: error : qemuCapsInit:930 : mips64el: 256ms
2013-01-23 20:43:42.367+0000: 3082: error : qemuCapsInit:930 : openrisc: 0ms
2013-01-23 20:43:42.367+0000: 3082: error : qemuCapsInit:930 : parisc: 0ms
2013-01-23 20:43:42.367+0000: 3082: error : qemuCapsInit:930 : parisc64: 0ms
2013-01-23 20:43:42.642+0000: 3082: error : qemuCapsInit:930 : ppc: 275ms
2013-01-23 20:43:42.917+0000: 3082: error : qemuCapsInit:930 : ppc64: 275ms
2013-01-23 20:43:43.175+0000: 3082: error : qemuCapsInit:930 : ppcemb: 258ms
2013-01-23 20:43:43.175+0000: 3082: error : qemuCapsInit:930 : s390: 0ms
2013-01-23 20:43:43.425+0000: 3082: error : qemuCapsInit:930 : s390x: 250ms
2013-01-23 20:43:43.681+0000: 3082: error : qemuCapsInit:930 : sh4: 255ms
2013-01-23 20:43:43.689+0000: 3054: error : qemuMonitorIORead:502 : Unable to read from monitor: Connection reset by peer
2013-01-23 20:43:43.782+0000: 3082: error : qemuCapsInit:930 : sh4eb: 101ms
2013-01-23 20:43:44.030+0000: 3082: error : qemuCapsInit:930 : sparc: 248ms
2013-01-23 20:43:44.286+0000: 3082: error : qemuCapsInit:930 : sparc64: 256ms
2013-01-23 20:43:44.537+0000: 3082: error : qemuCapsInit:930 : unicore32: 251ms
2013-01-23 20:43:44.797+0000: 3082: error : qemuCapsInit:930 : x86_64: 260ms
2013-01-23 20:43:45.045+0000: 3082: error : qemuCapsInit:930 : xtensa: 248ms
2013-01-23 20:43:45.293+0000: 3082: error : qemuCapsInit:930 : xtensaeb: 248ms
2013-01-23 20:43:45.293+0000: 3082: error : qemuCreateCapabilities:429 : Caps end


The time to probe is roughly the same for each arch, which is what we expect, since the do the exact same work for all. Oddly I see random failures as see by the errors above.  The wierdest thing is that it takes soo much longer to run qemu just once & query via QMP, than to run qemu multiple times. I think we need to investigate just why QMP is taking soo much longer. If we could get back to < 100ms per binary we'd be much closer to previous release performance

Comment 13 Daniel Berrangé 2013-01-23 20:48:19 UTC
BTW, with reference to the original bug report about 'virConnectGetCapabilities' API being slow here is current time for that API

# time virsh capabilities  &> /tmp/caps

real	0m0.040s
user	0m0.007s

so you can see our caching is effective. We thus need to focus on libvirtd startup time - in fact there are quite a few other things in libvirtd startup that time a while - particularly if any VMs are running.

Comment 14 Daniel Berrangé 2013-01-23 21:07:34 UTC
Looking at the debug logs I see these interesting lines

2013-01-23 21:03:23.579+0000: 6041: debug : qemuCapsHook:300 : Switch QEMU uid:gid to 0:0
2013-01-23 21:03:23.781+0000: 6010: debug : qemuMonitorOpenInternal:747 : QEMU_MONITOR_NEW: mon=0x7f9ea80ac830 refs=2 fd=16


So between fork()ing qemu and connecting to the monitor, we have 200ms runtime.

Now looking at qemuMonitorOpenUnix I see

    do {                                                                                                                                              
        ret = connect(monfd, (struct sockaddr *) &addr, sizeof(addr));                                                                                
                                                                                                                                                      
        if (ret == 0)                                                                                                                                 
            break;                                                                                                                                    
                                                                                                                                                      
        if ((errno == ENOENT || errno == ECONNREFUSED) &&                                                                                             
            (!cpid || virProcessKill(cpid, 0) == 0)) {                                                                                                
            /* ENOENT       : Socket may not have shown up yet                                                                                        
             * ECONNREFUSED : Leftover socket hasn't been removed yet */                                                                              
            continue;                                                                                                                                 
        }                                                                                                                                             
                                                                                                                                                      
        virReportSystemError(errno, "%s",                                                                                                             
                             _("failed to connect to monitor socket"));                                                                               
        goto error;                                                                                                                                   
                                                                                                                                                      
    } while ((++i <= timeout*5) && (usleep(.2 * 1000000) <= 0));     

So this indicates we're failing to connect initially, sleeping 200ms then trying again. Of course this 200ms sleep is horrific when multiplied by 25 QEMU binaries to run

Comment 15 Daniel Berrangé 2013-01-24 12:46:14 UTC
So this is the root cause of the 200ms sleep problem

commit 5227a718fceccc98e2d837e279b467c468de0ca2
Author: Viktor Mihajlovski <mihajlov.ibm.com>
Date:   Mon Nov 26 15:17:13 2012 +0100

    qemu: Fix QMP Capabability Probing Failure
    
    QMP Capability probing will fail if QEMU cannot bind to the
    QMP monitor socket in the qemu_driver->libDir directory.
    That's because the child process is stripped of all
    capabilities and this directory is chown'ed to the configured
    QEMU user/group (normally qemu:qemu) by the QEMU driver.
    
    To prevent this from happening, the driver startup will now pass
    the QEMU uid and gid down to the capability probing code.
    All capability probing invocations of QEMU will be run with
    the configured QEMU uid instead of libvirtd's.
    
    Furter, the pid file handling is moved to libvirt, as QEMU
    cannot write to the qemu_driver->runDir (root:root). This also
    means that the libvirt daemonizing must be used.
    
    Signed-off-by: Viktor Mihajlovski <mihajlov.ibm.com>

When I first wrote the code, I intentionally used QEMU's -daemonize arg so that we'd be guaranteed that the monitor socket was present when control returned to libvirt. This code removed that arg, meaning that libvirt would run before QEMU was ready, thus getting into the 200ms sleep loop. It is also the cause of the periodic failures to probe emulators seen in the log

2013-01-23 20:43:43.689+0000: 3054: error : qemuMonitorIORead:502 : Unable to read from monitor: Connection reset by peer

Need to revert much of this change and fix the UID handling properly

Comment 16 Daniel Berrangé 2013-01-24 18:40:24 UTC
Fix proposed here

https://www.redhat.com/archives/libvir-list/2013-January/msg01816.html

Comment 17 Zeeshan Ali 2013-03-01 01:12:21 UTC
(In reply to comment #16)
> Fix proposed here
> 
> https://www.redhat.com/archives/libvir-list/2013-January/msg01816.html

Seems this and some other related fixes has already landed. Should we treat this as fixed then?

Comment 18 Zeeshan Ali 2013-06-24 23:13:02 UTC
ping?

Comment 19 Zeeshan Ali 2014-02-17 18:25:20 UTC
(In reply to Zeeshan Ali from comment #0)
> Description of problem:
> 
> virConnectGetCapabilities() is slow:
> 
> $ time virsh capabilities &> /tmp/caps 
> 
> real	0m0.663s
> user	0m0.013s
> sys	0m0.010s
> 
> $ time virsh capabilities &> /tmp/caps
> 
> real	0m1.064s
> user	0m0.008s
> sys	0m0.012s

Wow, this is not fixed by a long shot (at least not in libvirt 1.1.3.3 in Fedora 20: 

$ time virsh capabilities &> /tmp/caps 

real	0m3.246s
user	0m0.013s
sys	0m0.015s


Can we do something about this rather critical regression anytime soon?

Comment 20 Daniel Berrangé 2014-02-17 19:24:22 UTC
I think you're not measuring the sped of the capabilities API call there. Instead I'd guess libvirtd was not already running, so you're instead measuring libvirtd start up time.

eg the first call will be slow, but the remaining ones very fast

$ killall libvirtd

$ time virsh capabilities > /tmp/a

real	0m1.536s
user	0m0.008s
sys	0m0.007s

$ time virsh capabilities > /tmp/a

real	0m0.020s
user	0m0.009s
sys	0m0.007s

$ time virsh capabilities > /tmp/a

real	0m0.019s
user	0m0.008s
sys	0m0.006s

Comment 21 Zeeshan Ali 2014-02-18 12:53:16 UTC
(In reply to Daniel Berrange from comment #20)
> I think you're not measuring the sped of the capabilities API call there.

The thing is that this bug was about slow startup of libvirt and the reason to use capabilities command as example and for the title of this bug was that I was told by a libvirt dev (you I think?) back then that slow startup is coming from caps probing.

> Instead I'd guess libvirtd was not already running, so you're instead
> measuring libvirtd start up time.
> 
> eg the first call will be slow, but the remaining ones very fast

With libvirtd timing out at 30seconds, this is what is going to be the case most often for Boxes users. I've added a spinner in Boxes because of this but we really shouldn't need that.

Comment 22 Daniel Berrangé 2014-03-05 17:55:25 UTC
This series adds caching of capabilities information. So the first time libvirtd starts it will be slow as now, but thereafter it'll be fast.

https://www.redhat.com/archives/libvir-list/2014-March/msg00297.html

Comment 23 Ján Tomko 2015-03-16 13:10:17 UTC
Merged upstream:
commit cbde35899b901ab3f3108110f23ebf944d7aed74
Author:     Daniel P. Berrange <berrange>
AuthorDate: 2014-03-05 16:51:59 +0000
Commit:     Daniel P. Berrange <berrange>
CommitDate: 2014-03-11 10:59:00 +0000

    Cache result of QEMU capabilities extraction
    
    Extracting capabilities from QEMU takes a notable amount of time
    when all QEMU binaries are installed. Each system emulator
    needs about 200-300ms multiplied by 26 binaries == ~5-8 seconds.
    
    This change causes the QEMU driver to save an XML file containing
    the content of the virQEMUCaps object instance in the cache
    dir eg /var/cache/libvirt/qemu/capabilities/$SHA256(binarypath).xml
    or $HOME/.cache/libvirt/qemu/cache/capabilities/$SHA256(binarypath).xml
    
    We attempt to load this and only if it fails, do we fallback to
    probing the QEMU binary. The ctime of the QEMU binary and libvirtd
    are stored in the cached file and its data discarded if either
    of them change.
    
    Signed-off-by: Daniel P. Berrange <berrange>

git describe: v1.2.2-81-gcbde358 contains: v1.2.3-rc1~306


Note You need to log in before you can comment on or make changes to this bug.