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;
255*4abc8923SRichard 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 */
264*4abc8923SRichard 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