1*1b4c136bSAlex Bennée /* 2*1b4c136bSAlex Bennée * Copyright (C) 2018, Emilio G. Cota <cota@braap.org> 3*1b4c136bSAlex Bennée * 4*1b4c136bSAlex Bennée * License: GNU GPL, version 2 or later. 5*1b4c136bSAlex Bennée * See the COPYING file in the top-level directory. 6*1b4c136bSAlex Bennée */ 7*1b4c136bSAlex Bennée #include <inttypes.h> 8*1b4c136bSAlex Bennée #include <assert.h> 9*1b4c136bSAlex Bennée #include <stdlib.h> 10*1b4c136bSAlex Bennée #include <string.h> 11*1b4c136bSAlex Bennée #include <unistd.h> 12*1b4c136bSAlex Bennée #include <stdio.h> 13*1b4c136bSAlex Bennée #include <glib.h> 14*1b4c136bSAlex Bennée 15*1b4c136bSAlex Bennée #include <qemu-plugin.h> 16*1b4c136bSAlex Bennée 17*1b4c136bSAlex Bennée QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; 18*1b4c136bSAlex Bennée 19*1b4c136bSAlex Bennée typedef struct { 20*1b4c136bSAlex Bennée uint64_t bb_count; 21*1b4c136bSAlex Bennée uint64_t insn_count; 22*1b4c136bSAlex Bennée } CPUCount; 23*1b4c136bSAlex Bennée 24*1b4c136bSAlex Bennée static struct qemu_plugin_scoreboard *counts; 25*1b4c136bSAlex Bennée static qemu_plugin_u64 bb_count; 26*1b4c136bSAlex Bennée static qemu_plugin_u64 insn_count; 27*1b4c136bSAlex Bennée 28*1b4c136bSAlex Bennée static bool do_inline; 29*1b4c136bSAlex Bennée /* Dump running CPU total on idle? */ 30*1b4c136bSAlex Bennée static bool idle_report; 31*1b4c136bSAlex Bennée 32*1b4c136bSAlex Bennée static void gen_one_cpu_report(CPUCount *count, GString *report, 33*1b4c136bSAlex Bennée unsigned int cpu_index) 34*1b4c136bSAlex Bennée { 35*1b4c136bSAlex Bennée if (count->bb_count) { 36*1b4c136bSAlex Bennée g_string_append_printf(report, "CPU%d: " 37*1b4c136bSAlex Bennée "bb's: %" PRIu64", insns: %" PRIu64 "\n", 38*1b4c136bSAlex Bennée cpu_index, 39*1b4c136bSAlex Bennée count->bb_count, count->insn_count); 40*1b4c136bSAlex Bennée } 41*1b4c136bSAlex Bennée } 42*1b4c136bSAlex Bennée 43*1b4c136bSAlex Bennée static void plugin_exit(qemu_plugin_id_t id, void *p) 44*1b4c136bSAlex Bennée { 45*1b4c136bSAlex Bennée g_autoptr(GString) report = g_string_new(""); 46*1b4c136bSAlex Bennée 47*1b4c136bSAlex Bennée for (int i = 0; i < qemu_plugin_num_vcpus(); ++i) { 48*1b4c136bSAlex Bennée CPUCount *count = qemu_plugin_scoreboard_find(counts, i); 49*1b4c136bSAlex Bennée gen_one_cpu_report(count, report, i); 50*1b4c136bSAlex Bennée } 51*1b4c136bSAlex Bennée g_string_append_printf(report, "Total: " 52*1b4c136bSAlex Bennée "bb's: %" PRIu64", insns: %" PRIu64 "\n", 53*1b4c136bSAlex Bennée qemu_plugin_u64_sum(bb_count), 54*1b4c136bSAlex Bennée qemu_plugin_u64_sum(insn_count)); 55*1b4c136bSAlex Bennée qemu_plugin_outs(report->str); 56*1b4c136bSAlex Bennée qemu_plugin_scoreboard_free(counts); 57*1b4c136bSAlex Bennée } 58*1b4c136bSAlex Bennée 59*1b4c136bSAlex Bennée static void vcpu_idle(qemu_plugin_id_t id, unsigned int cpu_index) 60*1b4c136bSAlex Bennée { 61*1b4c136bSAlex Bennée CPUCount *count = qemu_plugin_scoreboard_find(counts, cpu_index); 62*1b4c136bSAlex Bennée g_autoptr(GString) report = g_string_new(""); 63*1b4c136bSAlex Bennée gen_one_cpu_report(count, report, cpu_index); 64*1b4c136bSAlex Bennée 65*1b4c136bSAlex Bennée if (report->len > 0) { 66*1b4c136bSAlex Bennée g_string_prepend(report, "Idling "); 67*1b4c136bSAlex Bennée qemu_plugin_outs(report->str); 68*1b4c136bSAlex Bennée } 69*1b4c136bSAlex Bennée } 70*1b4c136bSAlex Bennée 71*1b4c136bSAlex Bennée static void vcpu_tb_exec(unsigned int cpu_index, void *udata) 72*1b4c136bSAlex Bennée { 73*1b4c136bSAlex Bennée CPUCount *count = qemu_plugin_scoreboard_find(counts, cpu_index); 74*1b4c136bSAlex Bennée 75*1b4c136bSAlex Bennée uintptr_t n_insns = (uintptr_t)udata; 76*1b4c136bSAlex Bennée count->insn_count += n_insns; 77*1b4c136bSAlex Bennée count->bb_count++; 78*1b4c136bSAlex Bennée } 79*1b4c136bSAlex Bennée 80*1b4c136bSAlex Bennée static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) 81*1b4c136bSAlex Bennée { 82*1b4c136bSAlex Bennée size_t n_insns = qemu_plugin_tb_n_insns(tb); 83*1b4c136bSAlex Bennée 84*1b4c136bSAlex Bennée if (do_inline) { 85*1b4c136bSAlex Bennée qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu( 86*1b4c136bSAlex Bennée tb, QEMU_PLUGIN_INLINE_ADD_U64, bb_count, 1); 87*1b4c136bSAlex Bennée qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu( 88*1b4c136bSAlex Bennée tb, QEMU_PLUGIN_INLINE_ADD_U64, insn_count, n_insns); 89*1b4c136bSAlex Bennée } else { 90*1b4c136bSAlex Bennée qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec, 91*1b4c136bSAlex Bennée QEMU_PLUGIN_CB_NO_REGS, 92*1b4c136bSAlex Bennée (void *)n_insns); 93*1b4c136bSAlex Bennée } 94*1b4c136bSAlex Bennée } 95*1b4c136bSAlex Bennée 96*1b4c136bSAlex Bennée QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, 97*1b4c136bSAlex Bennée const qemu_info_t *info, 98*1b4c136bSAlex Bennée int argc, char **argv) 99*1b4c136bSAlex Bennée { 100*1b4c136bSAlex Bennée int i; 101*1b4c136bSAlex Bennée 102*1b4c136bSAlex Bennée for (i = 0; i < argc; i++) { 103*1b4c136bSAlex Bennée char *opt = argv[i]; 104*1b4c136bSAlex Bennée g_auto(GStrv) tokens = g_strsplit(opt, "=", 2); 105*1b4c136bSAlex Bennée if (g_strcmp0(tokens[0], "inline") == 0) { 106*1b4c136bSAlex Bennée if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) { 107*1b4c136bSAlex Bennée fprintf(stderr, "boolean argument parsing failed: %s\n", opt); 108*1b4c136bSAlex Bennée return -1; 109*1b4c136bSAlex Bennée } 110*1b4c136bSAlex Bennée } else if (g_strcmp0(tokens[0], "idle") == 0) { 111*1b4c136bSAlex Bennée if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &idle_report)) { 112*1b4c136bSAlex Bennée fprintf(stderr, "boolean argument parsing failed: %s\n", opt); 113*1b4c136bSAlex Bennée return -1; 114*1b4c136bSAlex Bennée } 115*1b4c136bSAlex Bennée } else { 116*1b4c136bSAlex Bennée fprintf(stderr, "option parsing failed: %s\n", opt); 117*1b4c136bSAlex Bennée return -1; 118*1b4c136bSAlex Bennée } 119*1b4c136bSAlex Bennée } 120*1b4c136bSAlex Bennée 121*1b4c136bSAlex Bennée counts = qemu_plugin_scoreboard_new(sizeof(CPUCount)); 122*1b4c136bSAlex Bennée bb_count = qemu_plugin_scoreboard_u64_in_struct(counts, CPUCount, bb_count); 123*1b4c136bSAlex Bennée insn_count = qemu_plugin_scoreboard_u64_in_struct( 124*1b4c136bSAlex Bennée counts, CPUCount, insn_count); 125*1b4c136bSAlex Bennée 126*1b4c136bSAlex Bennée if (idle_report) { 127*1b4c136bSAlex Bennée qemu_plugin_register_vcpu_idle_cb(id, vcpu_idle); 128*1b4c136bSAlex Bennée } 129*1b4c136bSAlex Bennée 130*1b4c136bSAlex Bennée qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); 131*1b4c136bSAlex Bennée qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); 132*1b4c136bSAlex Bennée return 0; 133*1b4c136bSAlex Bennée } 134