Message ID | 20210416071740.3393-1-ma.mandourr@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v2] plugins/syscall: Added a table-like summary output | expand |
Mahmoud Mandour <ma.mandourr@gmail.com> writes: > Added a table-like output which contains the total number of calls > for each used syscall along with the number of errors that occurred. > > Per-call tracing is still available through supplying the argument > ``print`` to the plugin. > > Signed-off-by: Mahmoud Mandour <ma.mandourr@gmail.com> > --- > v1: https://lists.gnu.org/archive/html/qemu-devel/2021-04/msg02623.html > v1 -> v2: Removed debugging code in the on-return from syscall callback > that was silently existent. > > tests/plugin/syscall.c | 91 +++++++++++++++++++++++++++++++++++++++--- > 1 file changed, 85 insertions(+), 6 deletions(-) > > diff --git a/tests/plugin/syscall.c b/tests/plugin/syscall.c > index 53ee2ab6c4..b66a930635 100644 > --- a/tests/plugin/syscall.c > +++ b/tests/plugin/syscall.c > @@ -16,32 +16,111 @@ > > QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; > > +typedef struct { > + int64_t calls; > + int64_t errors; > +} SyscallStats; > + > +static GHashTable *syscalls_statistics; > + > +static bool percall_print; > + > static void vcpu_syscall(qemu_plugin_id_t id, unsigned int vcpu_index, > int64_t num, uint64_t a1, uint64_t a2, > uint64_t a3, uint64_t a4, uint64_t a5, > uint64_t a6, uint64_t a7, uint64_t a8) > { > - g_autofree gchar *out = g_strdup_printf("syscall #%" PRIi64 "\n", num); > - qemu_plugin_outs(out); > + if (!percall_print) { I think you could eliminate the percall_print global and just invert the test and have if (syscall_statisitics) > + SyscallStats *syscall_entry; > + > + syscall_entry = > + (SyscallStats *) g_hash_table_lookup(syscalls_statistics, > + GINT_TO_POINTER(num)); > + > + if (!syscall_entry) { > + syscall_entry = g_new(SyscallStats, 1); > + syscall_entry->calls = 1; > + syscall_entry->errors = 0; > + > + g_hash_table_insert(syscalls_statistics, GINT_TO_POINTER(num), > + (gpointer) syscall_entry); You you wrap up the entry creation into a helper it would make the code less cluttered here, e.g.: syscall_entry = get_or_create_entry(); syscall_entry->calls++; > + } else { > + syscall_entry->calls++; > + } > + } else { > + g_autofree gchar *out = g_strdup_printf("syscall #%" PRIi64 "\n", num); > + qemu_plugin_outs(out); > + } > } > > static void vcpu_syscall_ret(qemu_plugin_id_t id, unsigned int vcpu_idx, > int64_t num, int64_t ret) > +{ > + if (!percall_print) { > + SyscallStats *syscall_entry; > + > + syscall_entry = > + (SyscallStats *) g_hash_table_lookup(syscalls_statistics, > + GINT_TO_POINTER(num)); > + if (ret < 0) { > + syscall_entry->errors++; > + } > + } else { > + g_autofree gchar *out; > + out = g_strdup_printf("syscall #%" PRIi64 " returned -> %" PRIi64 "\n", > + num, ret); > + qemu_plugin_outs(out); > + } ditto. > +} > + > +/* ************************************************************************* */ > + > +void print_entry(gpointer key, gpointer val, gpointer user_data) > { > g_autofree gchar *out; > - out = g_strdup_printf("syscall #%" PRIi64 " returned -> %" PRIi64 "\n", > - num, ret); > + int64_t syscall_num = (int64_t) key; > + SyscallStats *syscall_entry = (SyscallStats *) val; > + out = g_strdup_printf( > + "%-13" PRIi64 "%-6" PRIi64 " %" PRIi64 "\n", > + syscall_num, syscall_entry->calls, syscall_entry->errors); > qemu_plugin_outs(out); > } > > -/* ************************************************************************* */ > +static void plugin_exit(qemu_plugin_id_t id, void *p) > +{ > + if (!percall_print) { > + qemu_plugin_outs("syscall no. calls errors\n"); > + g_hash_table_foreach(syscalls_statistics, &print_entry, > NULL); Sorting the hash list by calls would be a nice improvement - see howvec for an example of how to use g_hash_table_get_values/g_list_sort. For cleanliness you should also clean-up the syscall_statisitics hash table and deallocation although in practice it doesn't really matter as use space is about to exit anyway. > + } > +} > > -static void plugin_exit(qemu_plugin_id_t id, void *p) {} > +void free_entry(gpointer entry) > +{ > + g_free(entry); > +} > > QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, > const qemu_info_t *info, > int argc, char **argv) > { > + int i; > + > + for (i = 0; i < argc; i++) { > + char *opt = argv[i]; > + if (g_strcmp0(opt, "print") == 0) { > + percall_print = true; So this would be a local now and or even: if (argc == 0) { syscalls_statistics = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, &free_entry); } else { for (i = 0; i < argc; i++) { ... > + } else { > + fprintf(stderr, "unsupported argument: %s\n", opt); > + return -1; > + } > + } > + > + if (!percall_print) { > + syscalls_statistics = > + g_hash_table_new_full(g_direct_hash, g_direct_equal, > + NULL, &free_entry); For a simple non-nested structure you might even get away with a plain g_hash_table_new() > + } > + > qemu_plugin_register_vcpu_syscall_cb(id, vcpu_syscall); > qemu_plugin_register_vcpu_syscall_ret_cb(id, vcpu_syscall_ret); > qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
diff --git a/tests/plugin/syscall.c b/tests/plugin/syscall.c index 53ee2ab6c4..b66a930635 100644 --- a/tests/plugin/syscall.c +++ b/tests/plugin/syscall.c @@ -16,32 +16,111 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; +typedef struct { + int64_t calls; + int64_t errors; +} SyscallStats; + +static GHashTable *syscalls_statistics; + +static bool percall_print; + static void vcpu_syscall(qemu_plugin_id_t id, unsigned int vcpu_index, int64_t num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6, uint64_t a7, uint64_t a8) { - g_autofree gchar *out = g_strdup_printf("syscall #%" PRIi64 "\n", num); - qemu_plugin_outs(out); + if (!percall_print) { + SyscallStats *syscall_entry; + + syscall_entry = + (SyscallStats *) g_hash_table_lookup(syscalls_statistics, + GINT_TO_POINTER(num)); + + if (!syscall_entry) { + syscall_entry = g_new(SyscallStats, 1); + syscall_entry->calls = 1; + syscall_entry->errors = 0; + + g_hash_table_insert(syscalls_statistics, GINT_TO_POINTER(num), + (gpointer) syscall_entry); + } else { + syscall_entry->calls++; + } + } else { + g_autofree gchar *out = g_strdup_printf("syscall #%" PRIi64 "\n", num); + qemu_plugin_outs(out); + } } static void vcpu_syscall_ret(qemu_plugin_id_t id, unsigned int vcpu_idx, int64_t num, int64_t ret) +{ + if (!percall_print) { + SyscallStats *syscall_entry; + + syscall_entry = + (SyscallStats *) g_hash_table_lookup(syscalls_statistics, + GINT_TO_POINTER(num)); + if (ret < 0) { + syscall_entry->errors++; + } + } else { + g_autofree gchar *out; + out = g_strdup_printf("syscall #%" PRIi64 " returned -> %" PRIi64 "\n", + num, ret); + qemu_plugin_outs(out); + } +} + +/* ************************************************************************* */ + +void print_entry(gpointer key, gpointer val, gpointer user_data) { g_autofree gchar *out; - out = g_strdup_printf("syscall #%" PRIi64 " returned -> %" PRIi64 "\n", - num, ret); + int64_t syscall_num = (int64_t) key; + SyscallStats *syscall_entry = (SyscallStats *) val; + out = g_strdup_printf( + "%-13" PRIi64 "%-6" PRIi64 " %" PRIi64 "\n", + syscall_num, syscall_entry->calls, syscall_entry->errors); qemu_plugin_outs(out); } -/* ************************************************************************* */ +static void plugin_exit(qemu_plugin_id_t id, void *p) +{ + if (!percall_print) { + qemu_plugin_outs("syscall no. calls errors\n"); + g_hash_table_foreach(syscalls_statistics, &print_entry, NULL); + } +} -static void plugin_exit(qemu_plugin_id_t id, void *p) {} +void free_entry(gpointer entry) +{ + g_free(entry); +} QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, int argc, char **argv) { + int i; + + for (i = 0; i < argc; i++) { + char *opt = argv[i]; + if (g_strcmp0(opt, "print") == 0) { + percall_print = true; + } else { + fprintf(stderr, "unsupported argument: %s\n", opt); + return -1; + } + } + + if (!percall_print) { + syscalls_statistics = + g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, &free_entry); + } + qemu_plugin_register_vcpu_syscall_cb(id, vcpu_syscall); qemu_plugin_register_vcpu_syscall_ret_cb(id, vcpu_syscall_ret); qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
Added a table-like output which contains the total number of calls for each used syscall along with the number of errors that occurred. Per-call tracing is still available through supplying the argument ``print`` to the plugin. Signed-off-by: Mahmoud Mandour <ma.mandourr@gmail.com> --- v1: https://lists.gnu.org/archive/html/qemu-devel/2021-04/msg02623.html v1 -> v2: Removed debugging code in the on-return from syscall callback that was silently existent. tests/plugin/syscall.c | 91 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 6 deletions(-)