I just upgraded to -current and didn't have this patch in for a little
bit, and woof that was super noticable.  Still works for my big VM host.

OK


On 2023 Sep 01 (Fri) at 15:50:31 -0400 (-0400), Dave Voutila wrote:
:Now that my i8259 fix is in, it's safe to expand the testing pool for
:this diff. (Without that fix, users would definitely hit the hung block
:device issue testing this one.) Hoping that folks that run non-OpenBSD
:guests or strange configurations can give it a spin.
:
:This change removes an ioctl(2) call from the vcpu thread hot path in
:vmd. Instead of making that syscall to toggle on/off a pending interrupt
:flag on the vcpu object in vmm(4), it adds a flag into the vm_run_params
:struct sent with the VMM_IOC_RUN ioctl. The in-kernel vcpu runloop can
:now toggle the pending interrupt state prior to vm entry.
:
:mbuhl@ and phessler@ have run this diff on their machines. Current
:observations are reduced average network latency for guests.
:
:My terse measurements using the following btrace script show some
:promising changes in terms of reducing ioctl syscalls:
:
:  /* VMM_IOC_INTR: 0x800c5606 -> 2148292102 */
:  syscall:ioctl:entry
:  /arg1 == 2148292102/
:  {
:    @total[tid] = count();
:    @running[tid] = count();
:  }
:  interval:hz:1
:  {
:    print(@running);
:    clear(@running);
:  }
:
:Measuring from boot of an OpenBSD guest to after the guest finishes
:relinking (based on my manual observation of the libevent thread
:settling down in syscall rate), I see a huge reduction in VMM_IOC_INTR
:ioctls for a single guest:
:
:## -current
:@total[433237]: 1325100  # vcpu thread (!!)
:@total[187073]: 80239    # libevent thread
:
:## with diff
:@total[550347]: 42       # vcpu thread (!!)
:@total[256550]: 86946    # libevent thread
:
:Most of the VMM_IOC_INTR ioctls on the vcpu threads come from seabios
:and the bootloader prodding some of the emulated hardware, but even
:after the bootloader you'll see ~10-20k/s of ioctl's on -current
:vs. ~4-5k/s with the diff.
:
:At steady-state, the vcpu thread no longer makes the VMM_IOC_INTR calls
:at all and you should see the libevent thread calling it at a rate ~100/s
:(probably hardclock?). *Without* the diff, I see a steady 650/s rate on
:the vcpu thread at idle. *With* the diff, it's 0/s at idle. :)
:
:To test:
:- rebuild & install new kernel
:- copy/symlink vmmvar.h into /usr/include/machine/
:- rebuild & re-install vmd & vmctl
:- reboot
:
:-dv
:
:
:diffstat refs/heads/master refs/heads/vmm-vrp_intr_pending
: M  sys/arch/amd64/amd64/vmm_machdep.c  |  10+   0-
: M  sys/arch/amd64/include/vmmvar.h     |   1+   0-
: M  usr.sbin/vmd/vm.c                   |   2+  16-
:
:3 files changed, 13 insertions(+), 16 deletions(-)
:
:diff refs/heads/master refs/heads/vmm-vrp_intr_pending
:commit - 8afcf90fb39e4a84606e93137c2b6c20f44312cb
:commit + 10eeb8a0414ec927b6282473c50043a7027d6b41
:blob - 24a376a8f3bc94bc4a4203fe66c5994594adff46
:blob + e3b6d10a0ae78b12ec2f3296f708b42540ce798e
:--- sys/arch/amd64/amd64/vmm_machdep.c
:+++ sys/arch/amd64/amd64/vmm_machdep.c
:@@ -3973,6 +3973,11 @@ vcpu_run_vmx(struct vcpu *vcpu, struct vm_run_params *
:        */
:       irq = vrp->vrp_irq;
:
:+      if (vrp->vrp_intr_pending)
:+              vcpu->vc_intr = 1;
:+      else
:+              vcpu->vc_intr = 0;
:+
:       if (vrp->vrp_continue) {
:               switch (vcpu->vc_gueststate.vg_exit_reason) {
:               case VMX_EXIT_IO:
:@@ -6381,6 +6386,11 @@ vcpu_run_svm(struct vcpu *vcpu, struct vm_run_params *
:
:       irq = vrp->vrp_irq;
:
:+      if (vrp->vrp_intr_pending)
:+              vcpu->vc_intr = 1;
:+      else
:+              vcpu->vc_intr = 0;
:+
:       /*
:        * If we are returning from userspace (vmd) because we exited
:        * last time, fix up any needed vcpu state first. Which state
:blob - e9f8384cccfde33034d7ac9782610f93eb5dc640
:blob + 88545b54b35dd60280ba87403e343db9463d7419
:--- sys/arch/amd64/include/vmmvar.h
:+++ sys/arch/amd64/include/vmmvar.h
:@@ -456,6 +456,7 @@ struct vm_run_params {
:       uint32_t        vrp_vcpu_id;
:       uint8_t         vrp_continue;           /* Continuing from an exit */
:       uint16_t        vrp_irq;                /* IRQ to inject */
:+      uint8_t         vrp_intr_pending;       /* Additional intrs pending? */
:
:       /* Input/output parameter to VMM_IOC_RUN */
:       struct vm_exit  *vrp_exit;              /* updated exit data */
:blob - 5f598bcc14af5115372d34a4176254d377aad91c
:blob + 447fc219adadf945de2bf25d5335993c2abdc26f
:--- usr.sbin/vmd/vm.c
:+++ usr.sbin/vmd/vm.c
:@@ -1610,22 +1610,8 @@ vcpu_run_loop(void *arg)
:               } else
:                       vrp->vrp_irq = 0xFFFF;
:
:-              /* Still more pending? */
:-              if (i8259_is_pending()) {
:-                      /*
:-                       * XXX can probably avoid ioctls here by providing intr
:-                       * in vrp
:-                       */
:-                      if (vcpu_pic_intr(vrp->vrp_vm_id,
:-                          vrp->vrp_vcpu_id, 1)) {
:-                              fatal("can't set INTR");
:-                      }
:-              } else {
:-                      if (vcpu_pic_intr(vrp->vrp_vm_id,
:-                          vrp->vrp_vcpu_id, 0)) {
:-                              fatal("can't clear INTR");
:-                      }
:-              }
:+              /* Still more interrupts pending? */
:+              vrp->vrp_intr_pending = i8259_is_pending();
:
:               if (ioctl(env->vmd_fd, VMM_IOC_RUN, vrp) == -1) {
:                       /* If run ioctl failed, exit */
:

-- 
"Hey!  Who took the cork off my lunch??!"
                -- W. C. Fields

Reply via email to