qemu/tests/plugin/bb.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
   3 *
   4 * License: GNU GPL, version 2 or later.
   5 *   See the COPYING file in the top-level directory.
   6 */
   7#include <inttypes.h>
   8#include <assert.h>
   9#include <stdlib.h>
  10#include <string.h>
  11#include <unistd.h>
  12#include <stdio.h>
  13#include <glib.h>
  14
  15#include <qemu-plugin.h>
  16
  17QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
  18
  19typedef struct {
  20    GMutex lock;
  21    int index;
  22    uint64_t bb_count;
  23    uint64_t insn_count;
  24} CPUCount;
  25
  26/* Used by the inline & linux-user counts */
  27static bool do_inline;
  28static CPUCount inline_count;
  29
  30/* Dump running CPU total on idle? */
  31static bool idle_report;
  32static GPtrArray *counts;
  33static int max_cpus;
  34
  35static void gen_one_cpu_report(CPUCount *count, GString *report)
  36{
  37    if (count->bb_count) {
  38        g_string_append_printf(report, "CPU%d: "
  39                               "bb's: %" PRIu64", insns: %" PRIu64 "\n",
  40                               count->index,
  41                               count->bb_count, count->insn_count);
  42    }
  43}
  44
  45static void plugin_exit(qemu_plugin_id_t id, void *p)
  46{
  47    g_autoptr(GString) report = g_string_new("");
  48
  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);
  52    } else {
  53        g_ptr_array_foreach(counts, (GFunc) gen_one_cpu_report, report);
  54    }
  55    qemu_plugin_outs(report->str);
  56}
  57
  58static void vcpu_idle(qemu_plugin_id_t id, unsigned int cpu_index)
  59{
  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);
  63
  64    if (report->len > 0) {
  65        g_string_prepend(report, "Idling ");
  66        qemu_plugin_outs(report->str);
  67    }
  68}
  69
  70static void vcpu_tb_exec(unsigned int cpu_index, void *udata)
  71{
  72    CPUCount *count = max_cpus ?
  73        g_ptr_array_index(counts, cpu_index) : &inline_count;
  74
  75    uintptr_t n_insns = (uintptr_t)udata;
  76    g_mutex_lock(&count->lock);
  77    count->insn_count += n_insns;
  78    count->bb_count++;
  79    g_mutex_unlock(&count->lock);
  80}
  81
  82static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
  83{
  84    size_t n_insns = qemu_plugin_tb_n_insns(tb);
  85
  86    if (do_inline) {
  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,
  91                                                 n_insns);
  92    } else {
  93        qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec,
  94                                             QEMU_PLUGIN_CB_NO_REGS,
  95                                             (void *)n_insns);
  96    }
  97}
  98
  99QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
 100                                           const qemu_info_t *info,
 101                                           int argc, char **argv)
 102{
 103    int i;
 104
 105    for (i = 0; i < argc; i++) {
 106        char *opt = argv[i];
 107        if (g_strcmp0(opt, "inline") == 0) {
 108            do_inline = true;
 109        } else if (g_strcmp0(opt, "idle") == 0) {
 110            idle_report = true;
 111        } else {
 112            fprintf(stderr, "option parsing failed: %s\n", opt);
 113            return -1;
 114        }
 115    }
 116
 117    if (info->system_emulation && !do_inline) {
 118        max_cpus = info->system.max_vcpus;
 119        counts = g_ptr_array_new();
 120        for (i = 0; i < max_cpus; i++) {
 121            CPUCount *count = g_new0(CPUCount, 1);
 122            g_mutex_init(&count->lock);
 123            count->index = i;
 124            g_ptr_array_add(counts, count);
 125        }
 126    } else if (!do_inline) {
 127        g_mutex_init(&inline_count.lock);
 128    }
 129
 130    if (idle_report) {
 131        qemu_plugin_register_vcpu_idle_cb(id, vcpu_idle);
 132    }
 133
 134    qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
 135    qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
 136    return 0;
 137}
 138