diff mbox

[RFC,v8,20/21] replay: command line options

Message ID 20150122085323.5276.64995.stgit@PASHA-ISP.def.inno
State New
Headers show

Commit Message

Pavel Dovgalyuk Jan. 22, 2015, 8:53 a.m. UTC
This patch introduces command line options for enabling recording or replaying
virtual machine behavior. "-record" option starts recording of the execution
and saves it into the log, specified with "fname" parameter. "-replay" option
is intended for replaying previously saved log.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
---
 cpus.c          |    3 ++-
 qemu-options.hx |    8 ++++++--
 vl.c            |   27 ++++++++++++++++++++++++++-
 3 files changed, 34 insertions(+), 4 deletions(-)

Comments

Paolo Bonzini Jan. 30, 2015, 10:54 a.m. UTC | #1
On 22/01/2015 09:53, Pavel Dovgalyuk wrote:
> This patch introduces command line options for enabling recording or replaying
> virtual machine behavior. "-record" option starts recording of the execution
> and saves it into the log, specified with "fname" parameter. "-replay" option
> is intended for replaying previously saved log.
> 
> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> ---
>  cpus.c          |    3 ++-
>  qemu-options.hx |    8 ++++++--
>  vl.c            |   27 ++++++++++++++++++++++++++-
>  3 files changed, 34 insertions(+), 4 deletions(-)
> 
> diff --git a/cpus.c b/cpus.c
> index 9c32491..7689cec 100644
> --- a/cpus.c
> +++ b/cpus.c
> @@ -912,9 +912,10 @@ static void qemu_wait_io_event_common(CPUState *cpu)
>  static void qemu_tcg_wait_io_event(void)
>  {
>      CPUState *cpu;
> +    GMainContext *context = g_main_context_default();
>  
>      while (all_cpu_threads_idle()) {
> -       /* Start accounting real time to the virtual clock if the CPUs
> +        /* Start accounting real time to the virtual clock if the CPUs
>            are idle.  */
>          qemu_clock_warp(QEMU_CLOCK_VIRTUAL);
>          qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);

Extraneous change.

> diff --git a/qemu-options.hx b/qemu-options.hx
> index 10b9568..cb4b577 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -3037,11 +3037,11 @@ re-inject them.
>  ETEXI
>  
>  DEF("icount", HAS_ARG, QEMU_OPTION_icount, \
> -    "-icount [shift=N|auto][,align=on|off]\n" \
> +    "-icount [shift=N|auto][,align=on|off][,rr=record|replay,rrfname=<filename>]\n" \

rrfile?

>      "                enable virtual instruction counter with 2^N clock ticks per\n" \
>      "                instruction and enable aligning the host and virtual clocks\n", QEMU_ARCH_ALL)
>  STEXI
> -@item -icount [shift=@var{N}|auto]
> +@item -icount [shift=@var{N}|auto][,rr=record|replay,rrfname=@var{filename}]
>  @findex -icount
>  Enable virtual instruction counter.  The virtual cpu will execute one
>  instruction every 2^@var{N} ns of virtual time.  If @code{auto} is specified
> @@ -3063,6 +3063,10 @@ Currently this option does not work when @option{shift} is @code{auto}.
>  Note: The sync algorithm will work for those shift values for which
>  the guest clock runs ahead of the host clock. Typically this happens
>  when the shift value is high (how high depends on the host machine).
> +
> +When @option{rr} option is specified deterministic record/replay is enabled.
> +Replay log is written into @var{filename} file in record mode and
> +read from this file in replay mode.
>  ETEXI
>  
>  DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \
> diff --git a/vl.c b/vl.c
> index ae3e97e..39d9024 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -475,6 +475,12 @@ static QemuOptsList qemu_icount_opts = {
>          }, {
>              .name = "align",
>              .type = QEMU_OPT_BOOL,
> +        }, {
> +            .name = "rr",
> +            .type = QEMU_OPT_STRING,
> +        }, {
> +            .name = "rrfname",
> +            .type = QEMU_OPT_STRING,
>          },
>          { /* end of list */ }
>      },
> @@ -2752,6 +2758,8 @@ int main(int argc, char **argv, char **envp)
>  {
>      int i;
>      int snapshot, linux_boot;
> +    int not_compatible_replay_param = 0;
> +    const char *icount_option = NULL;
>      const char *initrd_filename;
>      const char *kernel_filename, *kernel_cmdline;
>      const char *boot_order;
> @@ -2949,6 +2957,7 @@ int main(int argc, char **argv, char **envp)
>                  break;
>              case QEMU_OPTION_pflash:
>                  drive_add(IF_PFLASH, -1, optarg, PFLASH_OPTS);
> +                not_compatible_replay_param++;

Why not compatible?

>                  break;
>              case QEMU_OPTION_snapshot:
>                  snapshot = 1;
> @@ -3105,6 +3114,7 @@ int main(int argc, char **argv, char **envp)
>  #endif
>              case QEMU_OPTION_bt:
>                  add_device_config(DEV_BT, optarg);
> +                not_compatible_replay_param++;

Could it be enough to add a migration blocker?

>                  break;
>              case QEMU_OPTION_audio_help:
>                  AUD_help ();
> @@ -3244,6 +3254,7 @@ int main(int argc, char **argv, char **envp)
>                  if (!opts) {
>                      exit(1);
>                  }
> +                not_compatible_replay_param++;

Why not compatible?

>                  break;
>              case QEMU_OPTION_fsdev:
>                  olist = qemu_find_opts("fsdev");
> @@ -3372,6 +3383,7 @@ int main(int argc, char **argv, char **envp)
>                  if (strncmp(optarg, "mon:", 4) == 0) {
>                      default_monitor = 0;
>                  }
> +                not_compatible_replay_param++;

Add a migration blocker?

>                  break;
>              case QEMU_OPTION_debugcon:
>                  add_device_config(DEV_DEBUGCON, optarg);
> @@ -3489,6 +3501,7 @@ int main(int argc, char **argv, char **envp)
>                  if (!qemu_opts_parse(qemu_find_opts("smp-opts"), optarg, 1)) {
>                      exit(1);
>                  }
> +                not_compatible_replay_param++;

Check smp_cpus instead in replay_configure?

>                  break;
>              case QEMU_OPTION_vnc:
>  #ifdef CONFIG_VNC
> @@ -3628,6 +3641,7 @@ int main(int argc, char **argv, char **envp)
>                  if (!icount_opts) {
>                      exit(1);
>                  }
> +                replay_configure(icount_opts);

Perhaps move this outside the switch so that you have a fuller view of
the command line?

>                  break;
>              case QEMU_OPTION_incoming:
>                  incoming = optarg;
> @@ -3786,6 +3800,12 @@ int main(int argc, char **argv, char **envp)
>          exit(1);
>      }
>  
> +    if (not_compatible_replay_param && (replay_mode != REPLAY_MODE_NONE)) {
> +        fprintf(stderr, "options -smp, -pflash, -chardev, -bt, -parallel "
> +                        "are not compatible with record/replay\n");
> +        exit(1);
> +    }

