diff mbox

[QEMU,2/2] kvm: allow configuration of tsc deadline timer advancement

Message ID 20141210162420.218207164@amt.cnet
State New
Headers show

Commit Message

Marcelo Tosatti Dec. 10, 2014, 4:23 p.m. UTC
Add machine option and QMP commands to configure TSC deadline
timer advancement.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>

---
 monitor.c         |   15 ++++++++++
 qapi-schema.json  |   29 +++++++++++++++++++
 qmp-commands.hx   |   48 ++++++++++++++++++++++++++++++++
 target-i386/kvm.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 vl.c              |    4 ++
 5 files changed, 176 insertions(+)

Comments

Paolo Bonzini Dec. 10, 2014, 5:01 p.m. UTC | #1
On 10/12/2014 17:23, Marcelo Tosatti wrote:
> Add machine option and QMP commands to configure TSC deadline
> timer advancement.
> 
> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
> 
> ---
>  monitor.c         |   15 ++++++++++
>  qapi-schema.json  |   29 +++++++++++++++++++
>  qmp-commands.hx   |   48 ++++++++++++++++++++++++++++++++
>  target-i386/kvm.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  vl.c              |    4 ++
>  5 files changed, 176 insertions(+)
> 
> Index: qemu.tscdeadline/qapi-schema.json
> ===================================================================
> --- qemu.tscdeadline.orig/qapi-schema.json
> +++ qemu.tscdeadline/qapi-schema.json
> @@ -3515,3 +3515,32 @@
>  # Since: 2.1
>  ##
>  { 'command': 'rtc-reset-reinjection' }
> +
> +##
> +# @set-lapic-tscdeadline-advance
> +#
> +# This command sets the TSC deadline timer advancement.
> +# This value will be subtracted from the expiration time
> +# of the high resolution timer which emulates
> +# TSC deadline timer.
> +#
> +# Useful to achieve low timer latencies.
> +#
> +# Only supported by KVM acceleration.
> +#
> +# Since: 2.3
> +##
> +{ 'command': 'set-lapic-tscdeadline-advance',
> +  'data': { 'advance':'int' }
> +}
> +
> +##
> +# @get-lapic-tscdeadline-advance
> +#
> +# This command gets the TSC deadline timer advancement.
> +#
> +# Only supported by KVM acceleration.
> +#
> +# Since: 2.3
> +##
> +{ 'command': 'get-lapic-tscdeadline-advance', 'returns': 'int' }

Please add an object property to the x86 CPU object.  It can then be
configured with "-global" on the command line.

> +    ret = kvm_vm_ioctl(s, KVM_SET_TSCDEADLINE_ADVANCE, &adv);
> +    if (ret < 0) {
> +        return ret;
> +    }

Please use KVM_GET/SET_ONE_REG instead of introducing a new set of ioctls.

Paolo

