1*e2c5557cSMahmoud Mandour /* 2*e2c5557cSMahmoud Mandour * Copyright (C) 2021, Mahmoud Mandour <ma.mandourr@gmail.com> 3*e2c5557cSMahmoud Mandour * 4*e2c5557cSMahmoud Mandour * License: GNU GPL, version 2 or later. 5*e2c5557cSMahmoud Mandour * See the COPYING file in the top-level directory. 6*e2c5557cSMahmoud Mandour */ 7*e2c5557cSMahmoud Mandour 8*e2c5557cSMahmoud Mandour #include <inttypes.h> 9*e2c5557cSMahmoud Mandour #include <stdio.h> 10*e2c5557cSMahmoud Mandour #include <glib.h> 11*e2c5557cSMahmoud Mandour 12*e2c5557cSMahmoud Mandour #include <qemu-plugin.h> 13*e2c5557cSMahmoud Mandour 14*e2c5557cSMahmoud Mandour QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; 15*e2c5557cSMahmoud Mandour 16*e2c5557cSMahmoud Mandour static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW; 17*e2c5557cSMahmoud Mandour 18*e2c5557cSMahmoud Mandour static GHashTable *miss_ht; 19*e2c5557cSMahmoud Mandour 20*e2c5557cSMahmoud Mandour static GMutex mtx; 21*e2c5557cSMahmoud Mandour static GRand *rng; 22*e2c5557cSMahmoud Mandour 23*e2c5557cSMahmoud Mandour static int limit; 24*e2c5557cSMahmoud Mandour static bool sys; 25*e2c5557cSMahmoud Mandour 26*e2c5557cSMahmoud Mandour static uint64_t dmem_accesses; 27*e2c5557cSMahmoud Mandour static uint64_t dmisses; 28*e2c5557cSMahmoud Mandour 29*e2c5557cSMahmoud Mandour static uint64_t imem_accesses; 30*e2c5557cSMahmoud Mandour static uint64_t imisses; 31*e2c5557cSMahmoud Mandour 32*e2c5557cSMahmoud Mandour /* 33*e2c5557cSMahmoud Mandour * A CacheSet is a set of cache blocks. A memory block that maps to a set can be 34*e2c5557cSMahmoud Mandour * put in any of the blocks inside the set. The number of block per set is 35*e2c5557cSMahmoud Mandour * called the associativity (assoc). 36*e2c5557cSMahmoud Mandour * 37*e2c5557cSMahmoud Mandour * Each block contains the the stored tag and a valid bit. Since this is not 38*e2c5557cSMahmoud Mandour * a functional simulator, the data itself is not stored. We only identify 39*e2c5557cSMahmoud Mandour * whether a block is in the cache or not by searching for its tag. 40*e2c5557cSMahmoud Mandour * 41*e2c5557cSMahmoud Mandour * In order to search for memory data in the cache, the set identifier and tag 42*e2c5557cSMahmoud Mandour * are extracted from the address and the set is probed to see whether a tag 43*e2c5557cSMahmoud Mandour * match occur. 44*e2c5557cSMahmoud Mandour * 45*e2c5557cSMahmoud Mandour * An address is logically divided into three portions: The block offset, 46*e2c5557cSMahmoud Mandour * the set number, and the tag. 47*e2c5557cSMahmoud Mandour * 48*e2c5557cSMahmoud Mandour * The set number is used to identify the set in which the block may exist. 49*e2c5557cSMahmoud Mandour * The tag is compared against all the tags of a set to search for a match. If a 50*e2c5557cSMahmoud Mandour * match is found, then the access is a hit. 51*e2c5557cSMahmoud Mandour */ 52*e2c5557cSMahmoud Mandour 53*e2c5557cSMahmoud Mandour typedef struct { 54*e2c5557cSMahmoud Mandour uint64_t tag; 55*e2c5557cSMahmoud Mandour bool valid; 56*e2c5557cSMahmoud Mandour } CacheBlock; 57*e2c5557cSMahmoud Mandour 58*e2c5557cSMahmoud Mandour typedef struct { 59*e2c5557cSMahmoud Mandour CacheBlock *blocks; 60*e2c5557cSMahmoud Mandour } CacheSet; 61*e2c5557cSMahmoud Mandour 62*e2c5557cSMahmoud Mandour typedef struct { 63*e2c5557cSMahmoud Mandour CacheSet *sets; 64*e2c5557cSMahmoud Mandour int num_sets; 65*e2c5557cSMahmoud Mandour int cachesize; 66*e2c5557cSMahmoud Mandour int assoc; 67*e2c5557cSMahmoud Mandour int blksize_shift; 68*e2c5557cSMahmoud Mandour uint64_t set_mask; 69*e2c5557cSMahmoud Mandour uint64_t tag_mask; 70*e2c5557cSMahmoud Mandour } Cache; 71*e2c5557cSMahmoud Mandour 72*e2c5557cSMahmoud Mandour typedef struct { 73*e2c5557cSMahmoud Mandour char *disas_str; 74*e2c5557cSMahmoud Mandour const char *symbol; 75*e2c5557cSMahmoud Mandour uint64_t addr; 76*e2c5557cSMahmoud Mandour uint64_t dmisses; 77*e2c5557cSMahmoud Mandour uint64_t imisses; 78*e2c5557cSMahmoud Mandour } InsnData; 79*e2c5557cSMahmoud Mandour 80*e2c5557cSMahmoud Mandour Cache *dcache, *icache; 81*e2c5557cSMahmoud Mandour 82*e2c5557cSMahmoud Mandour static int pow_of_two(int num) 83*e2c5557cSMahmoud Mandour { 84*e2c5557cSMahmoud Mandour g_assert((num & (num - 1)) == 0); 85*e2c5557cSMahmoud Mandour int ret = 0; 86*e2c5557cSMahmoud Mandour while (num /= 2) { 87*e2c5557cSMahmoud Mandour ret++; 88*e2c5557cSMahmoud Mandour } 89*e2c5557cSMahmoud Mandour return ret; 90*e2c5557cSMahmoud Mandour } 91*e2c5557cSMahmoud Mandour 92*e2c5557cSMahmoud Mandour static inline uint64_t extract_tag(Cache *cache, uint64_t addr) 93*e2c5557cSMahmoud Mandour { 94*e2c5557cSMahmoud Mandour return addr & cache->tag_mask; 95*e2c5557cSMahmoud Mandour } 96*e2c5557cSMahmoud Mandour 97*e2c5557cSMahmoud Mandour static inline uint64_t extract_set(Cache *cache, uint64_t addr) 98*e2c5557cSMahmoud Mandour { 99*e2c5557cSMahmoud Mandour return (addr & cache->set_mask) >> cache->blksize_shift; 100*e2c5557cSMahmoud Mandour } 101*e2c5557cSMahmoud Mandour 102*e2c5557cSMahmoud Mandour static Cache *cache_init(int blksize, int assoc, int cachesize) 103*e2c5557cSMahmoud Mandour { 104*e2c5557cSMahmoud Mandour Cache *cache; 105*e2c5557cSMahmoud Mandour int i; 106*e2c5557cSMahmoud Mandour uint64_t blk_mask; 107*e2c5557cSMahmoud Mandour 108*e2c5557cSMahmoud Mandour cache = g_new(Cache, 1); 109*e2c5557cSMahmoud Mandour cache->assoc = assoc; 110*e2c5557cSMahmoud Mandour cache->cachesize = cachesize; 111*e2c5557cSMahmoud Mandour cache->num_sets = cachesize / (blksize * assoc); 112*e2c5557cSMahmoud Mandour cache->sets = g_new(CacheSet, cache->num_sets); 113*e2c5557cSMahmoud Mandour cache->blksize_shift = pow_of_two(blksize); 114*e2c5557cSMahmoud Mandour 115*e2c5557cSMahmoud Mandour for (i = 0; i < cache->num_sets; i++) { 116*e2c5557cSMahmoud Mandour cache->sets[i].blocks = g_new0(CacheBlock, assoc); 117*e2c5557cSMahmoud Mandour } 118*e2c5557cSMahmoud Mandour 119*e2c5557cSMahmoud Mandour blk_mask = blksize - 1; 120*e2c5557cSMahmoud Mandour cache->set_mask = ((cache->num_sets - 1) << cache->blksize_shift); 121*e2c5557cSMahmoud Mandour cache->tag_mask = ~(cache->set_mask | blk_mask); 122*e2c5557cSMahmoud Mandour return cache; 123*e2c5557cSMahmoud Mandour } 124*e2c5557cSMahmoud Mandour 125*e2c5557cSMahmoud Mandour static int get_invalid_block(Cache *cache, uint64_t set) 126*e2c5557cSMahmoud Mandour { 127*e2c5557cSMahmoud Mandour int i; 128*e2c5557cSMahmoud Mandour 129*e2c5557cSMahmoud Mandour for (i = 0; i < cache->assoc; i++) { 130*e2c5557cSMahmoud Mandour if (!cache->sets[set].blocks[i].valid) { 131*e2c5557cSMahmoud Mandour return i; 132*e2c5557cSMahmoud Mandour } 133*e2c5557cSMahmoud Mandour } 134*e2c5557cSMahmoud Mandour 135*e2c5557cSMahmoud Mandour return -1; 136*e2c5557cSMahmoud Mandour } 137*e2c5557cSMahmoud Mandour 138*e2c5557cSMahmoud Mandour static int get_replaced_block(Cache *cache) 139*e2c5557cSMahmoud Mandour { 140*e2c5557cSMahmoud Mandour return g_rand_int_range(rng, 0, cache->assoc); 141*e2c5557cSMahmoud Mandour } 142*e2c5557cSMahmoud Mandour 143*e2c5557cSMahmoud Mandour static bool in_cache(Cache *cache, uint64_t addr) 144*e2c5557cSMahmoud Mandour { 145*e2c5557cSMahmoud Mandour int i; 146*e2c5557cSMahmoud Mandour uint64_t tag, set; 147*e2c5557cSMahmoud Mandour 148*e2c5557cSMahmoud Mandour tag = extract_tag(cache, addr); 149*e2c5557cSMahmoud Mandour set = extract_set(cache, addr); 150*e2c5557cSMahmoud Mandour 151*e2c5557cSMahmoud Mandour for (i = 0; i < cache->assoc; i++) { 152*e2c5557cSMahmoud Mandour if (cache->sets[set].blocks[i].tag == tag && 153*e2c5557cSMahmoud Mandour cache->sets[set].blocks[i].valid) { 154*e2c5557cSMahmoud Mandour return true; 155*e2c5557cSMahmoud Mandour } 156*e2c5557cSMahmoud Mandour } 157*e2c5557cSMahmoud Mandour 158*e2c5557cSMahmoud Mandour return false; 159*e2c5557cSMahmoud Mandour } 160*e2c5557cSMahmoud Mandour 161*e2c5557cSMahmoud Mandour /** 162*e2c5557cSMahmoud Mandour * access_cache(): Simulate a cache access 163*e2c5557cSMahmoud Mandour * @cache: The cache under simulation 164*e2c5557cSMahmoud Mandour * @addr: The address of the requested memory location 165*e2c5557cSMahmoud Mandour * 166*e2c5557cSMahmoud Mandour * Returns true if the requsted data is hit in the cache and false when missed. 167*e2c5557cSMahmoud Mandour * The cache is updated on miss for the next access. 168*e2c5557cSMahmoud Mandour */ 169*e2c5557cSMahmoud Mandour static bool access_cache(Cache *cache, uint64_t addr) 170*e2c5557cSMahmoud Mandour { 171*e2c5557cSMahmoud Mandour uint64_t tag, set; 172*e2c5557cSMahmoud Mandour int replaced_blk; 173*e2c5557cSMahmoud Mandour 174*e2c5557cSMahmoud Mandour if (in_cache(cache, addr)) { 175*e2c5557cSMahmoud Mandour return true; 176*e2c5557cSMahmoud Mandour } 177*e2c5557cSMahmoud Mandour 178*e2c5557cSMahmoud Mandour tag = extract_tag(cache, addr); 179*e2c5557cSMahmoud Mandour set = extract_set(cache, addr); 180*e2c5557cSMahmoud Mandour 181*e2c5557cSMahmoud Mandour replaced_blk = get_invalid_block(cache, set); 182*e2c5557cSMahmoud Mandour 183*e2c5557cSMahmoud Mandour if (replaced_blk == -1) { 184*e2c5557cSMahmoud Mandour replaced_blk = get_replaced_block(cache); 185*e2c5557cSMahmoud Mandour } 186*e2c5557cSMahmoud Mandour 187*e2c5557cSMahmoud Mandour cache->sets[set].blocks[replaced_blk].tag = tag; 188*e2c5557cSMahmoud Mandour cache->sets[set].blocks[replaced_blk].valid = true; 189*e2c5557cSMahmoud Mandour 190*e2c5557cSMahmoud Mandour return false; 191*e2c5557cSMahmoud Mandour } 192*e2c5557cSMahmoud Mandour 193*e2c5557cSMahmoud Mandour static void vcpu_mem_access(unsigned int vcpu_index, qemu_plugin_meminfo_t info, 194*e2c5557cSMahmoud Mandour uint64_t vaddr, void *userdata) 195*e2c5557cSMahmoud Mandour { 196*e2c5557cSMahmoud Mandour uint64_t effective_addr; 197*e2c5557cSMahmoud Mandour struct qemu_plugin_hwaddr *hwaddr; 198*e2c5557cSMahmoud Mandour InsnData *insn; 199*e2c5557cSMahmoud Mandour 200*e2c5557cSMahmoud Mandour g_mutex_lock(&mtx); 201*e2c5557cSMahmoud Mandour hwaddr = qemu_plugin_get_hwaddr(info, vaddr); 202*e2c5557cSMahmoud Mandour if (hwaddr && qemu_plugin_hwaddr_is_io(hwaddr)) { 203*e2c5557cSMahmoud Mandour g_mutex_unlock(&mtx); 204*e2c5557cSMahmoud Mandour return; 205*e2c5557cSMahmoud Mandour } 206*e2c5557cSMahmoud Mandour 207*e2c5557cSMahmoud Mandour effective_addr = hwaddr ? qemu_plugin_hwaddr_phys_addr(hwaddr) : vaddr; 208*e2c5557cSMahmoud Mandour 209*e2c5557cSMahmoud Mandour if (!access_cache(dcache, effective_addr)) { 210*e2c5557cSMahmoud Mandour insn = (InsnData *) userdata; 211*e2c5557cSMahmoud Mandour insn->dmisses++; 212*e2c5557cSMahmoud Mandour dmisses++; 213*e2c5557cSMahmoud Mandour } 214*e2c5557cSMahmoud Mandour dmem_accesses++; 215*e2c5557cSMahmoud Mandour g_mutex_unlock(&mtx); 216*e2c5557cSMahmoud Mandour } 217*e2c5557cSMahmoud Mandour 218*e2c5557cSMahmoud Mandour static void vcpu_insn_exec(unsigned int vcpu_index, void *userdata) 219*e2c5557cSMahmoud Mandour { 220*e2c5557cSMahmoud Mandour uint64_t insn_addr; 221*e2c5557cSMahmoud Mandour InsnData *insn; 222*e2c5557cSMahmoud Mandour 223*e2c5557cSMahmoud Mandour g_mutex_lock(&mtx); 224*e2c5557cSMahmoud Mandour insn_addr = ((InsnData *) userdata)->addr; 225*e2c5557cSMahmoud Mandour 226*e2c5557cSMahmoud Mandour if (!access_cache(icache, insn_addr)) { 227*e2c5557cSMahmoud Mandour insn = (InsnData *) userdata; 228*e2c5557cSMahmoud Mandour insn->imisses++; 229*e2c5557cSMahmoud Mandour imisses++; 230*e2c5557cSMahmoud Mandour } 231*e2c5557cSMahmoud Mandour imem_accesses++; 232*e2c5557cSMahmoud Mandour g_mutex_unlock(&mtx); 233*e2c5557cSMahmoud Mandour } 234*e2c5557cSMahmoud Mandour 235*e2c5557cSMahmoud Mandour static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) 236*e2c5557cSMahmoud Mandour { 237*e2c5557cSMahmoud Mandour size_t n_insns; 238*e2c5557cSMahmoud Mandour size_t i; 239*e2c5557cSMahmoud Mandour InsnData *data; 240*e2c5557cSMahmoud Mandour 241*e2c5557cSMahmoud Mandour n_insns = qemu_plugin_tb_n_insns(tb); 242*e2c5557cSMahmoud Mandour for (i = 0; i < n_insns; i++) { 243*e2c5557cSMahmoud Mandour struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i); 244*e2c5557cSMahmoud Mandour uint64_t effective_addr; 245*e2c5557cSMahmoud Mandour 246*e2c5557cSMahmoud Mandour if (sys) { 247*e2c5557cSMahmoud Mandour effective_addr = (uint64_t) qemu_plugin_insn_haddr(insn); 248*e2c5557cSMahmoud Mandour } else { 249*e2c5557cSMahmoud Mandour effective_addr = (uint64_t) qemu_plugin_insn_vaddr(insn); 250*e2c5557cSMahmoud Mandour } 251*e2c5557cSMahmoud Mandour 252*e2c5557cSMahmoud Mandour /* 253*e2c5557cSMahmoud Mandour * Instructions might get translated multiple times, we do not create 254*e2c5557cSMahmoud Mandour * new entries for those instructions. Instead, we fetch the same 255*e2c5557cSMahmoud Mandour * entry from the hash table and register it for the callback again. 256*e2c5557cSMahmoud Mandour */ 257*e2c5557cSMahmoud Mandour g_mutex_lock(&mtx); 258*e2c5557cSMahmoud Mandour data = g_hash_table_lookup(miss_ht, GUINT_TO_POINTER(effective_addr)); 259*e2c5557cSMahmoud Mandour if (data == NULL) { 260*e2c5557cSMahmoud Mandour data = g_new0(InsnData, 1); 261*e2c5557cSMahmoud Mandour data->disas_str = qemu_plugin_insn_disas(insn); 262*e2c5557cSMahmoud Mandour data->symbol = qemu_plugin_insn_symbol(insn); 263*e2c5557cSMahmoud Mandour data->addr = effective_addr; 264*e2c5557cSMahmoud Mandour g_hash_table_insert(miss_ht, GUINT_TO_POINTER(effective_addr), 265*e2c5557cSMahmoud Mandour (gpointer) data); 266*e2c5557cSMahmoud Mandour } 267*e2c5557cSMahmoud Mandour g_mutex_unlock(&mtx); 268*e2c5557cSMahmoud Mandour 269*e2c5557cSMahmoud Mandour qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem_access, 270*e2c5557cSMahmoud Mandour QEMU_PLUGIN_CB_NO_REGS, 271*e2c5557cSMahmoud Mandour rw, data); 272*e2c5557cSMahmoud Mandour 273*e2c5557cSMahmoud Mandour qemu_plugin_register_vcpu_insn_exec_cb(insn, vcpu_insn_exec, 274*e2c5557cSMahmoud Mandour QEMU_PLUGIN_CB_NO_REGS, data); 275*e2c5557cSMahmoud Mandour } 276*e2c5557cSMahmoud Mandour } 277*e2c5557cSMahmoud Mandour 278*e2c5557cSMahmoud Mandour static void insn_free(gpointer data) 279*e2c5557cSMahmoud Mandour { 280*e2c5557cSMahmoud Mandour InsnData *insn = (InsnData *) data; 281*e2c5557cSMahmoud Mandour g_free(insn->disas_str); 282*e2c5557cSMahmoud Mandour g_free(insn); 283*e2c5557cSMahmoud Mandour } 284*e2c5557cSMahmoud Mandour 285*e2c5557cSMahmoud Mandour static void cache_free(Cache *cache) 286*e2c5557cSMahmoud Mandour { 287*e2c5557cSMahmoud Mandour for (int i = 0; i < cache->num_sets; i++) { 288*e2c5557cSMahmoud Mandour g_free(cache->sets[i].blocks); 289*e2c5557cSMahmoud Mandour } 290*e2c5557cSMahmoud Mandour 291*e2c5557cSMahmoud Mandour g_free(cache->sets); 292*e2c5557cSMahmoud Mandour g_free(cache); 293*e2c5557cSMahmoud Mandour } 294*e2c5557cSMahmoud Mandour 295*e2c5557cSMahmoud Mandour static int dcmp(gconstpointer a, gconstpointer b) 296*e2c5557cSMahmoud Mandour { 297*e2c5557cSMahmoud Mandour InsnData *insn_a = (InsnData *) a; 298*e2c5557cSMahmoud Mandour InsnData *insn_b = (InsnData *) b; 299*e2c5557cSMahmoud Mandour 300*e2c5557cSMahmoud Mandour return insn_a->dmisses < insn_b->dmisses ? 1 : -1; 301*e2c5557cSMahmoud Mandour } 302*e2c5557cSMahmoud Mandour 303*e2c5557cSMahmoud Mandour static int icmp(gconstpointer a, gconstpointer b) 304*e2c5557cSMahmoud Mandour { 305*e2c5557cSMahmoud Mandour InsnData *insn_a = (InsnData *) a; 306*e2c5557cSMahmoud Mandour InsnData *insn_b = (InsnData *) b; 307*e2c5557cSMahmoud Mandour 308*e2c5557cSMahmoud Mandour return insn_a->imisses < insn_b->imisses ? 1 : -1; 309*e2c5557cSMahmoud Mandour } 310*e2c5557cSMahmoud Mandour 311*e2c5557cSMahmoud Mandour static void log_stats() 312*e2c5557cSMahmoud Mandour { 313*e2c5557cSMahmoud Mandour g_autoptr(GString) rep = g_string_new(""); 314*e2c5557cSMahmoud Mandour g_string_append_printf(rep, 315*e2c5557cSMahmoud Mandour "Data accesses: %lu, Misses: %lu\nMiss rate: %lf%%\n\n", 316*e2c5557cSMahmoud Mandour dmem_accesses, 317*e2c5557cSMahmoud Mandour dmisses, 318*e2c5557cSMahmoud Mandour ((double) dmisses / (double) dmem_accesses) * 100.0); 319*e2c5557cSMahmoud Mandour 320*e2c5557cSMahmoud Mandour g_string_append_printf(rep, 321*e2c5557cSMahmoud Mandour "Instruction accesses: %lu, Misses: %lu\nMiss rate: %lf%%\n\n", 322*e2c5557cSMahmoud Mandour imem_accesses, 323*e2c5557cSMahmoud Mandour imisses, 324*e2c5557cSMahmoud Mandour ((double) imisses / (double) imem_accesses) * 100.0); 325*e2c5557cSMahmoud Mandour 326*e2c5557cSMahmoud Mandour qemu_plugin_outs(rep->str); 327*e2c5557cSMahmoud Mandour } 328*e2c5557cSMahmoud Mandour 329*e2c5557cSMahmoud Mandour static void log_top_insns() 330*e2c5557cSMahmoud Mandour { 331*e2c5557cSMahmoud Mandour int i; 332*e2c5557cSMahmoud Mandour GList *curr, *miss_insns; 333*e2c5557cSMahmoud Mandour InsnData *insn; 334*e2c5557cSMahmoud Mandour 335*e2c5557cSMahmoud Mandour miss_insns = g_hash_table_get_values(miss_ht); 336*e2c5557cSMahmoud Mandour miss_insns = g_list_sort(miss_insns, dcmp); 337*e2c5557cSMahmoud Mandour g_autoptr(GString) rep = g_string_new(""); 338*e2c5557cSMahmoud Mandour g_string_append_printf(rep, "%s", "address, data misses, instruction\n"); 339*e2c5557cSMahmoud Mandour 340*e2c5557cSMahmoud Mandour for (curr = miss_insns, i = 0; curr && i < limit; i++, curr = curr->next) { 341*e2c5557cSMahmoud Mandour insn = (InsnData *) curr->data; 342*e2c5557cSMahmoud Mandour g_string_append_printf(rep, "0x%" PRIx64, insn->addr); 343*e2c5557cSMahmoud Mandour if (insn->symbol) { 344*e2c5557cSMahmoud Mandour g_string_append_printf(rep, " (%s)", insn->symbol); 345*e2c5557cSMahmoud Mandour } 346*e2c5557cSMahmoud Mandour g_string_append_printf(rep, ", %ld, %s\n", insn->dmisses, 347*e2c5557cSMahmoud Mandour insn->disas_str); 348*e2c5557cSMahmoud Mandour } 349*e2c5557cSMahmoud Mandour 350*e2c5557cSMahmoud Mandour miss_insns = g_list_sort(miss_insns, icmp); 351*e2c5557cSMahmoud Mandour g_string_append_printf(rep, "%s", "\naddress, fetch misses, instruction\n"); 352*e2c5557cSMahmoud Mandour 353*e2c5557cSMahmoud Mandour for (curr = miss_insns, i = 0; curr && i < limit; i++, curr = curr->next) { 354*e2c5557cSMahmoud Mandour insn = (InsnData *) curr->data; 355*e2c5557cSMahmoud Mandour g_string_append_printf(rep, "0x%" PRIx64, insn->addr); 356*e2c5557cSMahmoud Mandour if (insn->symbol) { 357*e2c5557cSMahmoud Mandour g_string_append_printf(rep, " (%s)", insn->symbol); 358*e2c5557cSMahmoud Mandour } 359*e2c5557cSMahmoud Mandour g_string_append_printf(rep, ", %ld, %s\n", insn->imisses, 360*e2c5557cSMahmoud Mandour insn->disas_str); 361*e2c5557cSMahmoud Mandour } 362*e2c5557cSMahmoud Mandour 363*e2c5557cSMahmoud Mandour qemu_plugin_outs(rep->str); 364*e2c5557cSMahmoud Mandour g_list_free(miss_insns); 365*e2c5557cSMahmoud Mandour } 366*e2c5557cSMahmoud Mandour 367*e2c5557cSMahmoud Mandour static void plugin_exit(qemu_plugin_id_t id, void *p) 368*e2c5557cSMahmoud Mandour { 369*e2c5557cSMahmoud Mandour log_stats(); 370*e2c5557cSMahmoud Mandour log_top_insns(); 371*e2c5557cSMahmoud Mandour 372*e2c5557cSMahmoud Mandour cache_free(dcache); 373*e2c5557cSMahmoud Mandour cache_free(icache); 374*e2c5557cSMahmoud Mandour 375*e2c5557cSMahmoud Mandour g_hash_table_destroy(miss_ht); 376*e2c5557cSMahmoud Mandour } 377*e2c5557cSMahmoud Mandour 378*e2c5557cSMahmoud Mandour QEMU_PLUGIN_EXPORT 379*e2c5557cSMahmoud Mandour int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, 380*e2c5557cSMahmoud Mandour int argc, char **argv) 381*e2c5557cSMahmoud Mandour { 382*e2c5557cSMahmoud Mandour int i; 383*e2c5557cSMahmoud Mandour int iassoc, iblksize, icachesize; 384*e2c5557cSMahmoud Mandour int dassoc, dblksize, dcachesize; 385*e2c5557cSMahmoud Mandour 386*e2c5557cSMahmoud Mandour limit = 32; 387*e2c5557cSMahmoud Mandour sys = info->system_emulation; 388*e2c5557cSMahmoud Mandour 389*e2c5557cSMahmoud Mandour dassoc = 8; 390*e2c5557cSMahmoud Mandour dblksize = 64; 391*e2c5557cSMahmoud Mandour dcachesize = dblksize * dassoc * 32; 392*e2c5557cSMahmoud Mandour 393*e2c5557cSMahmoud Mandour iassoc = 8; 394*e2c5557cSMahmoud Mandour iblksize = 64; 395*e2c5557cSMahmoud Mandour icachesize = iblksize * iassoc * 32; 396*e2c5557cSMahmoud Mandour 397*e2c5557cSMahmoud Mandour 398*e2c5557cSMahmoud Mandour for (i = 0; i < argc; i++) { 399*e2c5557cSMahmoud Mandour char *opt = argv[i]; 400*e2c5557cSMahmoud Mandour if (g_str_has_prefix(opt, "limit=")) { 401*e2c5557cSMahmoud Mandour limit = g_ascii_strtoll(opt + 6, NULL, 10); 402*e2c5557cSMahmoud Mandour } else { 403*e2c5557cSMahmoud Mandour fprintf(stderr, "option parsing failed: %s\n", opt); 404*e2c5557cSMahmoud Mandour return -1; 405*e2c5557cSMahmoud Mandour } 406*e2c5557cSMahmoud Mandour } 407*e2c5557cSMahmoud Mandour 408*e2c5557cSMahmoud Mandour dcache = cache_init(dblksize, dassoc, dcachesize); 409*e2c5557cSMahmoud Mandour icache = cache_init(iblksize, iassoc, icachesize); 410*e2c5557cSMahmoud Mandour 411*e2c5557cSMahmoud Mandour rng = g_rand_new(); 412*e2c5557cSMahmoud Mandour 413*e2c5557cSMahmoud Mandour qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); 414*e2c5557cSMahmoud Mandour qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); 415*e2c5557cSMahmoud Mandour 416*e2c5557cSMahmoud Mandour miss_ht = g_hash_table_new_full(NULL, g_direct_equal, NULL, insn_free); 417*e2c5557cSMahmoud Mandour 418*e2c5557cSMahmoud Mandour return 0; 419*e2c5557cSMahmoud Mandour } 420