Message ID | 4ab8ba6bf5de4943288c1ddc565179c807f263e3.1403079139.git.amit.shah@redhat.com |
---|---|
State | New |
Headers | show |
Amit Shah <amit.shah@redhat.com> wrote: > This commit adds a new command, '-dump-vmstate', that takes a filename > as a parameter. When executed, QEMU will dump the vmstate information > for the machine type it's invoked with to the file, and quit. > > The JSON-format output can then be used to compare the vmstate info for > different QEMU versions, specifically to test whether live migration > would break due to changes in the vmstate data. > > A Python script that compares the output of such JSON dumps is included > in the following commit. > > Signed-off-by: Amit Shah <amit.shah@redhat.com> > +static void dump_vmstate_vmsd(FILE *out_file, > + const VMStateDescription *vmsd, int indent, > + bool is_subsection) > +{ > + if (is_subsection) { > + fprintf(out_file, "%*s{\n", indent, ""); > + } else { > + fprintf(out_file, "%*s\"%s\": {\n", indent, "", "Description"); > + } > + indent += 2; > + fprintf(out_file, "%*s\"name\": \"%s\",\n", indent, "", vmsd->name); > + fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "", > + vmsd->version_id); > + fprintf(out_file, "%*s\"minimum_version_id\": %d", indent, "", > + vmsd->minimum_version_id); > + if (vmsd->fields != NULL) { > + const VMStateField *field = vmsd->fields; > + bool first; > + > + fprintf(out_file, ",\n%*s\"Fields\": [\n", indent, ""); Remove last "\n" (*) > + first = true; first can go now > + while (field->name != NULL) { > + if (field->flags & VMS_MUST_EXIST) { > + /* Ignore VMSTATE_VALIDATE bits; these don't get migrated */ > + field++; > + continue; > + } > + if (!first) { > + fprintf(out_file, ",\n"); You can print always \n now, right? Same for the other places? Or I am missing something. I will even go that itwould be better to just left the \n on the (*), and just add this \n at the end of writing a subsection. > + fprintf(out_file, "\n%*s}", indent - 2, ""); And you remove it from here. <full disclosure> Yes, I have always hated pretty-printers </full-disclosure> Rest of this, I fully agree. Later, Juan.
On (Wed) 18 Jun 2014 [12:24:25], Juan Quintela wrote: > Amit Shah <amit.shah@redhat.com> wrote: > > This commit adds a new command, '-dump-vmstate', that takes a filename > > as a parameter. When executed, QEMU will dump the vmstate information > > for the machine type it's invoked with to the file, and quit. > > > > The JSON-format output can then be used to compare the vmstate info for > > different QEMU versions, specifically to test whether live migration > > would break due to changes in the vmstate data. > > > > A Python script that compares the output of such JSON dumps is included > > in the following commit. > > > > Signed-off-by: Amit Shah <amit.shah@redhat.com> > > > > > +static void dump_vmstate_vmsd(FILE *out_file, > > + const VMStateDescription *vmsd, int indent, > > + bool is_subsection) > > +{ > > + if (is_subsection) { > > + fprintf(out_file, "%*s{\n", indent, ""); > > + } else { > > + fprintf(out_file, "%*s\"%s\": {\n", indent, "", "Description"); > > + } > > + indent += 2; > > + fprintf(out_file, "%*s\"name\": \"%s\",\n", indent, "", vmsd->name); > > + fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "", > > + vmsd->version_id); > > + fprintf(out_file, "%*s\"minimum_version_id\": %d", indent, "", > > + vmsd->minimum_version_id); > > + if (vmsd->fields != NULL) { > > + const VMStateField *field = vmsd->fields; > > + bool first; > > + > > + fprintf(out_file, ",\n%*s\"Fields\": [\n", indent, ""); > > Remove last "\n" (*) > > > > + first = true; > > first can go now > > > + while (field->name != NULL) { > > + if (field->flags & VMS_MUST_EXIST) { > > + /* Ignore VMSTATE_VALIDATE bits; these don't get migrated */ > > + field++; > > + continue; > > + } > > + if (!first) { > > + fprintf(out_file, ",\n"); > > You can print always \n now, right? There's also a , there... This sequence was added recently (v2 onwards) for the ignoring of the VMS_MUST_EXIST stuff. > Same for the other places? Or I am missing something. > > I will even go that itwould be better to just left the \n on the (*), > and just add this \n at the end of writing a subsection. > > > > + fprintf(out_file, "\n%*s}", indent - 2, ""); > > And you remove it from here. I tried several things with the \n; the current setting is the best I found. Of course, this is just pretty-printing, so I don't actually remember all the details but I can look it up my git tree... > <full disclosure> > Yes, I have always hated pretty-printers > </full-disclosure> Oh, me too! > Rest of this, I fully agree. > > Later, Juan. Amit
Amit Shah <amit.shah@redhat.com> wrote: >> >> You can print always \n now, right? > > There's also a , there... > > This sequence was added recently (v2 onwards) for the ignoring of the > VMS_MUST_EXIST stuff. I knew it needed to be some reason for the ugliness :-() >> Same for the other places? Or I am missing something. >> >> I will even go that itwould be better to just left the \n on the (*), >> and just add this \n at the end of writing a subsection. >> >> >> > + fprintf(out_file, "\n%*s}", indent - 2, ""); >> >> And you remove it from here. > > I tried several things with the \n; the current setting is the best I > found. > > Of course, this is just pretty-printing, so I don't actually remember > all the details but I can look it up my git tree... ok, I retire the comment, and anyways, it is trivial to fix incrementally if you/anybody came with a clever idea. Reviewed-by: Juan Quintela <quintela@redhat.com>
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 7e45048..9829c0e 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -778,4 +778,6 @@ void vmstate_register_ram(struct MemoryRegion *memory, DeviceState *dev); void vmstate_unregister_ram(struct MemoryRegion *memory, DeviceState *dev); void vmstate_register_ram_global(struct MemoryRegion *memory); +void dump_vmstate_json_to_file(FILE *out_fp); + #endif diff --git a/qemu-options.hx b/qemu-options.hx index d0714c4..48d493b 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3221,6 +3221,15 @@ STEXI prepend a timestamp to each log message.(default:on) ETEXI +DEF("dump-vmstate", HAS_ARG, QEMU_OPTION_dump_vmstate, + "-dump-vmstate <file>\n" "", QEMU_ARCH_ALL) +STEXI +@item -dump-vmstate @var{file} +@findex -dump-vmstate +Dump json-encoded vmstate information for current machine type to file +in @var{file} +ETEXI + HXCOMM This is the last statement. Insert new options before this line! STEXI @end table diff --git a/savevm.c b/savevm.c index da8aa24..0c8ad45 100644 --- a/savevm.c +++ b/savevm.c @@ -24,6 +24,7 @@ #include "config-host.h" #include "qemu-common.h" +#include "hw/boards.h" #include "hw/hw.h" #include "hw/qdev.h" #include "net/net.h" @@ -241,6 +242,144 @@ static QTAILQ_HEAD(savevm_handlers, SaveStateEntry) savevm_handlers = QTAILQ_HEAD_INITIALIZER(savevm_handlers); static int global_section_id; +static void dump_vmstate_vmsd(FILE *out_file, + const VMStateDescription *vmsd, int indent, + bool is_subsection); + +static void dump_vmstate_vmsf(FILE *out_file, const VMStateField *field, + int indent) +{ + fprintf(out_file, "%*s{\n", indent, ""); + indent += 2; + fprintf(out_file, "%*s\"field\": \"%s\",\n", indent, "", field->name); + fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "", + field->version_id); + fprintf(out_file, "%*s\"field_exists\": %s,\n", indent, "", + field->field_exists ? "true" : "false"); + fprintf(out_file, "%*s\"size\": %zu", indent, "", field->size); + if (field->vmsd != NULL) { + fprintf(out_file, ",\n"); + dump_vmstate_vmsd(out_file, field->vmsd, indent, false); + } + fprintf(out_file, "\n%*s}", indent - 2, ""); +} + +static void dump_vmstate_vmss(FILE *out_file, + const VMStateSubsection *subsection, + int indent) +{ + if (subsection->vmsd != NULL) { + dump_vmstate_vmsd(out_file, subsection->vmsd, indent, true); + } +} + +static void dump_vmstate_vmsd(FILE *out_file, + const VMStateDescription *vmsd, int indent, + bool is_subsection) +{ + if (is_subsection) { + fprintf(out_file, "%*s{\n", indent, ""); + } else { + fprintf(out_file, "%*s\"%s\": {\n", indent, "", "Description"); + } + indent += 2; + fprintf(out_file, "%*s\"name\": \"%s\",\n", indent, "", vmsd->name); + fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "", + vmsd->version_id); + fprintf(out_file, "%*s\"minimum_version_id\": %d", indent, "", + vmsd->minimum_version_id); + if (vmsd->fields != NULL) { + const VMStateField *field = vmsd->fields; + bool first; + + fprintf(out_file, ",\n%*s\"Fields\": [\n", indent, ""); + first = true; + while (field->name != NULL) { + if (field->flags & VMS_MUST_EXIST) { + /* Ignore VMSTATE_VALIDATE bits; these don't get migrated */ + field++; + continue; + } + if (!first) { + fprintf(out_file, ",\n"); + } + dump_vmstate_vmsf(out_file, field, indent + 2); + field++; + first = false; + } + fprintf(out_file, "\n%*s]", indent, ""); + } + if (vmsd->subsections != NULL) { + const VMStateSubsection *subsection = vmsd->subsections; + bool first; + + fprintf(out_file, ",\n%*s\"Subsections\": [\n", indent, ""); + first = true; + while (subsection->vmsd != NULL) { + if (!first) { + fprintf(out_file, ",\n"); + } + dump_vmstate_vmss(out_file, subsection, indent + 2); + subsection++; + first = false; + } + fprintf(out_file, "\n%*s]", indent, ""); + } + fprintf(out_file, "\n%*s}", indent - 2, ""); +} + +static void dump_machine_type(FILE *out_file) +{ + MachineClass *mc; + + mc = MACHINE_GET_CLASS(current_machine); + + fprintf(out_file, " \"vmschkmachine\": {\n"); + fprintf(out_file, " \"Name\": \"%s\"\n", mc->name); + fprintf(out_file, " },\n"); +} + +void dump_vmstate_json_to_file(FILE *out_file) +{ + GSList *list, *elt; + bool first; + + fprintf(out_file, "{\n"); + dump_machine_type(out_file); + + first = true; + list = object_class_get_list(TYPE_DEVICE, true); + for (elt = list; elt; elt = elt->next) { + DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data, + TYPE_DEVICE); + const char *name; + int indent = 2; + + if (!dc->vmsd) { + continue; + } + + if (!first) { + fprintf(out_file, ",\n"); + } + name = object_class_get_name(OBJECT_CLASS(dc)); + fprintf(out_file, "%*s\"%s\": {\n", indent, "", name); + indent += 2; + fprintf(out_file, "%*s\"Name\": \"%s\",\n", indent, "", name); + fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "", + dc->vmsd->version_id); + fprintf(out_file, "%*s\"minimum_version_id\": %d,\n", indent, "", + dc->vmsd->minimum_version_id); + + dump_vmstate_vmsd(out_file, dc->vmsd, indent, false); + + fprintf(out_file, "\n%*s}", indent - 2, ""); + first = false; + } + fprintf(out_file, "\n}\n"); + fclose(out_file); +} + static int calculate_new_instance_id(const char *idstr) { SaveStateEntry *se; diff --git a/vl.c b/vl.c index be69c7f..860541f 100644 --- a/vl.c +++ b/vl.c @@ -2991,6 +2991,7 @@ int main(int argc, char **argv, char **envp) const char *trace_file = NULL; const ram_addr_t default_ram_size = (ram_addr_t)DEFAULT_RAM_SIZE * 1024 * 1024; + FILE *vmstate_dump_file = NULL; atexit(qemu_run_exit_notifiers); error_set_progname(argv[0]); @@ -3957,6 +3958,13 @@ int main(int argc, char **argv, char **envp) } configure_msg(opts); break; + case QEMU_OPTION_dump_vmstate: + vmstate_dump_file = fopen(optarg, "w"); + if (vmstate_dump_file == NULL) { + fprintf(stderr, "open %s: %s\n", optarg, strerror(errno)); + exit(1); + } + break; default: os_parse_cmd_args(popt->index, optarg); } @@ -4542,6 +4550,11 @@ int main(int argc, char **argv, char **envp) } qdev_prop_check_global(); + if (vmstate_dump_file) { + /* dump and exit */ + dump_vmstate_json_to_file(vmstate_dump_file); + return 0; + } if (incoming) { Error *local_err = NULL;
This commit adds a new command, '-dump-vmstate', that takes a filename as a parameter. When executed, QEMU will dump the vmstate information for the machine type it's invoked with to the file, and quit. The JSON-format output can then be used to compare the vmstate info for different QEMU versions, specifically to test whether live migration would break due to changes in the vmstate data. A Python script that compares the output of such JSON dumps is included in the following commit. Signed-off-by: Amit Shah <amit.shah@redhat.com> --- include/migration/vmstate.h | 2 + qemu-options.hx | 9 +++ savevm.c | 139 ++++++++++++++++++++++++++++++++++++++++++++ vl.c | 13 +++++ 4 files changed, 163 insertions(+)