xref: /openbmc/qemu/contrib/plugins/bbv.c (revision 0d279bec)
1*0d279becSAkihiko Odaki /*
2*0d279becSAkihiko Odaki  * Generate basic block vectors for use with the SimPoint analysis tool.
3*0d279becSAkihiko Odaki  * SimPoint: https://cseweb.ucsd.edu/~calder/simpoint/
4*0d279becSAkihiko Odaki  *
5*0d279becSAkihiko Odaki  * SPDX-License-Identifier: GPL-2.0-or-later
6*0d279becSAkihiko Odaki  */
7*0d279becSAkihiko Odaki 
8*0d279becSAkihiko Odaki #include <stdio.h>
9*0d279becSAkihiko Odaki #include <glib.h>
10*0d279becSAkihiko Odaki 
11*0d279becSAkihiko Odaki #include <qemu-plugin.h>
12*0d279becSAkihiko Odaki 
13*0d279becSAkihiko Odaki typedef struct Bb {
14*0d279becSAkihiko Odaki     uint64_t vaddr;
15*0d279becSAkihiko Odaki     struct qemu_plugin_scoreboard *count;
16*0d279becSAkihiko Odaki     unsigned int index;
17*0d279becSAkihiko Odaki } Bb;
18*0d279becSAkihiko Odaki 
19*0d279becSAkihiko Odaki typedef struct Vcpu {
20*0d279becSAkihiko Odaki     uint64_t count;
21*0d279becSAkihiko Odaki     FILE *file;
22*0d279becSAkihiko Odaki } Vcpu;
23*0d279becSAkihiko Odaki 
24*0d279becSAkihiko Odaki QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
25*0d279becSAkihiko Odaki static GHashTable *bbs;
26*0d279becSAkihiko Odaki static GRWLock bbs_lock;
27*0d279becSAkihiko Odaki static char *filename;
28*0d279becSAkihiko Odaki static struct qemu_plugin_scoreboard *vcpus;
29*0d279becSAkihiko Odaki static uint64_t interval = 100000000;
30*0d279becSAkihiko Odaki 
plugin_exit(qemu_plugin_id_t id,void * p)31*0d279becSAkihiko Odaki static void plugin_exit(qemu_plugin_id_t id, void *p)
32*0d279becSAkihiko Odaki {
33*0d279becSAkihiko Odaki     for (int i = 0; i < qemu_plugin_num_vcpus(); i++) {
34*0d279becSAkihiko Odaki         fclose(((Vcpu *)qemu_plugin_scoreboard_find(vcpus, i))->file);
35*0d279becSAkihiko Odaki     }
36*0d279becSAkihiko Odaki 
37*0d279becSAkihiko Odaki     g_hash_table_unref(bbs);
38*0d279becSAkihiko Odaki     g_free(filename);
39*0d279becSAkihiko Odaki     qemu_plugin_scoreboard_free(vcpus);
40*0d279becSAkihiko Odaki }
41*0d279becSAkihiko Odaki 
free_bb(void * data)42*0d279becSAkihiko Odaki static void free_bb(void *data)
43*0d279becSAkihiko Odaki {
44*0d279becSAkihiko Odaki     qemu_plugin_scoreboard_free(((Bb *)data)->count);
45*0d279becSAkihiko Odaki     g_free(data);
46*0d279becSAkihiko Odaki }
47*0d279becSAkihiko Odaki 
count_u64(void)48*0d279becSAkihiko Odaki static qemu_plugin_u64 count_u64(void)
49*0d279becSAkihiko Odaki {
50*0d279becSAkihiko Odaki     return qemu_plugin_scoreboard_u64_in_struct(vcpus, Vcpu, count);
51*0d279becSAkihiko Odaki }
52*0d279becSAkihiko Odaki 
bb_count_u64(Bb * bb)53*0d279becSAkihiko Odaki static qemu_plugin_u64 bb_count_u64(Bb *bb)
54*0d279becSAkihiko Odaki {
55*0d279becSAkihiko Odaki     return qemu_plugin_scoreboard_u64(bb->count);
56*0d279becSAkihiko Odaki }
57*0d279becSAkihiko Odaki 
vcpu_init(qemu_plugin_id_t id,unsigned int vcpu_index)58*0d279becSAkihiko Odaki static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
59*0d279becSAkihiko Odaki {
60*0d279becSAkihiko Odaki     g_autofree gchar *vcpu_filename = NULL;
61*0d279becSAkihiko Odaki     Vcpu *vcpu = qemu_plugin_scoreboard_find(vcpus, vcpu_index);
62*0d279becSAkihiko Odaki 
63*0d279becSAkihiko Odaki     vcpu_filename = g_strdup_printf("%s.%u.bb", filename, vcpu_index);
64*0d279becSAkihiko Odaki     vcpu->file = fopen(vcpu_filename, "w");
65*0d279becSAkihiko Odaki }
66*0d279becSAkihiko Odaki 
vcpu_interval_exec(unsigned int vcpu_index,void * udata)67*0d279becSAkihiko Odaki static void vcpu_interval_exec(unsigned int vcpu_index, void *udata)
68*0d279becSAkihiko Odaki {
69*0d279becSAkihiko Odaki     Vcpu *vcpu = qemu_plugin_scoreboard_find(vcpus, vcpu_index);
70*0d279becSAkihiko Odaki     GHashTableIter iter;
71*0d279becSAkihiko Odaki     void *value;
72*0d279becSAkihiko Odaki 
73*0d279becSAkihiko Odaki     if (!vcpu->file) {
74*0d279becSAkihiko Odaki         return;
75*0d279becSAkihiko Odaki     }
76*0d279becSAkihiko Odaki 
77*0d279becSAkihiko Odaki     vcpu->count -= interval;
78*0d279becSAkihiko Odaki 
79*0d279becSAkihiko Odaki     fputc('T', vcpu->file);
80*0d279becSAkihiko Odaki 
81*0d279becSAkihiko Odaki     g_rw_lock_reader_lock(&bbs_lock);
82*0d279becSAkihiko Odaki     g_hash_table_iter_init(&iter, bbs);
83*0d279becSAkihiko Odaki 
84*0d279becSAkihiko Odaki     while (g_hash_table_iter_next(&iter, NULL, &value)) {
85*0d279becSAkihiko Odaki         Bb *bb = value;
86*0d279becSAkihiko Odaki         uint64_t bb_count = qemu_plugin_u64_get(bb_count_u64(bb), vcpu_index);
87*0d279becSAkihiko Odaki 
88*0d279becSAkihiko Odaki         if (!bb_count) {
89*0d279becSAkihiko Odaki             continue;
90*0d279becSAkihiko Odaki         }
91*0d279becSAkihiko Odaki 
92*0d279becSAkihiko Odaki         fprintf(vcpu->file, ":%u:%" PRIu64 " ", bb->index, bb_count);
93*0d279becSAkihiko Odaki         qemu_plugin_u64_set(bb_count_u64(bb), vcpu_index, 0);
94*0d279becSAkihiko Odaki     }
95*0d279becSAkihiko Odaki 
96*0d279becSAkihiko Odaki     g_rw_lock_reader_unlock(&bbs_lock);
97*0d279becSAkihiko Odaki     fputc('\n', vcpu->file);
98*0d279becSAkihiko Odaki }
99*0d279becSAkihiko Odaki 
vcpu_tb_trans(qemu_plugin_id_t id,struct qemu_plugin_tb * tb)100*0d279becSAkihiko Odaki static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
101*0d279becSAkihiko Odaki {
102*0d279becSAkihiko Odaki     uint64_t n_insns = qemu_plugin_tb_n_insns(tb);
103*0d279becSAkihiko Odaki     uint64_t vaddr = qemu_plugin_tb_vaddr(tb);
104*0d279becSAkihiko Odaki     Bb *bb;
105*0d279becSAkihiko Odaki 
106*0d279becSAkihiko Odaki     g_rw_lock_writer_lock(&bbs_lock);
107*0d279becSAkihiko Odaki     bb = g_hash_table_lookup(bbs, &vaddr);
108*0d279becSAkihiko Odaki     if (!bb) {
109*0d279becSAkihiko Odaki         bb = g_new(Bb, 1);
110*0d279becSAkihiko Odaki         bb->vaddr = vaddr;
111*0d279becSAkihiko Odaki         bb->count = qemu_plugin_scoreboard_new(sizeof(uint64_t));
112*0d279becSAkihiko Odaki         bb->index = g_hash_table_size(bbs);
113*0d279becSAkihiko Odaki         g_hash_table_replace(bbs, &bb->vaddr, bb);
114*0d279becSAkihiko Odaki     }
115*0d279becSAkihiko Odaki     g_rw_lock_writer_unlock(&bbs_lock);
116*0d279becSAkihiko Odaki 
117*0d279becSAkihiko Odaki     qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
118*0d279becSAkihiko Odaki         tb, QEMU_PLUGIN_INLINE_ADD_U64, count_u64(), n_insns);
119*0d279becSAkihiko Odaki 
120*0d279becSAkihiko Odaki     qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
121*0d279becSAkihiko Odaki         tb, QEMU_PLUGIN_INLINE_ADD_U64, bb_count_u64(bb), n_insns);
122*0d279becSAkihiko Odaki 
123*0d279becSAkihiko Odaki     qemu_plugin_register_vcpu_tb_exec_cond_cb(
124*0d279becSAkihiko Odaki         tb, vcpu_interval_exec, QEMU_PLUGIN_CB_NO_REGS,
125*0d279becSAkihiko Odaki         QEMU_PLUGIN_COND_GE, count_u64(), interval, NULL);
126*0d279becSAkihiko Odaki }
127*0d279becSAkihiko Odaki 
qemu_plugin_install(qemu_plugin_id_t id,const qemu_info_t * info,int argc,char ** argv)128*0d279becSAkihiko Odaki QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
129*0d279becSAkihiko Odaki                                            const qemu_info_t *info,
130*0d279becSAkihiko Odaki                                            int argc, char **argv)
131*0d279becSAkihiko Odaki {
132*0d279becSAkihiko Odaki     for (int i = 0; i < argc; i++) {
133*0d279becSAkihiko Odaki         char *opt = argv[i];
134*0d279becSAkihiko Odaki         g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
135*0d279becSAkihiko Odaki         if (g_strcmp0(tokens[0], "interval") == 0) {
136*0d279becSAkihiko Odaki             interval = g_ascii_strtoull(tokens[1], NULL, 10);
137*0d279becSAkihiko Odaki         } else if (g_strcmp0(tokens[0], "outfile") == 0) {
138*0d279becSAkihiko Odaki             filename = tokens[1];
139*0d279becSAkihiko Odaki             tokens[1] = NULL;
140*0d279becSAkihiko Odaki         } else {
141*0d279becSAkihiko Odaki             fprintf(stderr, "option parsing failed: %s\n", opt);
142*0d279becSAkihiko Odaki             return -1;
143*0d279becSAkihiko Odaki         }
144*0d279becSAkihiko Odaki     }
145*0d279becSAkihiko Odaki 
146*0d279becSAkihiko Odaki     if (!filename) {
147*0d279becSAkihiko Odaki         fputs("outfile unspecified\n", stderr);
148*0d279becSAkihiko Odaki         return -1;
149*0d279becSAkihiko Odaki     }
150*0d279becSAkihiko Odaki 
151*0d279becSAkihiko Odaki     bbs = g_hash_table_new_full(g_int64_hash, g_int64_equal, NULL, free_bb);
152*0d279becSAkihiko Odaki     vcpus = qemu_plugin_scoreboard_new(sizeof(Vcpu));
153*0d279becSAkihiko Odaki     qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
154*0d279becSAkihiko Odaki     qemu_plugin_register_vcpu_init_cb(id, vcpu_init);
155*0d279becSAkihiko Odaki     qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
156*0d279becSAkihiko Odaki 
157*0d279becSAkihiko Odaki     return 0;
158*0d279becSAkihiko Odaki }
159