> +    lapic_tscdeadline_advance.advance_ns = advance;
> +
> +    return ret;
> +}
> +
>  int kvm_arch_init(KVMState *s)
>  {
>      uint64_t identity_base = 0xfffbc000;
>      uint64_t shadow_mem;
>      int ret;
>      struct utsname utsname;
> +    uint32_t lapic_advance_ns;
>  
>      ret = kvm_get_supported_msrs(s);
>      if (ret < 0) {
> @@ -894,9 +919,40 @@ int kvm_arch_init(KVMState *s)
>              return ret;
>          }
>      }
> +
> +    lapic_advance_ns = qemu_opt_get_number(qemu_get_machine_opts(),
> +                                           "lapic-tscdeadline-advance",
> +                                           0);
> +    if (lapic_advance_ns) {
> +        ret = kvm_set_lapic_tscdeadline(s, lapic_advance_ns);
> +        if (ret) {
> +            fprintf(stderr, "Set tscdeadline advance failed: %s\n",
> +                    strerror(-ret));
> +            return ret;
> +        }
> +    }
> +
> +
>      return 0;
>  }
>  
> +int64_t qmp_get_lapic_tscdeadline_advance(Error **errp)
> +{
> +    return lapic_tscdeadline_advance.advance_ns;
> +}
> +
> +void qmp_set_lapic_tscdeadline_advance(int64_t advance, Error **errp)
> +{
> +    KVMState *s = kvm_state;
> +    int ret;
> +
> +    ret = kvm_set_lapic_tscdeadline(s, advance);
> +    if (ret) {
> +        error_setg_errno(errp, ret, "set lapic tscdeadline failed");
> +        return;
> +    }
> +}
> +
>  static void set_v8086_seg(struct kvm_segment *lhs, const SegmentCache *rhs)
>  {
>      lhs->selector = rhs->selector;
> Index: qemu.tscdeadline/monitor.c
> ===================================================================
> --- qemu.tscdeadline.orig/monitor.c
> +++ qemu.tscdeadline/monitor.c
> @@ -5447,3 +5447,18 @@ void qmp_rtc_reset_reinjection(Error **e
>      error_set(errp, QERR_FEATURE_DISABLED, "rtc-reset-reinjection");
>  }
>  #endif
> +
> +#if !defined (TARGET_I386) || !defined (CONFIG_KVM)
> +int64_t qmp_get_lapic_tscdeadline_advance(Error **errp)
> +{
> +    error_set(errp, QERR_FEATURE_DISABLED, "get-lapic-tscdeadline-advance");
> +
> +    return 0;
> +}
> +
> +void qmp_set_lapic_tscdeadline_advance(int64_t advance, Error **errp)
> +{
> +    error_set(errp, QERR_FEATURE_DISABLED, "set-lapic-tscdeadline-advance");
> +}
> +#endif
> +
> Index: qemu.tscdeadline/include/hw/boards.h
> ===================================================================
> --- qemu.tscdeadline.orig/include/hw/boards.h
> +++ qemu.tscdeadline/include/hw/boards.h
> @@ -133,6 +133,7 @@ struct MachineState {
>      bool usb;
>      char *firmware;
>      bool iommu;
> +    int lapi_tscdeadline_advance;
>  
>      ram_addr_t ram_size;
>      ram_addr_t maxram_size;
> Index: qemu.tscdeadline/qemu-options.hx
> ===================================================================
> --- qemu.tscdeadline.orig/qemu-options.hx
> +++ qemu.tscdeadline/qemu-options.hx
> @@ -37,7 +37,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_mach
>      "                kvm_shadow_mem=size of KVM shadow MMU\n"
>      "                dump-guest-core=on|off include guest memory in a core dump (default=on)\n"
>      "                mem-merge=on|off controls memory merge support (default: on)\n"
> -    "                iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n",
> +    "                iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n"
> +    "                lapic-tscdeadline-advance=value controls LAPIC tscdeadline timer advancement (default=0)\n",
>      QEMU_ARCH_ALL)
>  STEXI
>  @item -machine [type=]@var{name}[,prop=@var{value}[,...]]
> @@ -66,6 +67,8 @@ the host, de-duplicates identical memory
>  (enabled by default).
>  @item iommu=on|off
>  Enables or disables emulated Intel IOMMU (VT-d) support. The default is off.
> +@item lapic-tscdeadline-advance=value
> +Defines the advancement of LAPIC TSC deadline timer, in nanoseconds.
>  @end table
>  ETEXI
>  
> Index: qemu.tscdeadline/hw/core/machine.c
> ===================================================================
> --- qemu.tscdeadline.orig/hw/core/machine.c
> +++ qemu.tscdeadline/hw/core/machine.c
> @@ -72,6 +72,35 @@ static void machine_set_kvm_shadow_mem(O
>      ms->kvm_shadow_mem = value;
>  }
>  
> +static void machine_get_lapic_tscdeadline_advance(Object *obj, Visitor *v,
> +                                                  void *opaque,
> +                                                  const char *name,
> +                                                  Error **errp)
> +{
> +    MachineState *ms = MACHINE(obj);
> +    int64_t value = ms->kvm_shadow_mem;
> +
> +    visit_type_int(v, &value, name, errp);
> +}
> +
> +static void machine_set_lapic_tscdeadline_advance(Object *obj, Visitor *v,
> +                                                  void *opaque,
> +                                                  const char *name,
> +                                                  Error **errp)
> +{
> +    MachineState *ms = MACHINE(obj);
> +    Error *error = NULL;
> +    int64_t value;
> +
> +    visit_type_int(v, &value, name, &error);
> +    if (error) {
> +        error_propagate(errp, error);
> +        return;
> +    }
> +
> +    ms->lapi_tscdeadline_advance = value;
> +}
> +
>  static char *machine_get_kernel(Object *obj, Error **errp)
>  {
>      MachineState *ms = MACHINE(obj);
> @@ -299,6 +328,10 @@ static void machine_initfn(Object *obj)
>                          machine_get_kvm_shadow_mem,
>                          machine_set_kvm_shadow_mem,
>                          NULL, NULL, NULL);
> +    object_property_add(obj, "lapic-tscdeadline-advance", "int",
> +                        machine_get_lapic_tscdeadline_advance,
> +                        machine_set_lapic_tscdeadline_advance,
> +                        NULL, NULL, NULL);
>      object_property_add_str(obj, "kernel",
>                              machine_get_kernel, machine_set_kernel, NULL);
>      object_property_add_str(obj, "initrd",
> 
>
Marcelo Tosatti Dec. 10, 2014, 5:04 p.m. UTC | #2
On Wed, Dec 10, 2014 at 06:01:21PM +0100, Paolo Bonzini wrote:
> 
> 
> On 10/12/2014 17:23, Marcelo Tosatti wrote:
> > Add machine option and QMP commands to configure TSC deadline
> > timer advancement.
> > 
> > Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
> > 
> > ---
> >  monitor.c         |   15 ++++++++++
> >  qapi-schema.json  |   29 +++++++++++++++++++
> >  qmp-commands.hx   |   48 ++++++++++++++++++++++++++++++++
> >  target-i386/kvm.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  vl.c              |    4 ++
> >  5 files changed, 176 insertions(+)
> > 
> > Index: qemu.tscdeadline/qapi-schema.json
> > ===================================================================
> > --- qemu.tscdeadline.orig/qapi-schema.json
> > +++ qemu.tscdeadline/qapi-schema.json
> > @@ -3515,3 +3515,32 @@
> >  # Since: 2.1
> >  ##
> >  { 'command': 'rtc-reset-reinjection' }
> > +
> > +##
> > +# @set-lapic-tscdeadline-advance
> > +#
> > +# This command sets the TSC deadline timer advancement.
> > +# This value will be subtracted from the expiration time
> > +# of the high resolution timer which emulates
> > +# TSC deadline timer.
> > +#
> > +# Useful to achieve low timer latencies.
> > +#
> > +# Only supported by KVM acceleration.
> > +#
> > +# Since: 2.3
> > +##
> > +{ 'command': 'set-lapic-tscdeadline-advance',
> > +  'data': { 'advance':'int' }
> > +}
> > +
> > +##
> > +# @get-lapic-tscdeadline-advance
> > +#
> > +# This command gets the TSC deadline timer advancement.
> > +#
> > +# Only supported by KVM acceleration.
> > +#
> > +# Since: 2.3
> > +##
> > +{ 'command': 'get-lapic-tscdeadline-advance', 'returns': 'int' }
> 
> Please add an object property to the x86 CPU object.  It can then be
> configured with "-global" on the command line.

Don't want to allow individual values for different CPUs. 
It is a per-VM property.

Is it still appropriate to use an object property of the 
CPU object?

> 
> > +    ret = kvm_vm_ioctl(s, KVM_SET_TSCDEADLINE_ADVANCE, &adv);
> > +    if (ret < 0) {
> > +        return ret;
> > +    }
> 
> Please use KVM_GET/SET_ONE_REG instead of introducing a new set of ioctls.
> 
> Paolo
Eric Blake Dec. 10, 2014, 5:06 p.m. UTC | #3
On 12/10/2014 09:23 AM, Marcelo Tosatti wrote:
> Add machine option and QMP commands to configure TSC deadline
> timer advancement.
> 
> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
> 
> ---

> +##
> +# @get-lapic-tscdeadline-advance
> +#
> +# This command gets the TSC deadline timer advancement.
> +#
> +# Only supported by KVM acceleration.
> +#
> +# Since: 2.3
> +##
> +{ 'command': 'get-lapic-tscdeadline-advance', 'returns': 'int' }

Please don't return a bare int.  It is not extensible, if we ever need
multiple named values associated with lapic in the future.  Return a
dictionary instead.
Paolo Bonzini Dec. 10, 2014, 5:09 p.m. UTC | #4
On 10/12/2014 18:04, Marcelo Tosatti wrote:
>> Please add an object property to the x86 CPU object.  It can then be
>> configured with "-global" on the command line.
> 
> Don't want to allow individual values for different CPUs. 
> It is a per-VM property.

Why?  It can cause busy waiting, it would make sense to make it stricter
for realtime CPUs and leave 0 for non-realtime CPUs.

Paolo
Marcelo Tosatti Dec. 10, 2014, 5:27 p.m. UTC | #5
On Wed, Dec 10, 2014 at 06:09:19PM +0100, Paolo Bonzini wrote:
> 
> 
> On 10/12/2014 18:04, Marcelo Tosatti wrote:
> >> Please add an object property to the x86 CPU object.  It can then be
> >> configured with "-global" on the command line.
> > 
> > Don't want to allow individual values for different CPUs. 
> > It is a per-VM property.
> 
> Why?  It can cause busy waiting, it would make sense to make it stricter
> for realtime CPUs and leave 0 for non-realtime CPUs.
> 
> Paolo

HW timer behaviour should be consistent across CPUs, IMO.
Paolo Bonzini Dec. 10, 2014, 5:29 p.m. UTC | #6
On 10/12/2014 18:27, Marcelo Tosatti wrote:
> On Wed, Dec 10, 2014 at 06:09:19PM +0100, Paolo Bonzini wrote:
>>
>>
>> On 10/12/2014 18:04, Marcelo Tosatti wrote:
>>>> Please add an object property to the x86 CPU object.  It can then be
>>>> configured with "-global" on the command line.
>>>
>>> Don't want to allow individual values for different CPUs. 
>>> It is a per-VM property.
>>
>> Why?  It can cause busy waiting, it would make sense to make it stricter
>> for realtime CPUs and leave 0 for non-realtime CPUs.
>>
>> Paolo
> 
> HW timer behaviour should be consistent across CPUs, IMO.

It's not going to be anyway.  Cache line bounces, frequency scaling,
presence of higher-priority RT tasks, etc. can cause different response
for one CPU over the others.

Paolo
Marcelo Tosatti Dec. 10, 2014, 5:35 p.m. UTC | #7
On Wed, Dec 10, 2014 at 06:29:43PM +0100, Paolo Bonzini wrote:
> 
> 
> On 10/12/2014 18:27, Marcelo Tosatti wrote:
> > On Wed, Dec 10, 2014 at 06:09:19PM +0100, Paolo Bonzini wrote:
> >>
> >>
> >> On 10/12/2014 18:04, Marcelo Tosatti wrote:
> >>>> Please add an object property to the x86 CPU object.  It can then be
> >>>> configured with "-global" on the command line.
> >>>
> >>> Don't want to allow individual values for different CPUs. 
> >>> It is a per-VM property.
> >>
> >> Why?  It can cause busy waiting, it would make sense to make it stricter
> >> for realtime CPUs and leave 0 for non-realtime CPUs.
> >>
> >> Paolo
> > 
> > HW timer behaviour should be consistent across CPUs, IMO.
> 
> It's not going to be anyway.  Cache line bounces, frequency scaling,
> presence of higher-priority RT tasks, etc. can cause different response
> for one CPU over the others.
> 
> Paolo

OK i'll change it to per-CPU.
Paolo Bonzini Dec. 10, 2014, 5:55 p.m. UTC | #8
On 10/12/2014 18:35, Marcelo Tosatti wrote:
> On Wed, Dec 10, 2014 at 06:29:43PM +0100, Paolo Bonzini wrote:
>>
>>
>> On 10/12/2014 18:27, Marcelo Tosatti wrote:
>>> On Wed, Dec 10, 2014 at 06:09:19PM +0100, Paolo Bonzini wrote:
>>>>
>>>>
>>>> On 10/12/2014 18:04, Marcelo Tosatti wrote:
>>>>>> Please add an object property to the x86 CPU object.  It can then be
>>>>>> configured with "-global" on the command line.
>>>>>
>>>>> Don't want to allow individual values for different CPUs. 
>>>>> It is a per-VM property.
>>>>
>>>> Why?  It can cause busy waiting, it would make sense to make it stricter
>>>> for realtime CPUs and leave 0 for non-realtime CPUs.
>>>
>>> HW timer behaviour should be consistent across CPUs, IMO.
>>
>> It's not going to be anyway.  Cache line bounces, frequency scaling,
>> presence of higher-priority RT tasks, etc. can cause different response
>> for one CPU over the others.
> 
> OK i'll change it to per-CPU.

Well, my preferred choice would be automatic adjustment with a module
parameter.  If we need manual tuning, per-CPU would be my choice, but
automatic is nicer anyway. :)

Paolo
Radim Krčmář Dec. 10, 2014, 6:39 p.m. UTC | #9
2014-12-10 18:55+0100, Paolo Bonzini:
> Well, my preferred choice would be automatic adjustment with a module
> parameter.  If we need manual tuning, per-CPU would be my choice, but
> automatic is nicer anyway. :)

