[libvirt] [RFC PATCH] Add support for invtsc timer

Marcelo Tosatti mtosatti at redhat.com
Wed May 7 22:35:13 UTC 2014


On Tue, May 06, 2014 at 03:27:20PM +0200, Ján Tomko wrote:
> Not yet merged in upstream QEMU:
> https://lists.gnu.org/archive/html/qemu-devel/2014-04/msg05024.html
> 
> Add support for invariant TSC timer running at constant rate in
> all ACPI P-, C- and T-states.
> 
> It can be enabled by specifying:
> <clock>
>   <timer name='invtsc' present='yes'/>
> </clock>
> in the domain XML.
> 
> Migration and saving the domain does not work with this timer.
> 
> The support for this timer is indicated by bit 8 of EDX after calling
> CPUID with 0x80000007. It does not show up in /proc/cpuinfo [1]
> and since we're calling qemu without 'enforce', it doesn't error
> out if the host doesn't support this.

It is not a timer, really, but a CPU flag.

> Alternatively, we could expose it in libvirt as a cpu flag:
> <cpu mode='custom' match='exact'>
>   <model fallback='forbid'>qemu64</model>
>   <feature policy='require' name='invtsc'/>
> </cpu>

Would prefer that option. Can't one modify QEMU's "-cpu" parameters, via
libvirt XML?

> or maybe add +invtsc to qemu args when the 'nonstop_tsc' flag is
> requested?

No, since it blocks migration better not condition "+invtsc" on
presence of 'nonstop_tsc' flag.