... so this (or some replacement) can be done in replay_configure.

>      if (qemu_opts_foreach(qemu_find_opts("sandbox"), parse_sandbox, NULL, 0)) {
>          exit(1);
>      }
> @@ -4136,6 +4156,11 @@ int main(int argc, char **argv, char **envp)
>          qemu_opts_del(icount_opts);
>      }
>  
> +    if (replay_mode != REPLAY_MODE_NONE && !use_icount) {
> +        fprintf(stderr, "Please enable icount to use record/replay\n");
> +        exit(1);
> +    }

Same here.

Paolo

>      /* clean up network at qemu process termination */
>      atexit(&net_cleanup);
>  
> @@ -4172,7 +4197,7 @@ int main(int argc, char **argv, char **envp)
>      }
>  
>      /* open the virtual block devices */
> -    if (snapshot)
> +    if (snapshot || replay_mode != REPLAY_MODE_NONE)
>          qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, NULL, 0);
>      if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func,
>                            &machine_class->block_default_type, 1) != 0) {
>
Pavel Dovgalyuk Feb. 9, 2015, 12:15 p.m. UTC | #2
> From: Paolo Bonzini [mailto:pbonzini@redhat.com]
> On 22/01/2015 09:53, Pavel Dovgalyuk wrote:
> > This patch introduces command line options for enabling recording or replaying
> > virtual machine behavior. "-record" option starts recording of the execution
> > and saves it into the log, specified with "fname" parameter. "-replay" option
> > is intended for replaying previously saved log.
> >
> > Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> >                  break;
> >              case QEMU_OPTION_snapshot:
> >                  snapshot = 1;
> > @@ -3105,6 +3114,7 @@ int main(int argc, char **argv, char **envp)
> >  #endif
> >              case QEMU_OPTION_bt:
> >                  add_device_config(DEV_BT, optarg);
> > +                not_compatible_replay_param++;
> 
> Could it be enough to add a migration blocker?

Record/replay core does not use migration subsystem.
That is why it should check the hardware by itself.

> 
> >                  break;
> >              case QEMU_OPTION_audio_help:
> >                  AUD_help ();
> > @@ -3244,6 +3254,7 @@ int main(int argc, char **argv, char **envp)
> >                  if (!opts) {
> >                      exit(1);
> >                  }
> > +                not_compatible_replay_param++;
> 
> Why not compatible?

Replay for audio adapter will be added in latter patches.
Trying to record/replay machine with audio using current
set of patches will break the replay.

Pavel Dovgalyuk
Paolo Bonzini Feb. 9, 2015, 12:26 p.m. UTC | #3
On 09/02/2015 13:15, Pavel Dovgaluk wrote:
>> From: Paolo Bonzini [mailto:pbonzini@redhat.com]
>> On 22/01/2015 09:53, Pavel Dovgalyuk wrote:
>>> This patch introduces command line options for enabling recording or replaying
>>> virtual machine behavior. "-record" option starts recording of the execution
>>> and saves it into the log, specified with "fname" parameter. "-replay" option
>>> is intended for replaying previously saved log.
>>>
>>> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
>>>                  break;
>>>              case QEMU_OPTION_snapshot:
>>>                  snapshot = 1;
>>> @@ -3105,6 +3114,7 @@ int main(int argc, char **argv, char **envp)
>>>  #endif
>>>              case QEMU_OPTION_bt:
>>>                  add_device_config(DEV_BT, optarg);
>>> +                not_compatible_replay_param++;
>>
>> Could it be enough to add a migration blocker?
> 
> Record/replay core does not use migration subsystem.
> That is why it should check the hardware by itself.

Right.  But is there anything that supports migration but not replay?
If the two overlap, you can just check migration blockers to see if
record/replay can be allowed.

>>
>>>                  break;
>>>              case QEMU_OPTION_audio_help:
>>>                  AUD_help ();
>>> @@ -3244,6 +3254,7 @@ int main(int argc, char **argv, char **envp)
>>>                  if (!opts) {
>>>                      exit(1);
>>>                  }
>>> +                not_compatible_replay_param++;
>>
>> Why not compatible?
> 
> Replay for audio adapter will be added in latter patches.
> Trying to record/replay machine with audio using current
> set of patches will break the replay.

For this case you can try adding a mechanism similar to migration
blockers (replay blockers).

Paolo
Pavel Dovgalyuk Feb. 12, 2015, 9:12 a.m. UTC | #4
> From: Paolo Bonzini [mailto:pbonzini@redhat.com]
> On 09/02/2015 13:15, Pavel Dovgaluk wrote:
> >> From: Paolo Bonzini [mailto:pbonzini@redhat.com]
> >>>                  break;
> >>>              case QEMU_OPTION_audio_help:
> >>>                  AUD_help ();
> >>> @@ -3244,6 +3254,7 @@ int main(int argc, char **argv, char **envp)
> >>>                  if (!opts) {
> >>>                      exit(1);
> >>>                  }
> >>> +                not_compatible_replay_param++;
> >>
> >> Why not compatible?
> >
> > Replay for audio adapter will be added in latter patches.
> > Trying to record/replay machine with audio using current
> > set of patches will break the replay.
> 
> For this case you can try adding a mechanism similar to migration
> blockers (replay blockers).

Do you mean adding flag to vmsd similar to unmigratable?

Pavel Dovgalyuk
Paolo Bonzini Feb. 12, 2015, 2:12 p.m. UTC | #5
On 12/02/2015 10:12, Pavel Dovgaluk wrote:
>>> > >
>>> > > Replay for audio adapter will be added in latter patches.
>>> > > Trying to record/replay machine with audio using current
>>> > > set of patches will break the replay.
>> > 
>> > For this case you can try adding a mechanism similar to migration
>> > blockers (replay blockers).
> Do you mean adding flag to vmsd similar to unmigratable?

No, see this in migration/migration.c:

static GSList *migration_blockers;

void migrate_add_blocker(Error *reason)
{
    migration_blockers = g_slist_prepend(migration_blockers, reason);
}

void migrate_del_blocker(Error *reason)
{
    migration_blockers = g_slist_remove(migration_blockers, reason);
}

...

    if (migration_blockers) {
        *errp = error_copy(migration_blockers->data);
        return;
    }

Paolo
diff mbox

Patch

diff --git a/cpus.c b/cpus.c
index 9c32491..7689cec 100644
--- a/cpus.c
+++ b/cpus.c
@@ -912,9 +912,10 @@  static void qemu_wait_io_event_common(CPUState *cpu)
 static void qemu_tcg_wait_io_event(void)
 {
     CPUState *cpu;
+    GMainContext *context = g_main_context_default();
 
     while (all_cpu_threads_idle()) {
-       /* Start accounting real time to the virtual clock if the CPUs
+        /* Start accounting real time to the virtual clock if the CPUs
           are idle.  */
         qemu_clock_warp(QEMU_CLOCK_VIRTUAL);
         qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);
diff --git a/qemu-options.hx b/qemu-options.hx
index 10b9568..cb4b577 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3037,11 +3037,11 @@  re-inject them.
 ETEXI
 
 DEF("icount", HAS_ARG, QEMU_OPTION_icount, \
-    "-icount [shift=N|auto][,align=on|off]\n" \
+    "-icount [shift=N|auto][,align=on|off][,rr=record|replay,rrfname=<filename>]\n" \
     "                enable virtual instruction counter with 2^N clock ticks per\n" \
     "                instruction and enable aligning the host and virtual clocks\n", QEMU_ARCH_ALL)
 STEXI
-@item -icount [shift=@var{N}|auto]
+@item -icount [shift=@var{N}|auto][,rr=record|replay,rrfname=@var{filename}]
 @findex -icount
 Enable virtual instruction counter.  The virtual cpu will execute one
 instruction every 2^@var{N} ns of virtual time.  If @code{auto} is specified
@@ -3063,6 +3063,10 @@  Currently this option does not work when @option{shift} is @code{auto}.
 Note: The sync algorithm will work for those shift values for which
 the guest clock runs ahead of the host clock. Typically this happens
 when the shift value is high (how high depends on the host machine).
+
+When @option{rr} option is specified deterministic record/replay is enabled.
+Replay log is written into @var{filename} file in record mode and
+read from this file in replay mode.
 ETEXI
 
 DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \
diff --git a/vl.c b/vl.c
index ae3e97e..39d9024 100644
--- a/vl.c
+++ b/vl.c
@@ -475,6 +475,12 @@  static QemuOptsList qemu_icount_opts = {
         }, {
             .name = "align",
             .type = QEMU_OPT_BOOL,
+        }, {
+            .name = "rr",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "rrfname",
+            .type = QEMU_OPT_STRING,
         },
         { /* end of list */ }
     },
@@ -2752,6 +2758,8 @@  int main(int argc, char **argv, char **envp)
 {
     int i;
     int snapshot, linux_boot;
+    int not_compatible_replay_param = 0;
+    const char *icount_option = NULL;
     const char *initrd_filename;
     const char *kernel_filename, *kernel_cmdline;
     const char *boot_order;
@@ -2949,6 +2957,7 @@  int main(int argc, char **argv, char **envp)
                 break;
             case QEMU_OPTION_pflash:
                 drive_add(IF_PFLASH, -1, optarg, PFLASH_OPTS);
+                not_compatible_replay_param++;
                 break;
             case QEMU_OPTION_snapshot:
                 snapshot = 1;
@@ -3105,6 +3114,7 @@  int main(int argc, char **argv, char **envp)
 #endif
             case QEMU_OPTION_bt:
                 add_device_config(DEV_BT, optarg);
+                not_compatible_replay_param++;
                 break;
             case QEMU_OPTION_audio_help:
                 AUD_help ();
@@ -3244,6 +3254,7 @@  int main(int argc, char **argv, char **envp)
                 if (!opts) {
                     exit(1);
                 }
+                not_compatible_replay_param++;
                 break;
             case QEMU_OPTION_fsdev:
                 olist = qemu_find_opts("fsdev");
@@ -3372,6 +3383,7 @@  int main(int argc, char **argv, char **envp)
                 if (strncmp(optarg, "mon:", 4) == 0) {
                     default_monitor = 0;
                 }
+                not_compatible_replay_param++;
                 break;
             case QEMU_OPTION_debugcon:
                 add_device_config(DEV_DEBUGCON, optarg);
@@ -3489,6 +3501,7 @@  int main(int argc, char **argv, char **envp)
                 if (!qemu_opts_parse(qemu_find_opts("smp-opts"), optarg, 1)) {
                     exit(1);
                 }
+                not_compatible_replay_param++;
                 break;
             case QEMU_OPTION_vnc:
 #ifdef CONFIG_VNC
@@ -3628,6 +3641,7 @@  int main(int argc, char **argv, char **envp)
                 if (!icount_opts) {
                     exit(1);
                 }
+                replay_configure(icount_opts);
                 break;
             case QEMU_OPTION_incoming:
                 incoming = optarg;
@@ -3786,6 +3800,12 @@  int main(int argc, char **argv, char **envp)
         exit(1);
     }
 
+    if (not_compatible_replay_param && (replay_mode != REPLAY_MODE_NONE)) {
+        fprintf(stderr, "options -smp, -pflash, -chardev, -bt, -parallel "
+                        "are not compatible with record/replay\n");
+        exit(1);
+    }
+
     if (qemu_opts_foreach(qemu_find_opts("sandbox"), parse_sandbox, NULL, 0)) {
         exit(1);
     }
@@ -4136,6 +4156,11 @@  int main(int argc, char **argv, char **envp)
         qemu_opts_del(icount_opts);
     }
 
+    if (replay_mode != REPLAY_MODE_NONE && !use_icount) {
+        fprintf(stderr, "Please enable icount to use record/replay\n");
+        exit(1);
+    }
+
     /* clean up network at qemu process termination */
     atexit(&net_cleanup);
 
@@ -4172,7 +4197,7 @@  int main(int argc, char **argv, char **envp)
     }
 
     /* open the virtual block devices */
-    if (snapshot)
+    if (snapshot || replay_mode != REPLAY_MODE_NONE)
         qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, NULL, 0);
     if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func,
                           &machine_class->block_default_type, 1) != 0) {