I agree with Paolo, and think it would be better not to touch QEMU ...
it makes little sense to migrate this value and it is probably going to
be quite similar on every CPU, so a writeable module parameter is a
better starting point.  (We can always turn it into a nightmare later.)

If you measure the difference between the TSC you wanted and got on VM
entry, you can use it to automatically guess a delta for the next timer.
(That is IMO exactly what you would do with a manual tuning.
 The algorithm should probably prefer being a bit late than early too.)
Paolo Bonzini Dec. 10, 2014, 6:59 p.m. UTC | #10
On 10/12/2014 19:39, Radim Krčmář wrote:
> 2014-12-10 18:55+0100, Paolo Bonzini:
>> Well, my preferred choice would be automatic adjustment with a module
>> parameter.  If we need manual tuning, per-CPU would be my choice, but
>> automatic is nicer anyway. :)
> 
> I agree with Paolo, and think it would be better not to touch QEMU ...
> it makes little sense to migrate this value and it is probably going to
> be quite similar on every CPU, so a writeable module parameter is a
> better starting point.  (We can always turn it into a nightmare later.)

Ok, let's start with a simple module parameter, similar to what PLE used
to have.  We can use that to play with kvm-unit-tests.

Paolo
diff mbox

Patch

Index: qemu.tscdeadline/qapi-schema.json
===================================================================
--- qemu.tscdeadline.orig/qapi-schema.json
+++ qemu.tscdeadline/qapi-schema.json
@@ -3515,3 +3515,32 @@ 
 # Since: 2.1
 ##
 { 'command': 'rtc-reset-reinjection' }
