1*b480f7a6SPierrick Bouvier /* 2*b480f7a6SPierrick Bouvier * Copyright (C) 2023, Pierrick Bouvier <pierrick.bouvier@linaro.org> 3*b480f7a6SPierrick Bouvier * 4*b480f7a6SPierrick Bouvier * Demonstrates and tests usage of inline ops. 5*b480f7a6SPierrick Bouvier * 6*b480f7a6SPierrick Bouvier * License: GNU GPL, version 2 or later. 7*b480f7a6SPierrick Bouvier * See the COPYING file in the top-level directory. 8*b480f7a6SPierrick Bouvier */ 9*b480f7a6SPierrick Bouvier 10*b480f7a6SPierrick Bouvier #include <glib.h> 11*b480f7a6SPierrick Bouvier #include <stdint.h> 12*b480f7a6SPierrick Bouvier #include <stdio.h> 13*b480f7a6SPierrick Bouvier 14*b480f7a6SPierrick Bouvier #include <qemu-plugin.h> 15*b480f7a6SPierrick Bouvier 16*b480f7a6SPierrick Bouvier typedef struct { 17*b480f7a6SPierrick Bouvier uint64_t count_tb; 18*b480f7a6SPierrick Bouvier uint64_t count_tb_inline; 19*b480f7a6SPierrick Bouvier uint64_t count_insn; 20*b480f7a6SPierrick Bouvier uint64_t count_insn_inline; 21*b480f7a6SPierrick Bouvier uint64_t count_mem; 22*b480f7a6SPierrick Bouvier uint64_t count_mem_inline; 23*b480f7a6SPierrick Bouvier } CPUCount; 24*b480f7a6SPierrick Bouvier 25*b480f7a6SPierrick Bouvier static struct qemu_plugin_scoreboard *counts; 26*b480f7a6SPierrick Bouvier static qemu_plugin_u64 count_tb; 27*b480f7a6SPierrick Bouvier static qemu_plugin_u64 count_tb_inline; 28*b480f7a6SPierrick Bouvier static qemu_plugin_u64 count_insn; 29*b480f7a6SPierrick Bouvier static qemu_plugin_u64 count_insn_inline; 30*b480f7a6SPierrick Bouvier static qemu_plugin_u64 count_mem; 31*b480f7a6SPierrick Bouvier static qemu_plugin_u64 count_mem_inline; 32*b480f7a6SPierrick Bouvier 33*b480f7a6SPierrick Bouvier static uint64_t global_count_tb; 34*b480f7a6SPierrick Bouvier static uint64_t global_count_insn; 35*b480f7a6SPierrick Bouvier static uint64_t global_count_mem; 36*b480f7a6SPierrick Bouvier static unsigned int max_cpu_index; 37*b480f7a6SPierrick Bouvier static GMutex tb_lock; 38*b480f7a6SPierrick Bouvier static GMutex insn_lock; 39*b480f7a6SPierrick Bouvier static GMutex mem_lock; 40*b480f7a6SPierrick Bouvier 41*b480f7a6SPierrick Bouvier QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; 42*b480f7a6SPierrick Bouvier 43*b480f7a6SPierrick Bouvier static void stats_insn(void) 44*b480f7a6SPierrick Bouvier { 45*b480f7a6SPierrick Bouvier const uint64_t expected = global_count_insn; 46*b480f7a6SPierrick Bouvier const uint64_t per_vcpu = qemu_plugin_u64_sum(count_insn); 47*b480f7a6SPierrick Bouvier const uint64_t inl_per_vcpu = 48*b480f7a6SPierrick Bouvier qemu_plugin_u64_sum(count_insn_inline); 49*b480f7a6SPierrick Bouvier printf("insn: %" PRIu64 "\n", expected); 50*b480f7a6SPierrick Bouvier printf("insn: %" PRIu64 " (per vcpu)\n", per_vcpu); 51*b480f7a6SPierrick Bouvier printf("insn: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu); 52*b480f7a6SPierrick Bouvier g_assert(expected > 0); 53*b480f7a6SPierrick Bouvier g_assert(per_vcpu == expected); 54*b480f7a6SPierrick Bouvier g_assert(inl_per_vcpu == expected); 55*b480f7a6SPierrick Bouvier } 56*b480f7a6SPierrick Bouvier 57*b480f7a6SPierrick Bouvier static void stats_tb(void) 58*b480f7a6SPierrick Bouvier { 59*b480f7a6SPierrick Bouvier const uint64_t expected = global_count_tb; 60*b480f7a6SPierrick Bouvier const uint64_t per_vcpu = qemu_plugin_u64_sum(count_tb); 61*b480f7a6SPierrick Bouvier const uint64_t inl_per_vcpu = 62*b480f7a6SPierrick Bouvier qemu_plugin_u64_sum(count_tb_inline); 63*b480f7a6SPierrick Bouvier printf("tb: %" PRIu64 "\n", expected); 64*b480f7a6SPierrick Bouvier printf("tb: %" PRIu64 " (per vcpu)\n", per_vcpu); 65*b480f7a6SPierrick Bouvier printf("tb: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu); 66*b480f7a6SPierrick Bouvier g_assert(expected > 0); 67*b480f7a6SPierrick Bouvier g_assert(per_vcpu == expected); 68*b480f7a6SPierrick Bouvier g_assert(inl_per_vcpu == expected); 69*b480f7a6SPierrick Bouvier } 70*b480f7a6SPierrick Bouvier 71*b480f7a6SPierrick Bouvier static void stats_mem(void) 72*b480f7a6SPierrick Bouvier { 73*b480f7a6SPierrick Bouvier const uint64_t expected = global_count_mem; 74*b480f7a6SPierrick Bouvier const uint64_t per_vcpu = qemu_plugin_u64_sum(count_mem); 75*b480f7a6SPierrick Bouvier const uint64_t inl_per_vcpu = 76*b480f7a6SPierrick Bouvier qemu_plugin_u64_sum(count_mem_inline); 77*b480f7a6SPierrick Bouvier printf("mem: %" PRIu64 "\n", expected); 78*b480f7a6SPierrick Bouvier printf("mem: %" PRIu64 " (per vcpu)\n", per_vcpu); 79*b480f7a6SPierrick Bouvier printf("mem: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu); 80*b480f7a6SPierrick Bouvier g_assert(expected > 0); 81*b480f7a6SPierrick Bouvier g_assert(per_vcpu == expected); 82*b480f7a6SPierrick Bouvier g_assert(inl_per_vcpu == expected); 83*b480f7a6SPierrick Bouvier } 84*b480f7a6SPierrick Bouvier 85*b480f7a6SPierrick Bouvier static void plugin_exit(qemu_plugin_id_t id, void *udata) 86*b480f7a6SPierrick Bouvier { 87*b480f7a6SPierrick Bouvier const unsigned int num_cpus = qemu_plugin_num_vcpus(); 88*b480f7a6SPierrick Bouvier g_assert(num_cpus == max_cpu_index + 1); 89*b480f7a6SPierrick Bouvier 90*b480f7a6SPierrick Bouvier for (int i = 0; i < num_cpus ; ++i) { 91*b480f7a6SPierrick Bouvier const uint64_t tb = qemu_plugin_u64_get(count_tb, i); 92*b480f7a6SPierrick Bouvier const uint64_t tb_inline = qemu_plugin_u64_get(count_tb_inline, i); 93*b480f7a6SPierrick Bouvier const uint64_t insn = qemu_plugin_u64_get(count_insn, i); 94*b480f7a6SPierrick Bouvier const uint64_t insn_inline = qemu_plugin_u64_get(count_insn_inline, i); 95*b480f7a6SPierrick Bouvier const uint64_t mem = qemu_plugin_u64_get(count_mem, i); 96*b480f7a6SPierrick Bouvier const uint64_t mem_inline = qemu_plugin_u64_get(count_mem_inline, i); 97*b480f7a6SPierrick Bouvier printf("cpu %d: tb (%" PRIu64 ", %" PRIu64 ") | " 98*b480f7a6SPierrick Bouvier "insn (%" PRIu64 ", %" PRIu64 ") | " 99*b480f7a6SPierrick Bouvier "mem (%" PRIu64 ", %" PRIu64 ")" 100*b480f7a6SPierrick Bouvier "\n", 101*b480f7a6SPierrick Bouvier i, tb, tb_inline, insn, insn_inline, mem, mem_inline); 102*b480f7a6SPierrick Bouvier g_assert(tb == tb_inline); 103*b480f7a6SPierrick Bouvier g_assert(insn == insn_inline); 104*b480f7a6SPierrick Bouvier g_assert(mem == mem_inline); 105*b480f7a6SPierrick Bouvier } 106*b480f7a6SPierrick Bouvier 107*b480f7a6SPierrick Bouvier stats_tb(); 108*b480f7a6SPierrick Bouvier stats_insn(); 109*b480f7a6SPierrick Bouvier stats_mem(); 110*b480f7a6SPierrick Bouvier 111*b480f7a6SPierrick Bouvier qemu_plugin_scoreboard_free(counts); 112*b480f7a6SPierrick Bouvier } 113*b480f7a6SPierrick Bouvier 114*b480f7a6SPierrick Bouvier static void vcpu_tb_exec(unsigned int cpu_index, void *udata) 115*b480f7a6SPierrick Bouvier { 116*b480f7a6SPierrick Bouvier qemu_plugin_u64_add(count_tb, cpu_index, 1); 117*b480f7a6SPierrick Bouvier g_mutex_lock(&tb_lock); 118*b480f7a6SPierrick Bouvier max_cpu_index = MAX(max_cpu_index, cpu_index); 119*b480f7a6SPierrick Bouvier global_count_tb++; 120*b480f7a6SPierrick Bouvier g_mutex_unlock(&tb_lock); 121*b480f7a6SPierrick Bouvier } 122*b480f7a6SPierrick Bouvier 123*b480f7a6SPierrick Bouvier static void vcpu_insn_exec(unsigned int cpu_index, void *udata) 124*b480f7a6SPierrick Bouvier { 125*b480f7a6SPierrick Bouvier qemu_plugin_u64_add(count_insn, cpu_index, 1); 126*b480f7a6SPierrick Bouvier g_mutex_lock(&insn_lock); 127*b480f7a6SPierrick Bouvier global_count_insn++; 128*b480f7a6SPierrick Bouvier g_mutex_unlock(&insn_lock); 129*b480f7a6SPierrick Bouvier } 130*b480f7a6SPierrick Bouvier 131*b480f7a6SPierrick Bouvier static void vcpu_mem_access(unsigned int cpu_index, 132*b480f7a6SPierrick Bouvier qemu_plugin_meminfo_t info, 133*b480f7a6SPierrick Bouvier uint64_t vaddr, 134*b480f7a6SPierrick Bouvier void *userdata) 135*b480f7a6SPierrick Bouvier { 136*b480f7a6SPierrick Bouvier qemu_plugin_u64_add(count_mem, cpu_index, 1); 137*b480f7a6SPierrick Bouvier g_mutex_lock(&mem_lock); 138*b480f7a6SPierrick Bouvier global_count_mem++; 139*b480f7a6SPierrick Bouvier g_mutex_unlock(&mem_lock); 140*b480f7a6SPierrick Bouvier } 141*b480f7a6SPierrick Bouvier 142*b480f7a6SPierrick Bouvier static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) 143*b480f7a6SPierrick Bouvier { 144*b480f7a6SPierrick Bouvier qemu_plugin_register_vcpu_tb_exec_cb( 145*b480f7a6SPierrick Bouvier tb, vcpu_tb_exec, QEMU_PLUGIN_CB_NO_REGS, 0); 146*b480f7a6SPierrick Bouvier qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu( 147*b480f7a6SPierrick Bouvier tb, QEMU_PLUGIN_INLINE_ADD_U64, count_tb_inline, 1); 148*b480f7a6SPierrick Bouvier 149*b480f7a6SPierrick Bouvier for (int idx = 0; idx < qemu_plugin_tb_n_insns(tb); ++idx) { 150*b480f7a6SPierrick Bouvier struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, idx); 151*b480f7a6SPierrick Bouvier qemu_plugin_register_vcpu_insn_exec_cb( 152*b480f7a6SPierrick Bouvier insn, vcpu_insn_exec, QEMU_PLUGIN_CB_NO_REGS, 0); 153*b480f7a6SPierrick Bouvier qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu( 154*b480f7a6SPierrick Bouvier insn, QEMU_PLUGIN_INLINE_ADD_U64, count_insn_inline, 1); 155*b480f7a6SPierrick Bouvier qemu_plugin_register_vcpu_mem_cb(insn, &vcpu_mem_access, 156*b480f7a6SPierrick Bouvier QEMU_PLUGIN_CB_NO_REGS, 157*b480f7a6SPierrick Bouvier QEMU_PLUGIN_MEM_RW, 0); 158*b480f7a6SPierrick Bouvier qemu_plugin_register_vcpu_mem_inline_per_vcpu( 159*b480f7a6SPierrick Bouvier insn, QEMU_PLUGIN_MEM_RW, 160*b480f7a6SPierrick Bouvier QEMU_PLUGIN_INLINE_ADD_U64, 161*b480f7a6SPierrick Bouvier count_mem_inline, 1); 162*b480f7a6SPierrick Bouvier } 163*b480f7a6SPierrick Bouvier } 164*b480f7a6SPierrick Bouvier 165*b480f7a6SPierrick Bouvier QEMU_PLUGIN_EXPORT 166*b480f7a6SPierrick Bouvier int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, 167*b480f7a6SPierrick Bouvier int argc, char **argv) 168*b480f7a6SPierrick Bouvier { 169*b480f7a6SPierrick Bouvier counts = qemu_plugin_scoreboard_new(sizeof(CPUCount)); 170*b480f7a6SPierrick Bouvier count_tb = qemu_plugin_scoreboard_u64_in_struct( 171*b480f7a6SPierrick Bouvier counts, CPUCount, count_tb); 172*b480f7a6SPierrick Bouvier count_insn = qemu_plugin_scoreboard_u64_in_struct( 173*b480f7a6SPierrick Bouvier counts, CPUCount, count_insn); 174*b480f7a6SPierrick Bouvier count_mem = qemu_plugin_scoreboard_u64_in_struct( 175*b480f7a6SPierrick Bouvier counts, CPUCount, count_mem); 176*b480f7a6SPierrick Bouvier count_tb_inline = qemu_plugin_scoreboard_u64_in_struct( 177*b480f7a6SPierrick Bouvier counts, CPUCount, count_tb_inline); 178*b480f7a6SPierrick Bouvier count_insn_inline = qemu_plugin_scoreboard_u64_in_struct( 179*b480f7a6SPierrick Bouvier counts, CPUCount, count_insn_inline); 180*b480f7a6SPierrick Bouvier count_mem_inline = qemu_plugin_scoreboard_u64_in_struct( 181*b480f7a6SPierrick Bouvier counts, CPUCount, count_mem_inline); 182*b480f7a6SPierrick Bouvier qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); 183*b480f7a6SPierrick Bouvier qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); 184*b480f7a6SPierrick Bouvier 185*b480f7a6SPierrick Bouvier return 0; 186*b480f7a6SPierrick Bouvier } 187