Jonathan Cameron <jonathan.came...@huawei.com> writes: > This allows an external program to act as a hotness tracker. > > Signed-off-by: Jonathan Cameron <jonathan.came...@huawei.com> > --- > contrib/plugins/cache.c | 75 +++++++++++++++++++++++++++++++++++++---- > 1 file changed, 68 insertions(+), 7 deletions(-) > > diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c > index 7baff86860..5af1e6559c 100644 > --- a/contrib/plugins/cache.c > +++ b/contrib/plugins/cache.c > @@ -7,10 +7,17 @@ > > #include <inttypes.h> > #include <stdio.h> > +#include <unistd.h> > #include <glib.h> > +#include <sys/socket.h> > +#include <arpa/inet.h> > > #include <qemu-plugin.h> > > +static int client_socket = -1; > +static uint64_t missfilterbase; > +static uint64_t missfiltersize; > + > #define STRTOLL(x) g_ascii_strtoll(x, NULL, 10) > > QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; > @@ -104,6 +111,7 @@ static Cache **l2_ucaches; > static GMutex *l1_dcache_locks; > static GMutex *l1_icache_locks; > static GMutex *l2_ucache_locks; > +static GMutex *socket_lock; > > static uint64_t l1_dmem_accesses; > static uint64_t l1_imem_accesses; > @@ -385,6 +393,21 @@ static bool access_cache(Cache *cache, uint64_t addr) > return false; > } > > +static void miss(uint64_t paddr) > +{ > + if (client_socket < 0) { > + return; > + } > + > + if (paddr < missfilterbase || paddr >= missfilterbase + missfiltersize) { > + return; > + } > + > + g_mutex_lock(socket_lock); > + send(client_socket, &paddr, sizeof(paddr), 0); > + g_mutex_unlock(socket_lock); > +} > + > static void vcpu_mem_access(unsigned int vcpu_index, qemu_plugin_meminfo_t > info, > uint64_t vaddr, void *userdata) > { > @@ -395,9 +418,6 @@ static void vcpu_mem_access(unsigned int vcpu_index, > qemu_plugin_meminfo_t info, > bool hit_in_l1; > > hwaddr = qemu_plugin_get_hwaddr(info, vaddr); > - if (hwaddr && qemu_plugin_hwaddr_is_io(hwaddr)) { > - return; > - } > > effective_addr = hwaddr ? qemu_plugin_hwaddr_phys_addr(hwaddr) : vaddr; > cache_idx = vcpu_index % cores; > @@ -412,7 +432,11 @@ static void vcpu_mem_access(unsigned int vcpu_index, > qemu_plugin_meminfo_t info, > l1_dcaches[cache_idx]->accesses++; > g_mutex_unlock(&l1_dcache_locks[cache_idx]); > > - if (hit_in_l1 || !use_l2) { > + if (hit_in_l1) { > + return; > + } > + if (!use_l2) { > + miss(effective_addr); > /* No need to access L2 */ > return; > } > @@ -422,6 +446,7 @@ static void vcpu_mem_access(unsigned int vcpu_index, > qemu_plugin_meminfo_t info, > insn = userdata; > __atomic_fetch_add(&insn->l2_misses, 1, __ATOMIC_SEQ_CST); > l2_ucaches[cache_idx]->misses++; > + miss(effective_addr); > } > l2_ucaches[cache_idx]->accesses++; > g_mutex_unlock(&l2_ucache_locks[cache_idx]); > @@ -447,8 +472,12 @@ static void vcpu_insn_exec(unsigned int vcpu_index, void > *userdata) > l1_icaches[cache_idx]->accesses++; > g_mutex_unlock(&l1_icache_locks[cache_idx]); > > - if (hit_in_l1 || !use_l2) { > - /* No need to access L2 */ > + if (hit_in_l1) { > + return; > + } > + > + if (!use_l2) { > + miss(insn_addr); > return; > } > > @@ -739,14 +768,16 @@ QEMU_PLUGIN_EXPORT > int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, > int argc, char **argv) > { > - int i; > + int i, port; > int l1_iassoc, l1_iblksize, l1_icachesize; > int l1_dassoc, l1_dblksize, l1_dcachesize; > int l2_assoc, l2_blksize, l2_cachesize; > + struct sockaddr_in server_addr; > > limit = 32; > sys = info->system_emulation; > > + port = -1; > l1_dassoc = 8; > l1_dblksize = 64; > l1_dcachesize = l1_dblksize * l1_dassoc * 32; > @@ -808,11 +839,39 @@ int qemu_plugin_install(qemu_plugin_id_t id, const > qemu_info_t *info, > fprintf(stderr, "invalid eviction policy: %s\n", opt); > return -1; > } > + } else if (g_strcmp0(tokens[0], "port") == 0) { > + port = STRTOLL(tokens[1]); > + } else if (g_strcmp0(tokens[0], "missfilterbase") == 0) { > + missfilterbase = STRTOLL(tokens[1]); > + } else if (g_strcmp0(tokens[0], "missfiltersize") == 0) { > + missfiltersize = STRTOLL(tokens[1]); > } else { > fprintf(stderr, "option parsing failed: %s\n", opt); > return -1; > } > } > + if (port >= -1) { > + uint64_t paddr = 42; /* hello, I'm a provider */ > + client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); > + if (client_socket < 0) { > + printf("failed to create a socket\n"); > + return -1; > + } > + printf("Cache miss reported on on %lx size %lx\n", > + missfilterbase, missfiltersize); > + memset((char *)&server_addr, 0, sizeof(server_addr)); > + server_addr.sin_family = AF_INET; > + server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); > + server_addr.sin_port = htons(port); > + > + if (connect(client_socket, (struct sockaddr *)&server_addr, > + sizeof(server_addr)) < 0) { > + close(client_socket); > + return -1; > + } > + /* Let it know we are a data provider */ > + send(client_socket, &paddr, sizeof(paddr), 0); > + }
No particular objections to the patch as is. I do wonder if it would be worth exposing a chardev pipe to plugins so we could take advantage of QEMU's flexible redirection handling. But not a blocker for this. > > policy_init(); > > @@ -840,6 +899,8 @@ int qemu_plugin_install(qemu_plugin_id_t id, const > qemu_info_t *info, > return -1; > } > > + socket_lock = g_new0(GMutex, 1); > + > l1_dcache_locks = g_new0(GMutex, cores); > l1_icache_locks = g_new0(GMutex, cores); > l2_ucache_locks = use_l2 ? g_new0(GMutex, cores) : NULL; -- Alex Bennée Virtualisation Tech Lead @ Linaro