2 * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
4 * License: GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
15 #include <qemu-plugin.h>
17 QEMU_PLUGIN_EXPORT
int qemu_plugin_version
= QEMU_PLUGIN_VERSION
;
26 /* Used by the inline & linux-user counts */
27 static bool do_inline
;
28 static CPUCount inline_count
;
30 /* Dump running CPU total on idle? */
31 static bool idle_report
;
32 static GPtrArray
*counts
;
35 static void gen_one_cpu_report(CPUCount
*count
, GString
*report
)
37 if (count
->bb_count
) {
38 g_string_append_printf(report
, "CPU%d: "
39 "bb's: %" PRIu64
", insns: %" PRIu64
"\n",
41 count
->bb_count
, count
->insn_count
);
45 static void plugin_exit(qemu_plugin_id_t id
, void *p
)
47 g_autoptr(GString
) report
= g_string_new("");
49 if (do_inline
|| !max_cpus
) {
50 g_string_printf(report
, "bb's: %" PRIu64
", insns: %" PRIu64
"\n",
51 inline_count
.bb_count
, inline_count
.insn_count
);
53 g_ptr_array_foreach(counts
, (GFunc
) gen_one_cpu_report
, report
);
55 qemu_plugin_outs(report
->str
);
58 static void vcpu_idle(qemu_plugin_id_t id
, unsigned int cpu_index
)
60 CPUCount
*count
= g_ptr_array_index(counts
, cpu_index
);
61 g_autoptr(GString
) report
= g_string_new("");
62 gen_one_cpu_report(count
, report
);
64 if (report
->len
> 0) {
65 g_string_prepend(report
, "Idling ");
66 qemu_plugin_outs(report
->str
);
70 static void vcpu_tb_exec(unsigned int cpu_index
, void *udata
)
72 CPUCount
*count
= max_cpus
?
73 g_ptr_array_index(counts
, cpu_index
) : &inline_count
;
75 uintptr_t n_insns
= (uintptr_t)udata
;
76 g_mutex_lock(&count
->lock
);
77 count
->insn_count
+= n_insns
;
79 g_mutex_unlock(&count
->lock
);
82 static void vcpu_tb_trans(qemu_plugin_id_t id
, struct qemu_plugin_tb
*tb
)
84 size_t n_insns
= qemu_plugin_tb_n_insns(tb
);
87 qemu_plugin_register_vcpu_tb_exec_inline(tb
, QEMU_PLUGIN_INLINE_ADD_U64
,
88 &inline_count
.bb_count
, 1);
89 qemu_plugin_register_vcpu_tb_exec_inline(tb
, QEMU_PLUGIN_INLINE_ADD_U64
,
90 &inline_count
.insn_count
,
93 qemu_plugin_register_vcpu_tb_exec_cb(tb
, vcpu_tb_exec
,
94 QEMU_PLUGIN_CB_NO_REGS
,
99 QEMU_PLUGIN_EXPORT
int qemu_plugin_install(qemu_plugin_id_t id
,
100 const qemu_info_t
*info
,
101 int argc
, char **argv
)
105 for (i
= 0; i
< argc
; i
++) {
107 g_autofree
char **tokens
= g_strsplit(opt
, "=", 2);
108 if (g_strcmp0(tokens
[0], "inline") == 0) {
109 if (!qemu_plugin_bool_parse(tokens
[0], tokens
[1], &do_inline
)) {
110 fprintf(stderr
, "boolean argument parsing failed: %s\n", opt
);
113 } else if (g_strcmp0(tokens
[0], "idle") == 0) {
114 if (!qemu_plugin_bool_parse(tokens
[0], tokens
[1], &idle_report
)) {
115 fprintf(stderr
, "boolean argument parsing failed: %s\n", opt
);
119 fprintf(stderr
, "option parsing failed: %s\n", opt
);
124 if (info
->system_emulation
&& !do_inline
) {
125 max_cpus
= info
->system
.max_vcpus
;
126 counts
= g_ptr_array_new();
127 for (i
= 0; i
< max_cpus
; i
++) {
128 CPUCount
*count
= g_new0(CPUCount
, 1);
129 g_mutex_init(&count
->lock
);
131 g_ptr_array_add(counts
, count
);
133 } else if (!do_inline
) {
134 g_mutex_init(&inline_count
.lock
);
138 qemu_plugin_register_vcpu_idle_cb(id
, vcpu_idle
);
141 qemu_plugin_register_vcpu_tb_trans_cb(id
, vcpu_tb_trans
);
142 qemu_plugin_register_atexit_cb(id
, plugin_exit
, NULL
);