> 
> [1]:
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/powerflags.c?id=30321c7b#n18
> ---
>  docs/formatdomain.html.in                          |  9 ++++++--
>  docs/schemas/domaincommon.rng                      |  1 +
>  src/conf/domain_conf.c                             |  6 +++--
>  src/conf/domain_conf.h                             |  1 +
>  src/qemu/qemu_command.c                            |  6 +++++
>  src/qemu/qemu_migration.c                          | 14 ++++++++++++
>  .../qemuxml2argv-clock-timer-inv-tsc.args          |  5 +++++
>  .../qemuxml2argv-clock-timer-inv-tsc.xml           | 26 ++++++++++++++++++++++
>  tests/qemuxml2argvtest.c                           |  1 +
>  tests/qemuxml2xmltest.c                            |  1 +
>  10 files changed, 66 insertions(+), 4 deletions(-)
>  create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-clock-timer-inv-tsc.args
>  create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-clock-timer-inv-tsc.xml
> 
> diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
> index 4f19473..1d3fd93 100644
> --- a/docs/formatdomain.html.in
> +++ b/docs/formatdomain.html.in
> @@ -1368,13 +1368,18 @@
>              being modified, and can be one of
>              "platform" (currently unsupported),
>              "hpet" (libxl, xen, qemu), "kvmclock" (qemu),
> -            "pit" (qemu), "rtc" (qemu), "tsc" (libxl) or "hypervclock"
> -            (qemu - <span class="since">since 1.2.2</span>).
> +            "pit" (qemu), "rtc" (qemu), "tsc" (libxl), "hypervclock"
> +            (qemu - <span class="since">since 1.2.2</span>) or
> +            "invtsc" (qemu - <span class="since">since 1.2.5</span>).
>  
>              The <code>hypervclock</code> timer adds support for the
>              reference time counter and the reference page for iTSC
>              feature for guests running the Microsoft Windows
>              operating system.
> +
> +            The <code>invtsc</code> timer adds support for the invariant
> +            TSC. It runs at a constant rate in all ACPI P- C- and T-states.
> +            A guest with this timer enabled cannot be migrated or saved.
>            </dd>
>            <dt><code>track</code></dt>
>            <dd>
> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
> index 4249ed5..5154826 100644
> --- a/docs/schemas/domaincommon.rng
> +++ b/docs/schemas/domaincommon.rng
> @@ -918,6 +918,7 @@
>              <choice>
>                <value>kvmclock</value>
>                <value>hypervclock</value>
> +              <value>invtsc</value>
>              </choice>
>            </attribute>
>          </group>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 6c3bdad..893d904 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -706,7 +706,8 @@ VIR_ENUM_IMPL(virDomainTimerName, VIR_DOMAIN_TIMER_NAME_LAST,
>                "hpet",
>                "tsc",
>                "kvmclock",
> -              "hypervclock");
> +              "hypervclock",
> +              "invtsc");
>  
>  VIR_ENUM_IMPL(virDomainTimerTrack, VIR_DOMAIN_TIMER_TRACK_LAST,
>                "boot",
> @@ -2931,7 +2932,8 @@ virDomainDefPostParseInternal(virDomainDefPtr def,
>          virDomainTimerDefPtr timer = def->clock.timers[i];
>  
>          if (timer->name == VIR_DOMAIN_TIMER_NAME_KVMCLOCK ||
> -            timer->name == VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK) {
> +            timer->name == VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK ||
> +            timer->name == VIR_DOMAIN_TIMER_NAME_INVTSC) {
>              if (timer->tickpolicy != -1) {
>                  virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
>                                 _("timer %s doesn't support setting of "
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index a92f0f3..53c02e6 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -1635,6 +1635,7 @@ enum virDomainTimerNameType {
>      VIR_DOMAIN_TIMER_NAME_TSC,
>      VIR_DOMAIN_TIMER_NAME_KVMCLOCK,
>      VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK,
> +    VIR_DOMAIN_TIMER_NAME_INVTSC,
>  
>      VIR_DOMAIN_TIMER_NAME_LAST
>  };
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 6c1e17d..2994427 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -6736,6 +6736,11 @@ qemuBuildCpuArgStr(virQEMUDriverPtr driver,
>                                have_cpu ? "" : default_model,
>                                timer->present ? '+' : '-');
>              have_cpu = true;
> +        } else if (timer->name == VIR_DOMAIN_TIMER_NAME_INVTSC) {
> +            virBufferAsprintf(&buf, "%s,%cinvtsc",
> +                              have_cpu ? "" : default_model,
> +                              timer->present ? '+' : '-');
> +            have_cpu = true;
>          } else if (timer->name == VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK &&
>                     timer->present) {
>              virBufferAsprintf(&buf, "%s,hv_time",
> @@ -8063,6 +8068,7 @@ qemuBuildCommandLine(virConnectPtr conn,
>  
>          case VIR_DOMAIN_TIMER_NAME_KVMCLOCK:
>          case VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK:
> +        case VIR_DOMAIN_TIMER_NAME_INVTSC:
>              /* Timers above are handled when building -cpu.  */
>          case VIR_DOMAIN_TIMER_NAME_LAST:
>              break;
> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
> index a9f7fea..c1ffc0f 100644
> --- a/src/qemu/qemu_migration.c
> +++ b/src/qemu/qemu_migration.c
> @@ -1513,6 +1513,20 @@ qemuMigrationIsAllowed(virQEMUDriverPtr driver, virDomainObjPtr vm,
>          return false;
>      }
>  
> +    for (i = 0; i < def->clock.ntimers; i++) {
> +        virDomainTimerDefPtr timer = def->clock.timers[i];
> +
> +        if (timer->present != 1)
> +            continue;
> +
> +        if (timer->name == VIR_DOMAIN_TIMER_NAME_INVTSC) {
> +            virReportError(VIR_ERR_OPERATION_INVALID,
> +                           _("domain has '%s' timer"),
> +                           virDomainTimerNameTypeToString(timer->name));
> +            return false;
> +        }
> +    }
> +
>      return true;
>  }
>  
> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-clock-timer-inv-tsc.args b/tests/qemuxml2argvdata/qemuxml2argv-clock-timer-inv-tsc.args
> new file mode 100644
> index 0000000..ae74ae8
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/qemuxml2argv-clock-timer-inv-tsc.args
> @@ -0,0 +1,5 @@
> +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
> +/usr/bin/kvm -S -M pc \
> +-cpu qemu32,+invtsc -m 214 -smp 6 \
> +-nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot n -usb -net \
> +none -serial none -parallel none
> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-clock-timer-inv-tsc.xml b/tests/qemuxml2argvdata/qemuxml2argv-clock-timer-inv-tsc.xml
> new file mode 100644
> index 0000000..b4a82e8
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/qemuxml2argv-clock-timer-inv-tsc.xml
> @@ -0,0 +1,26 @@
> +<domain type='kvm'>
> +  <name>QEMUGuest1</name>
> +  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
> +  <memory unit='KiB'>219100</memory>
> +  <currentMemory unit='KiB'>219100</currentMemory>
> +  <vcpu placement='static'>6</vcpu>
> +  <os>
> +    <type arch='i686' machine='pc'>hvm</type>
> +    <boot dev='network'/>
> +  </os>
> +  <features>
> +    <pae/>
> +  </features>
> +  <clock offset='utc'>
> +    <timer name='invtsc' present='yes'/>
> +  </clock>
> +  <on_poweroff>destroy</on_poweroff>
> +  <on_reboot>restart</on_reboot>
> +  <on_crash>destroy</on_crash>
> +  <devices>
> +    <emulator>/usr/bin/kvm</emulator>
> +    <controller type='usb' index='0'/>
> +    <controller type='pci' index='0' model='pci-root'/>
> +    <memballoon model='virtio'/>
> +  </devices>
> +</domain>
> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
> index 14482fd..3c5024e 100644
> --- a/tests/qemuxml2argvtest.c
> +++ b/tests/qemuxml2argvtest.c
> @@ -641,6 +641,7 @@ mymain(void)
>      DO_TEST("cpu-host-kvmclock", QEMU_CAPS_ENABLE_KVM, QEMU_CAPS_CPU_HOST);
>      DO_TEST("kvmclock", QEMU_CAPS_KVM);
>      DO_TEST("clock-timer-hyperv-rtc", QEMU_CAPS_KVM);
> +    DO_TEST("clock-timer-inv-tsc", QEMU_CAPS_KVM);
>  
>      DO_TEST("cpu-eoi-disabled", QEMU_CAPS_ENABLE_KVM);
>      DO_TEST("cpu-eoi-enabled", QEMU_CAPS_ENABLE_KVM);
> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
> index 3ea03e6..a659cd0 100644
> --- a/tests/qemuxml2xmltest.c
> +++ b/tests/qemuxml2xmltest.c
> @@ -185,6 +185,7 @@ mymain(void)
>      DO_TEST("clock-catchup");
>      DO_TEST("kvmclock");
>      DO_TEST("clock-timer-hyperv-rtc");
> +    DO_TEST("clock-timer-inv-tsc");
>  
>      DO_TEST("cpu-eoi-disabled");
>      DO_TEST("cpu-eoi-enabled");
> -- 
> 1.8.3.2




More information about the libvir-list mailing list