1c17a386bSAlex Bennée /* 2c17a386bSAlex Bennée * Copyright (C) 2019, Alex Bennée <alex.bennee@linaro.org> 3c17a386bSAlex Bennée * 4c17a386bSAlex Bennée * How vectorised is this code? 5c17a386bSAlex Bennée * 6c17a386bSAlex Bennée * Attempt to measure the amount of vectorisation that has been done 7c17a386bSAlex Bennée * on some code by counting classes of instruction. 8c17a386bSAlex Bennée * 9c17a386bSAlex Bennée * License: GNU GPL, version 2 or later. 10c17a386bSAlex Bennée * See the COPYING file in the top-level directory. 11c17a386bSAlex Bennée */ 12c17a386bSAlex Bennée #include <inttypes.h> 13c17a386bSAlex Bennée #include <assert.h> 14c17a386bSAlex Bennée #include <stdlib.h> 15c17a386bSAlex Bennée #include <inttypes.h> 16c17a386bSAlex Bennée #include <string.h> 17c17a386bSAlex Bennée #include <unistd.h> 18c17a386bSAlex Bennée #include <stdio.h> 19c17a386bSAlex Bennée #include <glib.h> 20c17a386bSAlex Bennée 21c17a386bSAlex Bennée #include <qemu-plugin.h> 22c17a386bSAlex Bennée 23c17a386bSAlex Bennée QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; 24c17a386bSAlex Bennée 25c17a386bSAlex Bennée #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 26c17a386bSAlex Bennée 27c17a386bSAlex Bennée typedef enum { 28c17a386bSAlex Bennée COUNT_CLASS, 29c17a386bSAlex Bennée COUNT_INDIVIDUAL, 30c17a386bSAlex Bennée COUNT_NONE 31c17a386bSAlex Bennée } CountType; 32c17a386bSAlex Bennée 33c17a386bSAlex Bennée static int limit = 50; 34c17a386bSAlex Bennée static bool do_inline; 35c17a386bSAlex Bennée static bool verbose; 36c17a386bSAlex Bennée 37c17a386bSAlex Bennée static GMutex lock; 38c17a386bSAlex Bennée static GHashTable *insns; 39c17a386bSAlex Bennée 40c17a386bSAlex Bennée typedef struct { 41c17a386bSAlex Bennée const char *class; 42c17a386bSAlex Bennée const char *opt; 43c17a386bSAlex Bennée uint32_t mask; 44c17a386bSAlex Bennée uint32_t pattern; 45c17a386bSAlex Bennée CountType what; 46c125a8abSPierrick Bouvier qemu_plugin_u64 count; 47c17a386bSAlex Bennée } InsnClassExecCount; 48c17a386bSAlex Bennée 49c17a386bSAlex Bennée typedef struct { 50c17a386bSAlex Bennée char *insn; 51c17a386bSAlex Bennée uint32_t opcode; 52c125a8abSPierrick Bouvier qemu_plugin_u64 count; 53c17a386bSAlex Bennée InsnClassExecCount *class; 54c17a386bSAlex Bennée } InsnExecCount; 55c17a386bSAlex Bennée 56c17a386bSAlex Bennée /* 57c17a386bSAlex Bennée * Matchers for classes of instructions, order is important. 58c17a386bSAlex Bennée * 59c17a386bSAlex Bennée * Your most precise match must be before looser matches. If no match 60c17a386bSAlex Bennée * is found in the table we can create an individual entry. 61c17a386bSAlex Bennée * 62c17a386bSAlex Bennée * 31..28 27..24 23..20 19..16 15..12 11..8 7..4 3..0 63c17a386bSAlex Bennée */ 64c17a386bSAlex Bennée static InsnClassExecCount aarch64_insn_classes[] = { 65c17a386bSAlex Bennée /* "Reserved"" */ 66c17a386bSAlex Bennée { " UDEF", "udef", 0xffff0000, 0x00000000, COUNT_NONE}, 67c17a386bSAlex Bennée { " SVE", "sve", 0x1e000000, 0x04000000, COUNT_CLASS}, 68c17a386bSAlex Bennée { "Reserved", "res", 0x1e000000, 0x00000000, COUNT_CLASS}, 69c17a386bSAlex Bennée /* Data Processing Immediate */ 70c17a386bSAlex Bennée { " PCrel addr", "pcrel", 0x1f000000, 0x10000000, COUNT_CLASS}, 71c17a386bSAlex Bennée { " Add/Sub (imm,tags)", "asit", 0x1f800000, 0x11800000, COUNT_CLASS}, 72c17a386bSAlex Bennée { " Add/Sub (imm)", "asi", 0x1f000000, 0x11000000, COUNT_CLASS}, 73c17a386bSAlex Bennée { " Logical (imm)", "logi", 0x1f800000, 0x12000000, COUNT_CLASS}, 74c17a386bSAlex Bennée { " Move Wide (imm)", "movwi", 0x1f800000, 0x12800000, COUNT_CLASS}, 75c17a386bSAlex Bennée { " Bitfield", "bitf", 0x1f800000, 0x13000000, COUNT_CLASS}, 76c17a386bSAlex Bennée { " Extract", "extr", 0x1f800000, 0x13800000, COUNT_CLASS}, 77c17a386bSAlex Bennée { "Data Proc Imm", "dpri", 0x1c000000, 0x10000000, COUNT_CLASS}, 78c17a386bSAlex Bennée /* Branches */ 79c17a386bSAlex Bennée { " Cond Branch (imm)", "cndb", 0xfe000000, 0x54000000, COUNT_CLASS}, 80c17a386bSAlex Bennée { " Exception Gen", "excp", 0xff000000, 0xd4000000, COUNT_CLASS}, 81c17a386bSAlex Bennée { " NOP", "nop", 0xffffffff, 0xd503201f, COUNT_NONE}, 82c17a386bSAlex Bennée { " Hints", "hint", 0xfffff000, 0xd5032000, COUNT_CLASS}, 83c17a386bSAlex Bennée { " Barriers", "barr", 0xfffff000, 0xd5033000, COUNT_CLASS}, 84c17a386bSAlex Bennée { " PSTATE", "psta", 0xfff8f000, 0xd5004000, COUNT_CLASS}, 85c17a386bSAlex Bennée { " System Insn", "sins", 0xffd80000, 0xd5080000, COUNT_CLASS}, 86c17a386bSAlex Bennée { " System Reg", "sreg", 0xffd00000, 0xd5100000, COUNT_CLASS}, 87c17a386bSAlex Bennée { " Branch (reg)", "breg", 0xfe000000, 0xd6000000, COUNT_CLASS}, 88c17a386bSAlex Bennée { " Branch (imm)", "bimm", 0x7c000000, 0x14000000, COUNT_CLASS}, 89c17a386bSAlex Bennée { " Cmp & Branch", "cmpb", 0x7e000000, 0x34000000, COUNT_CLASS}, 90c17a386bSAlex Bennée { " Tst & Branch", "tstb", 0x7e000000, 0x36000000, COUNT_CLASS}, 91c17a386bSAlex Bennée { "Branches", "branch", 0x1c000000, 0x14000000, COUNT_CLASS}, 92c17a386bSAlex Bennée /* Loads and Stores */ 93c17a386bSAlex Bennée { " AdvSimd ldstmult", "advlsm", 0xbfbf0000, 0x0c000000, COUNT_CLASS}, 94c17a386bSAlex Bennée { " AdvSimd ldstmult++", "advlsmp", 0xbfb00000, 0x0c800000, COUNT_CLASS}, 95c17a386bSAlex Bennée { " AdvSimd ldst", "advlss", 0xbf9f0000, 0x0d000000, COUNT_CLASS}, 96c17a386bSAlex Bennée { " AdvSimd ldst++", "advlssp", 0xbf800000, 0x0d800000, COUNT_CLASS}, 97c17a386bSAlex Bennée { " ldst excl", "ldstx", 0x3f000000, 0x08000000, COUNT_CLASS}, 98c17a386bSAlex Bennée { " Prefetch", "prfm", 0xff000000, 0xd8000000, COUNT_CLASS}, 99c17a386bSAlex Bennée { " Load Reg (lit)", "ldlit", 0x1b000000, 0x18000000, COUNT_CLASS}, 100c17a386bSAlex Bennée { " ldst noalloc pair", "ldstnap", 0x3b800000, 0x28000000, COUNT_CLASS}, 101c17a386bSAlex Bennée { " ldst pair", "ldstp", 0x38000000, 0x28000000, COUNT_CLASS}, 102c17a386bSAlex Bennée { " ldst reg", "ldstr", 0x3b200000, 0x38000000, COUNT_CLASS}, 103c17a386bSAlex Bennée { " Atomic ldst", "atomic", 0x3b200c00, 0x38200000, COUNT_CLASS}, 104c17a386bSAlex Bennée { " ldst reg (reg off)", "ldstro", 0x3b200b00, 0x38200800, COUNT_CLASS}, 105c17a386bSAlex Bennée { " ldst reg (pac)", "ldstpa", 0x3b200200, 0x38200800, COUNT_CLASS}, 106c17a386bSAlex Bennée { " ldst reg (imm)", "ldsti", 0x3b000000, 0x39000000, COUNT_CLASS}, 107c17a386bSAlex Bennée { "Loads & Stores", "ldst", 0x0a000000, 0x08000000, COUNT_CLASS}, 108c17a386bSAlex Bennée /* Data Processing Register */ 109c17a386bSAlex Bennée { "Data Proc Reg", "dprr", 0x0e000000, 0x0a000000, COUNT_CLASS}, 110c17a386bSAlex Bennée /* Scalar FP */ 111c17a386bSAlex Bennée { "Scalar FP ", "fpsimd", 0x0e000000, 0x0e000000, COUNT_CLASS}, 112c17a386bSAlex Bennée /* Unclassified */ 113c17a386bSAlex Bennée { "Unclassified", "unclas", 0x00000000, 0x00000000, COUNT_CLASS}, 114c17a386bSAlex Bennée }; 115c17a386bSAlex Bennée 116c17a386bSAlex Bennée static InsnClassExecCount sparc32_insn_classes[] = { 117c17a386bSAlex Bennée { "Call", "call", 0xc0000000, 0x40000000, COUNT_CLASS}, 118c17a386bSAlex Bennée { "Branch ICond", "bcc", 0xc1c00000, 0x00800000, COUNT_CLASS}, 119c17a386bSAlex Bennée { "Branch Fcond", "fbcc", 0xc1c00000, 0x01800000, COUNT_CLASS}, 120c17a386bSAlex Bennée { "SetHi", "sethi", 0xc1c00000, 0x01000000, COUNT_CLASS}, 121c17a386bSAlex Bennée { "FPU ALU", "fpu", 0xc1f00000, 0x81a00000, COUNT_CLASS}, 122c17a386bSAlex Bennée { "ALU", "alu", 0xc0000000, 0x80000000, COUNT_CLASS}, 123c17a386bSAlex Bennée { "Load/Store", "ldst", 0xc0000000, 0xc0000000, COUNT_CLASS}, 124c17a386bSAlex Bennée /* Unclassified */ 125c17a386bSAlex Bennée { "Unclassified", "unclas", 0x00000000, 0x00000000, COUNT_INDIVIDUAL}, 126c17a386bSAlex Bennée }; 127c17a386bSAlex Bennée 128c17a386bSAlex Bennée static InsnClassExecCount sparc64_insn_classes[] = { 129c17a386bSAlex Bennée { "SetHi & Branches", "op0", 0xc0000000, 0x00000000, COUNT_CLASS}, 130c17a386bSAlex Bennée { "Call", "op1", 0xc0000000, 0x40000000, COUNT_CLASS}, 131c17a386bSAlex Bennée { "Arith/Logical/Move", "op2", 0xc0000000, 0x80000000, COUNT_CLASS}, 132c17a386bSAlex Bennée { "Arith/Logical/Move", "op3", 0xc0000000, 0xc0000000, COUNT_CLASS}, 133c17a386bSAlex Bennée /* Unclassified */ 134c17a386bSAlex Bennée { "Unclassified", "unclas", 0x00000000, 0x00000000, COUNT_INDIVIDUAL}, 135c17a386bSAlex Bennée }; 136c17a386bSAlex Bennée 137c17a386bSAlex Bennée /* Default matcher for currently unclassified architectures */ 138c17a386bSAlex Bennée static InsnClassExecCount default_insn_classes[] = { 139c17a386bSAlex Bennée { "Unclassified", "unclas", 0x00000000, 0x00000000, COUNT_INDIVIDUAL}, 140c17a386bSAlex Bennée }; 141c17a386bSAlex Bennée 142c17a386bSAlex Bennée typedef struct { 143c17a386bSAlex Bennée const char *qemu_target; 144c17a386bSAlex Bennée InsnClassExecCount *table; 145c17a386bSAlex Bennée int table_sz; 146c17a386bSAlex Bennée } ClassSelector; 147c17a386bSAlex Bennée 14824fa5d66Szhouyang static ClassSelector class_tables[] = { 149c17a386bSAlex Bennée { "aarch64", aarch64_insn_classes, ARRAY_SIZE(aarch64_insn_classes) }, 150c17a386bSAlex Bennée { "sparc", sparc32_insn_classes, ARRAY_SIZE(sparc32_insn_classes) }, 151c17a386bSAlex Bennée { "sparc64", sparc64_insn_classes, ARRAY_SIZE(sparc64_insn_classes) }, 152c17a386bSAlex Bennée { NULL, default_insn_classes, ARRAY_SIZE(default_insn_classes) }, 153c17a386bSAlex Bennée }; 154c17a386bSAlex Bennée 155c17a386bSAlex Bennée static InsnClassExecCount *class_table; 156c17a386bSAlex Bennée static int class_table_sz; 157c17a386bSAlex Bennée 158c17a386bSAlex Bennée static gint cmp_exec_count(gconstpointer a, gconstpointer b) 159c17a386bSAlex Bennée { 160c17a386bSAlex Bennée InsnExecCount *ea = (InsnExecCount *) a; 161c17a386bSAlex Bennée InsnExecCount *eb = (InsnExecCount *) b; 162c125a8abSPierrick Bouvier uint64_t count_a = qemu_plugin_u64_sum(ea->count); 163c125a8abSPierrick Bouvier uint64_t count_b = qemu_plugin_u64_sum(eb->count); 164c125a8abSPierrick Bouvier return count_a > count_b ? -1 : 1; 165c17a386bSAlex Bennée } 166c17a386bSAlex Bennée 167c17a386bSAlex Bennée static void free_record(gpointer data) 168c17a386bSAlex Bennée { 169c17a386bSAlex Bennée InsnExecCount *rec = (InsnExecCount *) data; 170*73281023SPaolo Bonzini qemu_plugin_scoreboard_free(rec->count.score); 171c17a386bSAlex Bennée g_free(rec->insn); 172c17a386bSAlex Bennée g_free(rec); 173c17a386bSAlex Bennée } 174c17a386bSAlex Bennée 175c17a386bSAlex Bennée static void plugin_exit(qemu_plugin_id_t id, void *p) 176c17a386bSAlex Bennée { 177c17a386bSAlex Bennée g_autoptr(GString) report = g_string_new("Instruction Classes:\n"); 178c17a386bSAlex Bennée int i; 179c125a8abSPierrick Bouvier uint64_t total_count; 180c17a386bSAlex Bennée GList *counts; 181c17a386bSAlex Bennée InsnClassExecCount *class = NULL; 182c17a386bSAlex Bennée 183c17a386bSAlex Bennée for (i = 0; i < class_table_sz; i++) { 184c17a386bSAlex Bennée class = &class_table[i]; 185c17a386bSAlex Bennée switch (class->what) { 186c17a386bSAlex Bennée case COUNT_CLASS: 187c125a8abSPierrick Bouvier total_count = qemu_plugin_u64_sum(class->count); 188c125a8abSPierrick Bouvier if (total_count || verbose) { 1899b60d6a1SPhilippe Mathieu-Daudé g_string_append_printf(report, 1909b60d6a1SPhilippe Mathieu-Daudé "Class: %-24s\t(%" PRId64 " hits)\n", 191c17a386bSAlex Bennée class->class, 192c125a8abSPierrick Bouvier total_count); 193c17a386bSAlex Bennée } 194c17a386bSAlex Bennée break; 195c17a386bSAlex Bennée case COUNT_INDIVIDUAL: 196c17a386bSAlex Bennée g_string_append_printf(report, "Class: %-24s\tcounted individually\n", 197c17a386bSAlex Bennée class->class); 198c17a386bSAlex Bennée break; 199c17a386bSAlex Bennée case COUNT_NONE: 200c17a386bSAlex Bennée g_string_append_printf(report, "Class: %-24s\tnot counted\n", 201c17a386bSAlex Bennée class->class); 202c17a386bSAlex Bennée break; 203c17a386bSAlex Bennée default: 204c17a386bSAlex Bennée break; 205c17a386bSAlex Bennée } 206c17a386bSAlex Bennée } 207c17a386bSAlex Bennée 208c17a386bSAlex Bennée counts = g_hash_table_get_values(insns); 209c17a386bSAlex Bennée if (counts && g_list_next(counts)) { 210c17a386bSAlex Bennée g_string_append_printf(report, "Individual Instructions:\n"); 211c17a386bSAlex Bennée counts = g_list_sort(counts, cmp_exec_count); 212c17a386bSAlex Bennée 213c17a386bSAlex Bennée for (i = 0; i < limit && g_list_next(counts); 214c17a386bSAlex Bennée i++, counts = g_list_next(counts)) { 215c17a386bSAlex Bennée InsnExecCount *rec = (InsnExecCount *) counts->data; 216c17a386bSAlex Bennée g_string_append_printf(report, 2179b60d6a1SPhilippe Mathieu-Daudé "Instr: %-24s\t(%" PRId64 " hits)" 2189b60d6a1SPhilippe Mathieu-Daudé "\t(op=0x%08x/%s)\n", 219c17a386bSAlex Bennée rec->insn, 220c125a8abSPierrick Bouvier qemu_plugin_u64_sum(rec->count), 221c17a386bSAlex Bennée rec->opcode, 222c17a386bSAlex Bennée rec->class ? 223c17a386bSAlex Bennée rec->class->class : "un-categorised"); 224c17a386bSAlex Bennée } 225c17a386bSAlex Bennée g_list_free(counts); 226c17a386bSAlex Bennée } 227c17a386bSAlex Bennée 228c17a386bSAlex Bennée g_hash_table_destroy(insns); 229c125a8abSPierrick Bouvier for (i = 0; i < ARRAY_SIZE(class_tables); i++) { 230c125a8abSPierrick Bouvier for (int j = 0; j < class_tables[i].table_sz; ++j) { 231c125a8abSPierrick Bouvier qemu_plugin_scoreboard_free(class_tables[i].table[j].count.score); 232c125a8abSPierrick Bouvier } 233c125a8abSPierrick Bouvier } 234c125a8abSPierrick Bouvier 235c17a386bSAlex Bennée 236c17a386bSAlex Bennée qemu_plugin_outs(report->str); 237c17a386bSAlex Bennée } 238c17a386bSAlex Bennée 239c17a386bSAlex Bennée static void plugin_init(void) 240c17a386bSAlex Bennée { 241c17a386bSAlex Bennée insns = g_hash_table_new_full(NULL, g_direct_equal, NULL, &free_record); 242c17a386bSAlex Bennée } 243c17a386bSAlex Bennée 244c17a386bSAlex Bennée static void vcpu_insn_exec_before(unsigned int cpu_index, void *udata) 245c17a386bSAlex Bennée { 246c125a8abSPierrick Bouvier struct qemu_plugin_scoreboard *score = udata; 247c125a8abSPierrick Bouvier qemu_plugin_u64_add(qemu_plugin_scoreboard_u64(score), cpu_index, 1); 248c17a386bSAlex Bennée } 249c17a386bSAlex Bennée 250c125a8abSPierrick Bouvier static struct qemu_plugin_scoreboard *find_counter( 251c125a8abSPierrick Bouvier struct qemu_plugin_insn *insn) 252c17a386bSAlex Bennée { 253c17a386bSAlex Bennée int i; 254c17a386bSAlex Bennée uint64_t *cnt = NULL; 255c17a386bSAlex Bennée uint32_t opcode; 256c17a386bSAlex Bennée InsnClassExecCount *class = NULL; 257c17a386bSAlex Bennée 258c17a386bSAlex Bennée /* 259c17a386bSAlex Bennée * We only match the first 32 bits of the instruction which is 260c17a386bSAlex Bennée * fine for most RISCs but a bit limiting for CISC architectures. 261c17a386bSAlex Bennée * They would probably benefit from a more tailored plugin. 262c17a386bSAlex Bennée * However we can fall back to individual instruction counting. 263c17a386bSAlex Bennée */ 264c17a386bSAlex Bennée opcode = *((uint32_t *)qemu_plugin_insn_data(insn)); 265c17a386bSAlex Bennée 266c17a386bSAlex Bennée for (i = 0; !cnt && i < class_table_sz; i++) { 267c17a386bSAlex Bennée class = &class_table[i]; 268c17a386bSAlex Bennée uint32_t masked_bits = opcode & class->mask; 269c17a386bSAlex Bennée if (masked_bits == class->pattern) { 270c17a386bSAlex Bennée break; 271c17a386bSAlex Bennée } 272c17a386bSAlex Bennée } 273c17a386bSAlex Bennée 274c17a386bSAlex Bennée g_assert(class); 275c17a386bSAlex Bennée 276c17a386bSAlex Bennée switch (class->what) { 277c17a386bSAlex Bennée case COUNT_NONE: 278c17a386bSAlex Bennée return NULL; 279c17a386bSAlex Bennée case COUNT_CLASS: 280c125a8abSPierrick Bouvier return class->count.score; 281c17a386bSAlex Bennée case COUNT_INDIVIDUAL: 282c17a386bSAlex Bennée { 283c17a386bSAlex Bennée InsnExecCount *icount; 284c17a386bSAlex Bennée 285c17a386bSAlex Bennée g_mutex_lock(&lock); 286c17a386bSAlex Bennée icount = (InsnExecCount *) g_hash_table_lookup(insns, 287c17a386bSAlex Bennée GUINT_TO_POINTER(opcode)); 288c17a386bSAlex Bennée 289c17a386bSAlex Bennée if (!icount) { 290c17a386bSAlex Bennée icount = g_new0(InsnExecCount, 1); 291c17a386bSAlex Bennée icount->opcode = opcode; 292c17a386bSAlex Bennée icount->insn = qemu_plugin_insn_disas(insn); 293c17a386bSAlex Bennée icount->class = class; 294c125a8abSPierrick Bouvier struct qemu_plugin_scoreboard *score = 295c125a8abSPierrick Bouvier qemu_plugin_scoreboard_new(sizeof(uint64_t)); 296c125a8abSPierrick Bouvier icount->count = qemu_plugin_scoreboard_u64(score); 297c17a386bSAlex Bennée 298c17a386bSAlex Bennée g_hash_table_insert(insns, GUINT_TO_POINTER(opcode), 299c17a386bSAlex Bennée (gpointer) icount); 300c17a386bSAlex Bennée } 301c17a386bSAlex Bennée g_mutex_unlock(&lock); 302c17a386bSAlex Bennée 303c125a8abSPierrick Bouvier return icount->count.score; 304c17a386bSAlex Bennée } 305c17a386bSAlex Bennée default: 306c17a386bSAlex Bennée g_assert_not_reached(); 307c17a386bSAlex Bennée } 308c17a386bSAlex Bennée 309c17a386bSAlex Bennée return NULL; 310c17a386bSAlex Bennée } 311c17a386bSAlex Bennée 312c17a386bSAlex Bennée static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) 313c17a386bSAlex Bennée { 314c17a386bSAlex Bennée size_t n = qemu_plugin_tb_n_insns(tb); 315c17a386bSAlex Bennée size_t i; 316c17a386bSAlex Bennée 317c17a386bSAlex Bennée for (i = 0; i < n; i++) { 318c17a386bSAlex Bennée struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i); 319c125a8abSPierrick Bouvier struct qemu_plugin_scoreboard *cnt = find_counter(insn); 320c17a386bSAlex Bennée 321c17a386bSAlex Bennée if (cnt) { 322c17a386bSAlex Bennée if (do_inline) { 323c125a8abSPierrick Bouvier qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu( 324c125a8abSPierrick Bouvier insn, QEMU_PLUGIN_INLINE_ADD_U64, 325c125a8abSPierrick Bouvier qemu_plugin_scoreboard_u64(cnt), 1); 326c17a386bSAlex Bennée } else { 327c17a386bSAlex Bennée qemu_plugin_register_vcpu_insn_exec_cb( 328c17a386bSAlex Bennée insn, vcpu_insn_exec_before, QEMU_PLUGIN_CB_NO_REGS, cnt); 329c17a386bSAlex Bennée } 330c17a386bSAlex Bennée } 331c17a386bSAlex Bennée } 332c17a386bSAlex Bennée } 333c17a386bSAlex Bennée 334c17a386bSAlex Bennée QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, 335c17a386bSAlex Bennée const qemu_info_t *info, 336c17a386bSAlex Bennée int argc, char **argv) 337c17a386bSAlex Bennée { 338c17a386bSAlex Bennée int i; 339c17a386bSAlex Bennée 340c125a8abSPierrick Bouvier for (i = 0; i < ARRAY_SIZE(class_tables); i++) { 341c125a8abSPierrick Bouvier for (int j = 0; j < class_tables[i].table_sz; ++j) { 342c125a8abSPierrick Bouvier struct qemu_plugin_scoreboard *score = 343c125a8abSPierrick Bouvier qemu_plugin_scoreboard_new(sizeof(uint64_t)); 344c125a8abSPierrick Bouvier class_tables[i].table[j].count = qemu_plugin_scoreboard_u64(score); 345c125a8abSPierrick Bouvier } 346c125a8abSPierrick Bouvier } 347c125a8abSPierrick Bouvier 348c17a386bSAlex Bennée /* Select a class table appropriate to the guest architecture */ 349c17a386bSAlex Bennée for (i = 0; i < ARRAY_SIZE(class_tables); i++) { 350c17a386bSAlex Bennée ClassSelector *entry = &class_tables[i]; 351c17a386bSAlex Bennée if (!entry->qemu_target || 352c17a386bSAlex Bennée strcmp(entry->qemu_target, info->target_name) == 0) { 353c17a386bSAlex Bennée class_table = entry->table; 354c17a386bSAlex Bennée class_table_sz = entry->table_sz; 355c17a386bSAlex Bennée break; 356c17a386bSAlex Bennée } 357c17a386bSAlex Bennée } 358c17a386bSAlex Bennée 359c17a386bSAlex Bennée for (i = 0; i < argc; i++) { 360c17a386bSAlex Bennée char *p = argv[i]; 36140258741SAlex Bennée g_auto(GStrv) tokens = g_strsplit(p, "=", -1); 362d8525358SMahmoud Mandour if (g_strcmp0(tokens[0], "inline") == 0) { 363d8525358SMahmoud Mandour if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) { 364d8525358SMahmoud Mandour fprintf(stderr, "boolean argument parsing failed: %s\n", p); 365d8525358SMahmoud Mandour return -1; 366d8525358SMahmoud Mandour } 367d8525358SMahmoud Mandour } else if (g_strcmp0(tokens[0], "verbose") == 0) { 368d8525358SMahmoud Mandour if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &verbose)) { 369d8525358SMahmoud Mandour fprintf(stderr, "boolean argument parsing failed: %s\n", p); 370d8525358SMahmoud Mandour return -1; 371d8525358SMahmoud Mandour } 372d8525358SMahmoud Mandour } else if (g_strcmp0(tokens[0], "count") == 0) { 373d8525358SMahmoud Mandour char *value = tokens[1]; 374c17a386bSAlex Bennée int j; 375c17a386bSAlex Bennée CountType type = COUNT_INDIVIDUAL; 376d8525358SMahmoud Mandour if (*value == '!') { 377c17a386bSAlex Bennée type = COUNT_NONE; 378d8525358SMahmoud Mandour value++; 379c17a386bSAlex Bennée } 380c17a386bSAlex Bennée for (j = 0; j < class_table_sz; j++) { 381d8525358SMahmoud Mandour if (strcmp(value, class_table[j].opt) == 0) { 382c17a386bSAlex Bennée class_table[j].what = type; 383c17a386bSAlex Bennée break; 384c17a386bSAlex Bennée } 385c17a386bSAlex Bennée } 386d8525358SMahmoud Mandour } else { 387d8525358SMahmoud Mandour fprintf(stderr, "option parsing failed: %s\n", p); 388d8525358SMahmoud Mandour return -1; 389c17a386bSAlex Bennée } 390c17a386bSAlex Bennée } 391c17a386bSAlex Bennée 392c17a386bSAlex Bennée plugin_init(); 393c17a386bSAlex Bennée 394c17a386bSAlex Bennée qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); 395c17a386bSAlex Bennée qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); 396c17a386bSAlex Bennée return 0; 397c17a386bSAlex Bennée } 398