--- counter.c #include <assert.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>
#include <glib.h> #include <qemu-plugin.h> QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; // Files with descriptors after this one are intercepted for instruction counting marks. #define CATCH_BASE 0xcafebabe static uint64_t insn_count = 0; static pthread_t counting = false; static pthread_t counting_for = 0; static bool on_every_close = false; static void vcpu_insn_exec_before(unsigned int cpu_index, void *udata) { if (counting && pthread_self() == counting_for) insn_count++; } static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) { size_t n = qemu_plugin_tb_n_insns(tb); size_t i; for (i = 0; i < n; i++) { struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i); // TODO: do this call only on first insn in bb. qemu_plugin_register_vcpu_insn_exec_cb( insn, vcpu_insn_exec_before, QEMU_PLUGIN_CB_NO_REGS, NULL); } } static void print_insn_count(void) { g_autofree gchar *out = g_strdup_printf("executed %" PRIu64 " instructions\n", insn_count); qemu_plugin_outs(out); } 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) { // We put our listener on fd reads in range [CATCH_BASE, CATCH_BASE + 1] if (num == 0) { // sys_read switch (a1) { case CATCH_BASE + 0: counting = true; counting_for = pthread_self(); insn_count = 0; break; case CATCH_BASE + 1: { counting = false; counting_for = 0; if (a3 == 8) { // In case of user emulation in QEMU, addresses are 1:1 translated, so we can tell the caller // number of executed instructions by just writing into the buffer argument of read. *(uint64_t*)a2 = insn_count; } print_insn_count(); break; } default: break; } } if (num == 3 && on_every_close) { // sys_close print_insn_count(); } } 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++) { if (!strcmp(argv[i], "on_every_close")) { on_every_close = true; counting = true; counting_for = pthread_self(); } } qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); qemu_plugin_register_vcpu_syscall_cb(id, vcpu_syscall); return 0; } --- test.c #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #define CATCH_BASE 0xcafebabe static void start_counting() { char buf; int rv = read(CATCH_BASE, &buf, 1); (void)rv; } static void end_counting() { uint64_t counter = 0; int rv = read(CATCH_BASE + 1, &counter, sizeof(counter)); (void)rv; printf("We got %lld from TCG\n", counter); } int global = 0; typedef struct { int delay; } ThreadArg; static void* thread_fn(void* varg) { ThreadArg* arg = varg; usleep(arg->delay); free(arg); return NULL; } int main(int argc, char** argv) { int i; int repeat = 100; #define THREAD_NUM 10 pthread_t threads[THREAD_NUM]; if (argc > 1) { repeat = atoi(argv[1]); } for (i = 0; i < THREAD_NUM; i++) { ThreadArg* arg = calloc(sizeof(ThreadArg), 1); arg->delay = i * 100; pthread_create(threads + i, NULL, thread_fn, arg); } start_counting(); for (i = 0; i < repeat; i++) { global += i; } end_counting(); for (i = 0; i < THREAD_NUM; i++) { pthread_join(threads[i], NULL); } return 0; } On Tue, May 12, 2020 at 3:55 AM Emilio G. Cota <c...@braap.org> wrote: > On Mon, May 11, 2020 at 18:53:19 +0300, Nikolay Igotti wrote: > > Attached to the mail counter.c when running with attached test.c compiled > > to Linux standalone binary shows failing assert, unless the patch is > > applied. > > I didn't get the attachment. Can you paste the code at the end of your > reply? > > Thanks, > Emilio >