@@ -29,8 +29,8 @@
typedef struct TBContext TBContext;
struct TBContext {
-
struct qht htable;
+ struct qht stats;
/* statistics */
unsigned tb_flush_count;
@@ -141,6 +141,9 @@ struct TranslationBlock {
uintptr_t jmp_list_head;
uintptr_t jmp_list_next[2];
uintptr_t jmp_dest[2];
+
+ /* Pointer to a struct where statistics from the TB is stored */
+ TBStatistics *tb_stats;
};
/* The alignment given to TranslationBlock during allocation. */
@@ -131,6 +131,7 @@ typedef struct Range Range;
typedef struct ReservedRegion ReservedRegion;
typedef struct SHPCDevice SHPCDevice;
typedef struct SSIBus SSIBus;
+typedef struct TBStatistics TBStatistics;
typedef struct TCGHelperInfo TCGHelperInfo;
typedef struct TranslationBlock TranslationBlock;
typedef struct VirtIODevice VirtIODevice;
new file mode 100644
@@ -0,0 +1,132 @@
+/*
+ * QEMU System Emulator, Code Quality Monitor System
+ *
+ * Copyright (c) 2019 Vanderson M. do Rosario <vandersonmr2@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef TCG_TB_STATS_H
+#define TCG_TB_STATS_H 1
+
+#include "qemu/thread.h"
+#include "exec/translation-block.h"
+
+enum {
+ TB_STATS_EXEC = 1u << 0,
+ TB_STATS_JIT = 1u << 1,
+
+ TB_STATS_NONE = 0,
+ TB_STATS_ALL = TB_STATS_EXEC | TB_STATS_JIT,
+};
+
+extern uint32_t tb_stats_enabled;
+
+/**
+ * tb_stats_init:
+ * @flags: TB_STATS_* flags to enable.
+ *
+ * Initialize translation block statistics, enabling @flags.
+ * If @flags is 0, disable all statistics.
+ */
+void tb_stats_init(uint32_t flags);
+
+/*
+ * This struct stores statistics such as execution count of the
+ * TranslationBlocks. Each sets of TBs for a given phys_pc/pc/flags
+ * has its own TBStatistics which will persist over tb_flush.
+ *
+ * We include additional counters to track number of translations as
+ * well as variants for compile flags.
+ */
+struct TBStatistics {
+ tb_page_addr_t phys_pc;
+ vaddr pc;
+ uint32_t flags;
+ uint64_t flags2;
+
+ /* Execution stats */
+ struct {
+ unsigned long normal;
+ unsigned long atomic;
+ /* filled only when dumping x% cover set */
+ double coverage;
+ } executions;
+
+ /* JIT Stats - protected by lock */
+ QemuMutex jit_stats_lock;
+
+ /* Sum of all operations for all translations */
+ struct {
+ unsigned long num_guest_inst;
+ unsigned long num_tcg_ops;
+ unsigned long num_tcg_ops_opt;
+ unsigned long spills;
+
+ unsigned long temps;
+ unsigned long deleted_ops;
+ unsigned long in_len;
+ unsigned long out_len;
+ unsigned long search_out_len;
+ } code;
+
+ struct {
+ unsigned long total;
+ unsigned long spanning;
+ } translations;
+
+ /*
+ * All persistent (cached) TranslationBlocks using
+ * this TBStats structure. Has to be reset on a tb_flush.
+ */
+ GPtrArray *tbs;
+};
+
+/**
+ * tb_stats_enabled:
+ * @tb: TranslationBlock
+ * @f: flag to check
+ *
+ * Return true if any stats are enabled for @tb and
+ * if @f is enabled globally.
+ */
+static inline bool tb_stats_enabled_for_tb(TranslationBlock *tb, uint32_t f)
+{
+ return unlikely(tb_stats_enabled & f) && tb->tb_stats;
+}
+
+/**
+ * tb_stats_reset_tbs: reset the linked array of TBs
+ *
+ * Reset the list of tbs for a given array. Should be called from
+ * safe work during tb_flush.
+ */
+void tb_stats_reset_tbs(void);
+
+/**
+ * tb_stats_lookup:
+ *
+ * If any tb_stats are enabled, return a new or existing struct
+ * for the tuple (phys_pc, pc, flags, flags2). To be used when
+ * building a new TranslationBlock.
+ */
+TBStatistics *tb_stats_lookup(tb_page_addr_t phys_pc, vaddr pc,
+ uint32_t flags, uint64_t flags2);
+
+#endif /* TCG_TB_STATS_H */
@@ -27,6 +27,7 @@
#include "exec/translate-all.h"
#include "sysemu/tcg.h"
#include "tcg/tcg.h"
+#include "tcg/tb-stats.h"
#include "tb-hash.h"
#include "tb-context.h"
#include "internal-common.h"
@@ -772,7 +773,7 @@ static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count)
qht_reset_size(&tb_ctx.htable, CODE_GEN_HTABLE_SIZE);
tb_remove_all();
-
+ tb_stats_reset_tbs();
tcg_region_reset_all();
/* XXX: flush processor icache at this point if cache flush is expensive */
qatomic_inc(&tb_ctx.tb_flush_count);
new file mode 100644
@@ -0,0 +1,85 @@
+/*
+ * QEMU System Emulator, Code Quality Monitor System
+ *
+ * Copyright (c) 2019 Vanderson M. do Rosario <vandersonmr2@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/xxhash.h"
+#include "tcg/tb-stats.h"
+#include "tb-context.h"
+
+uint32_t tb_stats_enabled;
+
+static bool tb_stats_cmp(const void *ap, const void *bp)
+{
+ const TBStatistics *a = ap;
+ const TBStatistics *b = bp;
+
+ return a->phys_pc == b->phys_pc &&
+ a->pc == b->pc &&
+ a->flags == b->flags &&
+ a->flags2 == b->flags2;
+
+}
+
+static void tb_stats_free(void *p, uint32_t hash, void *userp)
+{
+ TBStatistics *s = p;
+
+ qemu_mutex_destroy(&s->jit_stats_lock);
+ g_ptr_array_free(s->tbs, true);
+ g_free(s);
+}
+
+void tb_stats_init(uint32_t flags)
+{
+ tb_stats_enabled = flags;
+ if (flags) {
+ if (!tb_ctx.stats.map) {
+ qht_init(&tb_ctx.stats, tb_stats_cmp,
+ CODE_GEN_HTABLE_SIZE, QHT_MODE_AUTO_RESIZE);
+ }
+ } else {
+ qht_iter(&tb_ctx.stats, tb_stats_free, NULL);
+ qht_destroy(&tb_ctx.stats);
+ }
+}
+
+static void tb_stats_reset(void *p, uint32_t hash, void *userp)
+{
+ TBStatistics *s = p;
+ g_ptr_array_set_size(s->tbs, 0);
+}
+
+void tb_stats_reset_tbs(void)
+{
+ if (tb_ctx.stats.map) {
+ qht_iter(&tb_ctx.stats, tb_stats_reset, NULL);
+ }
+}
+
+TBStatistics *tb_stats_lookup(tb_page_addr_t phys_pc, vaddr pc,
+ uint32_t flags, uint64_t flags2)
+{
+ TBStatistics *s;
+ uint32_t h;
+ void *existing;
+
+ s = g_new0(TBStatistics, 1);
+ s->phys_pc = phys_pc;
+ s->pc = pc;
+ s->flags = flags;
+ s->flags2 = flags2;
+ s->tbs = g_ptr_array_new();
+ qemu_mutex_init(&s->jit_stats_lock);
+
+ h = qemu_xxhash7(phys_pc, pc, flags2, flags);
+ if (!qht_insert(&tb_ctx.stats, s, h, &existing)) {
+ tb_stats_free(s, 0, NULL);
+ return existing;
+ }
+ return s;
+}
@@ -65,6 +65,7 @@
#include "internal-target.h"
#include "perf.h"
#include "tcg/insn-start-words.h"
+#include "tcg/tb-stats.h"
TBContext tb_ctx;
@@ -353,6 +354,24 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tcg_ctx->guest_mo = TCG_MO_ALL;
#endif
+ /*
+ * Insert the TB into the corresponding stats structure, if required.
+ * Do this before code generation so that translator_loop can see
+ * the structure address.
+ */
+ tb->tb_stats = NULL;
+ if (unlikely(tb_stats_enabled) && qemu_log_in_addr_range(pc)) {
+ TBStatistics *s = tb_stats_lookup(phys_pc,
+ cflags & CF_PCREL ? 0 : pc,
+ flags, cs_base);
+ if (s) {
+ tb->tb_stats = s;
+ qemu_mutex_lock(&s->jit_stats_lock);
+ g_ptr_array_add(s->tbs, tb);
+ qemu_mutex_unlock(&s->jit_stats_lock);
+ }
+ }
+
restart_translate:
trace_translate_block(tb, pc, tb->tc.ptr);
@@ -6,6 +6,7 @@ tcg_ss.add(files(
'tcg-all.c',
'cpu-exec.c',
'tb-maint.c',
+ 'tb-stats.c',
'tcg-runtime-gvec.c',
'tcg-runtime.c',
'translate-all.c',