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