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.mando...@gmail.com> --- tests/plugin/syscall.c | 94 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 6 deletions(-) diff --git a/tests/plugin/syscall.c b/tests/plugin/syscall.c index 53ee2ab6c4..b92340c636 100644 --- a/tests/plugin/syscall.c +++ b/tests/plugin/syscall.c @@ -16,32 +16,114 @@ 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 (!syscall_entry) { + qemu_plugin_outs(g_strdup_printf("%" PRIi64 "\n", 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); -- 2.25.1