+
+##
+# @set-lapic-tscdeadline-advance
+#
+# This command sets the TSC deadline timer advancement.
+# This value will be subtracted from the expiration time
+# of the high resolution timer which emulates
+# TSC deadline timer.
+#
+# Useful to achieve low timer latencies.
+#
+# Only supported by KVM acceleration.
+#
+# Since: 2.3
+##
+{ 'command': 'set-lapic-tscdeadline-advance',
+  'data': { 'advance':'int' }
+}
+
+##
+# @get-lapic-tscdeadline-advance
+#
+# This command gets the TSC deadline timer advancement.
+#
+# Only supported by KVM acceleration.
+#
+# Since: 2.3
+##
+{ 'command': 'get-lapic-tscdeadline-advance', 'returns': 'int' }
Index: qemu.tscdeadline/qmp-commands.hx
===================================================================
--- qemu.tscdeadline.orig/qmp-commands.hx
+++ qemu.tscdeadline/qmp-commands.hx
@@ -3854,3 +3854,51 @@  Move mouse pointer to absolute coordinat
 <- { "return": {} }
 
 EQMP
+
+    {
+        .name       = "set-lapic-tscdeadline-advance",
+        .args_type  = "advance:i",
+        .mhandler.cmd_new = qmp_marshal_input_set_lapic_tscdeadline_advance,
+    },
+
+SQMP
+set-lapic-tscdeadline-advance
+-----------------------------
+
+Set LAPIC tscdeadline timer advancement, in nanoseconds.
+
+Arguments:
+
+- "advance": LAPIC tscdeadline timer advancement (json-int)
+
+Example:
+
+-> { "execute": "set-lapic-tscdeadline-advance 1000" }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "get-lapic-tscdeadline-advance",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_get_lapic_tscdeadline_advance,
+    },
+
+SQMP
+get-lapic-tscdeadline-advance
+-----------------------------
+
+Get LAPIC tscdeadline timer advancement, in nanoseconds.
+
+Arguments: None.
+
+returns a json-object with the following information:
+- "value" : json-int
+
+Example:
+
+-> { "execute": "get-lapic-tscdeadline-advance" }
+<- { "return": {1000} }
+
+EQMP
+
Index: qemu.tscdeadline/vl.c
===================================================================
--- qemu.tscdeadline.orig/vl.c
+++ qemu.tscdeadline/vl.c
@@ -387,6 +387,10 @@  static QemuOptsList qemu_machine_opts =
             .name = "iommu",
             .type = QEMU_OPT_BOOL,
             .help = "Set on/off to enable/disable Intel IOMMU (VT-d)",
