From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57831) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WjoDy-0002WP-VV for qemu-devel@nongnu.org; Mon, 12 May 2014 07:16:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WjoDu-0001Wl-07 for qemu-devel@nongnu.org; Mon, 12 May 2014 07:16:50 -0400 Received: from mx1.redhat.com ([209.132.183.28]:17716) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WjoDt-0001Wh-OG for qemu-devel@nongnu.org; Mon, 12 May 2014 07:16:45 -0400 From: Amit Shah Date: Mon, 12 May 2014 16:46:01 +0530 Message-Id: In-Reply-To: References: In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH 01/18] migration: dump vmstate info as a json file for static analysis List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu list Cc: Juan Quintela , Markus Armbruster , Alexander Graf , "\\\"Dr. David Alan Gilbert\\\"" , Amit Shah , Paolo Bonzini , =?UTF-8?q?Andreas=20F=C3=A4rber?= 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. This is based on a version from Andreas F=C3=A4rber posted here: https://lists.gnu.org/archive/html/qemu-devel/2013-10/msg03095.html A Python script that compares the output of such JSON dumps is included in the following commit. Signed-off-by: Amit Shah --- include/migration/vmstate.h | 2 + qemu-options.hx | 9 +++ savevm.c | 134 ++++++++++++++++++++++++++++++++++++++= ++++++ vl.c | 14 +++++ 4 files changed, 159 insertions(+) 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 *de= v); void vmstate_register_ram_global(struct MemoryRegion *memory); =20 +void dump_vmstate_json_to_file(FILE *out_fp); + #endif diff --git a/qemu-options.hx b/qemu-options.hx index 781af14..d376227 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3146,6 +3146,15 @@ STEXI prepend a timestamp to each log message.(default:on) ETEXI =20 +DEF("dump-vmstate", HAS_ARG, QEMU_OPTION_dump_vmstate, + "-dump-vmstate \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..a4ce279 100644 --- a/savevm.c +++ b/savevm.c @@ -24,6 +24,7 @@ =20 #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,139 @@ static QTAILQ_HEAD(savevm_handlers, SaveStateEntry)= savevm_handlers =3D QTAILQ_HEAD_INITIALIZER(savevm_handlers); static int global_section_id; =20 +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 +=3D 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 !=3D 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 !=3D 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 +=3D 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 !=3D NULL) { + const VMStateField *field =3D vmsd->fields; + bool first; + + fprintf(out_file, ",\n%*s\"Fields\": [\n", indent, ""); + first =3D true; + while (field->name !=3D NULL) { + if (!first) { + fprintf(out_file, ",\n"); + } + dump_vmstate_vmsf(out_file, field, indent + 2); + field++; + first =3D false; + } + fprintf(out_file, "\n%*s]", indent, ""); + } + if (vmsd->subsections !=3D NULL) { + const VMStateSubsection *subsection =3D vmsd->subsections; + bool first; + + fprintf(out_file, ",\n%*s\"Subsections\": [\n", indent, ""); + first =3D true; + while (subsection->vmsd !=3D NULL) { + if (!first) { + fprintf(out_file, ",\n"); + } + dump_vmstate_vmss(out_file, subsection, indent + 2); + subsection++; + first =3D 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 =3D 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 =3D true; + list =3D object_class_get_list(TYPE_DEVICE, true); + for (elt =3D list; elt; elt =3D elt->next) { + DeviceClass *dc =3D OBJECT_CLASS_CHECK(DeviceClass, elt->data, + TYPE_DEVICE); + const char *name; + int indent =3D 2; + + if (!dc->vmsd) { + continue; + } + + if (!first) { + fprintf(out_file, ",\n"); + } + name =3D object_class_get_name(OBJECT_CLASS(dc)); + fprintf(out_file, "%*s\"%s\": {\n", indent, "", name); + indent +=3D 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 =3D 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 73e0661..165ec3e 100644 --- a/vl.c +++ b/vl.c @@ -2988,6 +2988,7 @@ int main(int argc, char **argv, char **envp) const char *trace_file =3D NULL; const ram_addr_t default_ram_size =3D (ram_addr_t)DEFAULT_RAM_SIZE * 1024 * 1024; + FILE *vmstate_dump_file =3D NULL; =20 atexit(qemu_run_exit_notifiers); error_set_progname(argv[0]); @@ -3956,6 +3957,13 @@ int main(int argc, char **argv, char **envp) } configure_msg(opts); break; + case QEMU_OPTION_dump_vmstate: + vmstate_dump_file =3D fopen(optarg, "w"); + if (vmstate_dump_file =3D=3D NULL) { + fprintf(stderr, "open %s: %s\n", optarg, strerror(er= rno)); + exit(1); + } + break; default: os_parse_cmd_args(popt->index, optarg); } @@ -4533,6 +4541,12 @@ int main(int argc, char **argv, char **envp) } } =20 + if (vmstate_dump_file) { + /* dump and exit */ + dump_vmstate_json_to_file(vmstate_dump_file); + return 0; + } + if (incoming) { Error *local_err =3D NULL; qemu_start_incoming_migration(incoming, &local_err); --=20 1.9.0