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