+        },{
+            .name = "lapic-tscdeadline-advance",
+            .type = QEMU_OPT_NUMBER,
+            .help = "Set lapic tscdeadline timer advance",
         },
         { /* End of list */ }
     },
Index: qemu.tscdeadline/target-i386/kvm.c
===================================================================
--- qemu.tscdeadline.orig/target-i386/kvm.c
+++ qemu.tscdeadline/target-i386/kvm.c
@@ -37,6 +37,7 @@ 
 #include "hw/pci/pci.h"
 #include "migration/migration.h"
 #include "qapi/qmp/qerror.h"
+#include "qmp-commands.h"
 
 //#define DEBUG_KVM
 
@@ -84,6 +85,10 @@  static bool has_msr_mtrr;
 static bool has_msr_architectural_pmu;
 static uint32_t num_architectural_pmu_counters;
 
+static struct lapic_tscdeadline_advance {
+    unsigned int advance_ns;
+} lapic_tscdeadline_advance;
+
 bool kvm_allows_irq0_override(void)
 {
     return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
@@ -835,12 +840,32 @@  static int kvm_get_supported_msrs(KVMSta
     return ret;
 }
 
+static int kvm_set_lapic_tscdeadline(KVMState *s, uint32_t advance)
+{
+    struct kvm_tscdeadline_advance adv;
+    int ret = 0;
+
+    memset(&adv, 0, sizeof(adv));
+
+    adv.timer_advance = advance;
+
+    ret = kvm_vm_ioctl(s, KVM_SET_TSCDEADLINE_ADVANCE, &adv);
+    if (ret < 0) {
+        return ret;
+    }
+
+    lapic_tscdeadline_advance.advance_ns = advance;
+
+    return ret;
+}
+
 int kvm_arch_init(KVMState *s)
 {
     uint64_t identity_base = 0xfffbc000;
     uint64_t shadow_mem;
     int ret;
     struct utsname utsname;
+    uint32_t lapic_advance_ns;
 
     ret = kvm_get_supported_msrs(s);
     if (ret < 0) {
@@ -894,9 +919,40 @@  int kvm_arch_init(KVMState *s)
             return ret;
         }
     }
+
+    lapic_advance_ns = qemu_opt_get_number(qemu_get_machine_opts(),
+                                           "lapic-tscdeadline-advance",
+                                           0);
+    if (lapic_advance_ns) {
+        ret = kvm_set_lapic_tscdeadline(s, lapic_advance_ns);
+        if (ret) {
+            fprintf(stderr, "Set tscdeadline advance failed: %s\n",
+                    strerror(-ret));
+            return ret;
+        }
+    }
+
+
     return 0;
 }
 
