xref: /qemu/contrib/plugins/howvec.c (revision 4abc8923)
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 
cmp_exec_count(gconstpointer a,gconstpointer b)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 
free_record(gpointer data)167c17a386bSAlex Bennée static void free_record(gpointer data)
168c17a386bSAlex Bennée {
169c17a386bSAlex Bennée     InsnExecCount *rec = (InsnExecCount *) data;
17073281023SPaolo 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 
plugin_exit(qemu_plugin_id_t id,void * p)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 
plugin_init(void)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 
vcpu_insn_exec_before(unsigned int cpu_index,void * udata)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 
find_counter(struct qemu_plugin_insn * insn)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;
2554abc8923SRichard Henderson     uint32_t opcode = 0;
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      */
2644abc8923SRichard Henderson     qemu_plugin_insn_data(insn, &opcode, sizeof(opcode));
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 
vcpu_tb_trans(qemu_plugin_id_t id,struct qemu_plugin_tb * tb)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 
qemu_plugin_install(qemu_plugin_id_t id,const qemu_info_t * info,int argc,char ** argv)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