+int64_t qmp_get_lapic_tscdeadline_advance(Error **errp)
+{
+    return lapic_tscdeadline_advance.advance_ns;
+}
+
+void qmp_set_lapic_tscdeadline_advance(int64_t advance, Error **errp)
+{
+    KVMState *s = kvm_state;
+    int ret;
+
+    ret = kvm_set_lapic_tscdeadline(s, advance);
+    if (ret) {
+        error_setg_errno(errp, ret, "set lapic tscdeadline failed");
+        return;
+    }
+}
+
 static void set_v8086_seg(struct kvm_segment *lhs, const SegmentCache *rhs)
 {
     lhs->selector = rhs->selector;
Index: qemu.tscdeadline/monitor.c
===================================================================
--- qemu.tscdeadline.orig/monitor.c
+++ qemu.tscdeadline/monitor.c
@@ -5447,3 +5447,18 @@  void qmp_rtc_reset_reinjection(Error **e
     error_set(errp, QERR_FEATURE_DISABLED, "rtc-reset-reinjection");
 }
 #endif
+
+#if !defined (TARGET_I386) || !defined (CONFIG_KVM)
+int64_t qmp_get_lapic_tscdeadline_advance(Error **errp)
+{
+    error_set(errp, QERR_FEATURE_DISABLED, "get-lapic-tscdeadline-advance");
+
+    return 0;
+}
+
+void qmp_set_lapic_tscdeadline_advance(int64_t advance, Error **errp)
+{
+    error_set(errp, QERR_FEATURE_DISABLED, "set-lapic-tscdeadline-advance");
+}
+#endif
+
Index: qemu.tscdeadline/include/hw/boards.h
===================================================================
--- qemu.tscdeadline.orig/include/hw/boards.h
+++ qemu.tscdeadline/include/hw/boards.h
@@ -133,6 +133,7 @@  struct MachineState {
     bool usb;
     char *firmware;
     bool iommu;
+    int lapi_tscdeadline_advance;
 
     ram_addr_t ram_size;
     ram_addr_t maxram_size;
Index: qemu.tscdeadline/qemu-options.hx
===================================================================
--- qemu.tscdeadline.orig/qemu-options.hx
+++ qemu.tscdeadline/qemu-options.hx
@@ -37,7 +37,8 @@  DEF("machine", HAS_ARG, QEMU_OPTION_mach
     "                kvm_shadow_mem=size of KVM shadow MMU\n"
     "                dump-guest-core=on|off include guest memory in a core dump (default=on)\n"
     "                mem-merge=on|off controls memory merge support (default: on)\n"
-    "                iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n",
+    "                iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n"
+    "                lapic-tscdeadline-advance=value controls LAPIC tscdeadline timer advancement (default=0)\n",
     QEMU_ARCH_ALL)
 STEXI
 @item -machine [type=]@var{name}[,prop=@var{value}[,...]]
@@ -66,6 +67,8 @@  the host, de-duplicates identical memory
 (enabled by default).
 @item iommu=on|off
 Enables or disables emulated Intel IOMMU (VT-d) support. The default is off.
+@item lapic-tscdeadline-advance=value
+Defines the advancement of LAPIC TSC deadline timer, in nanoseconds.
 @end table
 ETEXI
 
Index: qemu.tscdeadline/hw/core/machine.c
===================================================================
--- qemu.tscdeadline.orig/hw/core/machine.c
+++ qemu.tscdeadline/hw/core/machine.c
@@ -72,6 +72,35 @@  static void machine_set_kvm_shadow_mem(O
     ms->kvm_shadow_mem = value;
 }
 
+static void machine_get_lapic_tscdeadline_advance(Object *obj, Visitor *v,
+                                                  void *opaque,
+                                                  const char *name,
+                                                  Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    int64_t value = ms->kvm_shadow_mem;
+
+    visit_type_int(v, &value, name, errp);
+}
+
+static void machine_set_lapic_tscdeadline_advance(Object *obj, Visitor *v,
+                                                  void *opaque,
+                                                  const char *name,
+                                                  Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    Error *error = NULL;
+    int64_t value;
+
+    visit_type_int(v, &value, name, &error);
+    if (error) {
+        error_propagate(errp, error);
+        return;
+    }
+
+    ms->lapi_tscdeadline_advance = value;
+}
+
 static char *machine_get_kernel(Object *obj, Error **errp)
 {
     MachineState *ms = MACHINE(obj);
@@ -299,6 +328,10 @@  static void machine_initfn(Object *obj)
                         machine_get_kvm_shadow_mem,
                         machine_set_kvm_shadow_mem,
                         NULL, NULL, NULL);
+    object_property_add(obj, "lapic-tscdeadline-advance", "int",
+                        machine_get_lapic_tscdeadline_advance,
+                        machine_set_lapic_tscdeadline_advance,
+                        NULL, NULL, NULL);
     object_property_add_str(obj, "kernel",
                             machine_get_kernel, machine_set_kernel, NULL);
     object_property_add_str(obj, "initrd",