From: Chang Bae Date: Wed, 20 Feb 2013 02:08:39 +0000 (-0600) Subject: PMU Host Interface and initial implementation for Linux and AMD/Intel X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=17556749e79560e7254e5f40155926ce5cce5cab;p=palacios.releases.git PMU Host Interface and initial implementation for Linux and AMD/Intel --- diff --git a/linux_module/Makefile b/linux_module/Makefile index 2236f81..3b8f699 100644 --- a/linux_module/Makefile +++ b/linux_module/Makefile @@ -33,6 +33,8 @@ v3vee-$(V3_CONFIG_HOST_DEVICE) += iface-host-dev.o v3vee-$(V3_CONFIG_GRAPHICS_CONSOLE) += iface-graphics-console.o v3vee-$(V3_CONFIG_EXT_MACH_CHECK) += mcheck.o +v3vee-$(V3_CONFIG_HOST_PMU) += iface-pmu.o + v3vee-$(V3_CONFIG_VNET) += palacios-vnet.o \ palacios-vnet-ctrl.o \ palacios-vnet-brg.o diff --git a/linux_module/iface-pmu-amd.h b/linux_module/iface-pmu-amd.h new file mode 100644 index 0000000..c348c9c --- /dev/null +++ b/linux_module/iface-pmu-amd.h @@ -0,0 +1,93 @@ +// Utility functions for AMD + +/* + * defines + */ + +/* + * should be changed + * + * + */ + +#define AMD_NUM_PMU_COUNTERS 4 +#define AMD_NUM_PMU_CONTROLS 4 + + +/* + * MSR OFFSETS FOR PMU RELATED: + */ + +/* + * MSR_K7_EVNTSEL0-3 is in msr-index.h + * + * MSR_K7_PERFCTR0-3 is also in msr-index.h + */ + +/* + * bit info according to AMD manual + performance monitoring counters: core performance event-select registers + * + */ +#define AMD_USR_BIT 16 +#define AMD_OS_BIT 17 +#define AMD_EDGE_BIT 18 +#define AMD_INT_BIT 20 +#define AMD_EN_BIT 22 +#define AMD_INV_BIT 23 +#define AMD_CMASK_BIT 24 +#define AMD_UMASK_BIT 8 +#define AMD_EVENT_BIT 0 + +/* + * SOME MACROS + */ + +#define AMD_CTR_READ(msrs, c) do {rdmsrl((MSR_K7_PERFCTR0 + (c)), (msrs).q);} while (0) +#define AMD_CTR_WRITE(msrs, c) do {wrmsrl((MSR_K7_PERFCTR0 + (c)), (msrs).q);} while (0) + +#define AMD_CTRL_READ(msrs, c) do {rdmsrl((MSR_K7_EVNTSEL0 + (c)), (msrs).q);} while (0) +#define AMD_CTRL_WRITE(msrs, c) \ +({ \ + (msrs).q |= 0x1<<21; \ + wrmsrl((MSR_K7_EVNTSEL0 + (c)), (msrs).q); \ +}) + +// given even and mask, make it to track it on all ring levels +#define AMD_CTRL_START(event, mask, i) \ +({ \ + uint64_t tmp = 0x0; \ + tmp |= (mask)< +#include +#include +#include + +#include +#include +#include + +#include "vm.h" +#include "palacios.h" +#include "iface-pmu-intel.h" +#include "iface-pmu-amd.h" +#include "util-queue.h" +#include "linux-exts.h" + + +// Number of inits/deinits we have seen (inc on init, dec on deinit) +// This is per CPU - init/deinit mean init/deinit PMU +// tracking ON THE CURRENT CORE +static DEFINE_PER_CPU(u32, pmu_refcount) = 0; + + +/* + * some macros may be commonly used + */ +#define MSR_READ(msrs, c) do {rdmsrl((c), (msrs).q);} while (0) +#define MSR_WRITE(msrs, c) do {wrmsrl((c), (msrs).q);} while (0) +#define SET_BIT(val, i) ((val) |= (1 << i)) +#define CLEAR_BIT(val, u, i) ((val) &= ~((u&1) << i)) +#define SET_BYTE(val, u, i) ((val) |= ((u&255) << i)) +#define CHECK_BIT(val, i) ((val) & (1U << i)) + + +static inline void cpuid_string(u32 id, u32 dest[4]) { + asm volatile("cpuid" + :"=a"(dest),"=b"(*(dest+1)),"=c"(*(dest+2)),"=d"(*(dest+3)) + :"a"(id)); +} + + +static int get_cpu_vendor(char name[13]) +{ + u32 dest[4]; + u32 maxid; + + cpuid_string(0,dest); + maxid=dest[0]; + ((u32*)name)[0]=dest[1]; + ((u32*)name)[1]=dest[3]; + ((u32*)name)[2]=dest[2]; + name[12]=0; + + return maxid; +} + +static int is_intel(void) +{ + char name[13]; + get_cpu_vendor(name); + return !strcmp(name,"GenuineIntel"); +} + +static int is_amd(void) +{ + char name[13]; + get_cpu_vendor(name); + return !strcmp(name,"AuthenticAMD"); +} + + + +/* + * AMD and Intel implementations are distinguished by prefix: INTEL or AMD + */ + +/* + * name: *_get_slot + * description: check available slots in pmu + * return: -1 if none, else returns index: 0 ... 3 + */ + +static int intel_get_slot(void) { + + int i, slot; + struct msr control; + + slot = -1; + control.q = 0x0; + + for (i=0; i>INTEL_EVENT_BIT) & 0xff) == event) && + (((control.l>>INTEL_UMASK_BIT) & 0xff) == mask)) { + return i; + } + } + + return -1; +} + + +/* + * following implementations : init, deinit, start_tracking, stop_track and get_value + * specifically fit into the pmu interface + */ + +static uint64_t intel_get_value(v3_pmon_ctr_t ctr) { + /* + * local variables + */ + int ctr_idx; + struct msr count; + + count.q = 0x0; + + switch(ctr) { + case V3_PMON_CLOCK_COUNT: + INTEL_FIXED_CTR_READ(count, INTEL_IDX_CLK_IN_FPMU); + break; + case V3_PMON_RETIRED_INST_COUNT: + INTEL_FIXED_CTR_READ(count, INTEL_IDX_INST_IN_FPMU); + break; + case V3_PMON_MEM_LOAD_COUNT: + if((ctr_idx = intel_find_idx(INTEL_MEM_INST_RETIRED, INTEL_LOADS)) >= 0) { + INTEL_CTR_READ(count, ctr_idx); + } else { + goto INTEL_READ_FAILED; + } + break; + case V3_PMON_MEM_STORE_COUNT: + if((ctr_idx = intel_find_idx(INTEL_MEM_INST_RETIRED, INTEL_STORES)) >= 0) { + INTEL_CTR_READ(count, ctr_idx); + } else { + goto INTEL_READ_FAILED; + } + break; + case V3_PMON_CACHE_MISS_COUNT: + if((ctr_idx = intel_find_idx(INTEL_MEM_LOAD_RETIRED, INTEL_L3_MISS)) >= 0) { + INTEL_CTR_READ(count, ctr_idx); + } else { + goto INTEL_READ_FAILED; + } + break; + case V3_PMON_TLB_MISS_COUNT: + if((ctr_idx = intel_find_idx(INTEL_MEM_LOAD_RETIRED, INTEL_DTLB_MISS)) >= 0) { + INTEL_CTR_READ(count, ctr_idx); + } else { + goto INTEL_READ_FAILED; + } + break; + } + + return (uint64_t)count.q; + + INTEL_READ_FAILED: + return 0; +} + + +static int intel_start_tracking(v3_pmon_ctr_t ctr) { + /* + * local variables + */ + int ctr_idx; + struct msr msrs; + + /* + * check if available slot in PMU, except for fixed counters (Intel specific) + */ + + switch(ctr) { + case V3_PMON_CLOCK_COUNT: + INTEL_FIXED_CTRL_READ(msrs); + msrs.l |= 0x3<<8; + INTEL_FIXED_CTRL_WRITE(msrs); + break; + case V3_PMON_RETIRED_INST_COUNT: + INTEL_FIXED_CTRL_READ(msrs); + msrs.l |= 0x3; + INTEL_FIXED_CTRL_WRITE(msrs); + break; + case V3_PMON_MEM_LOAD_COUNT: + if((ctr_idx = intel_get_slot()) >= 0) { + INTEL_CTRL_START(INTEL_MEM_INST_RETIRED, INTEL_LOADS, ctr_idx); + } else { + goto INTEL_START_FAILED; + } + break; + case V3_PMON_MEM_STORE_COUNT: + if((ctr_idx = intel_get_slot()) >= 0) { + INTEL_CTRL_START(INTEL_MEM_INST_RETIRED, INTEL_STORES, ctr_idx); + } else { + goto INTEL_START_FAILED; + } + break; + case V3_PMON_CACHE_MISS_COUNT: + if((ctr_idx = intel_get_slot()) >= 0) { + INTEL_CTRL_START(INTEL_MEM_LOAD_RETIRED, INTEL_L3_MISS, ctr_idx); + } else { + goto INTEL_START_FAILED; + } + break; + case V3_PMON_TLB_MISS_COUNT: + if((ctr_idx = intel_get_slot()) >= 0) { + INTEL_CTRL_START(INTEL_MEM_LOAD_RETIRED, INTEL_DTLB_MISS, ctr_idx); + } else { + goto INTEL_START_FAILED; + } + break; + } + + return 0; + + INTEL_START_FAILED: + ERROR("ERROR: no more slot remains for pmon events\n"); + return -1; +} + +/* + * descript: disabling pmu event counts + */ + +static int intel_stop_tracking(v3_pmon_ctr_t ctr) { + /* + * local variables + */ + int ctr_idx = -1; + struct msr msrs; + + /* + * check if available slot in PMU, except + */ + + switch(ctr) { + case V3_PMON_CLOCK_COUNT: + INTEL_FIXED_CTRL_READ(msrs); + msrs.l &= ~(0xf<<8); + INTEL_FIXED_CTRL_WRITE(msrs); + break; + case V3_PMON_RETIRED_INST_COUNT: + INTEL_FIXED_CTRL_READ(msrs); + msrs.l &= ~(0xf); + INTEL_FIXED_CTRL_WRITE(msrs); + break; + case V3_PMON_MEM_LOAD_COUNT: + if((ctr_idx = intel_find_idx(INTEL_MEM_INST_RETIRED, INTEL_LOADS)) >= 0) { + INTEL_CTRL_STOP(ctr_idx); + } else { + goto INTEL_STOP_FAILED; + } + break; + case V3_PMON_MEM_STORE_COUNT: + if((ctr_idx = intel_find_idx(INTEL_MEM_INST_RETIRED, INTEL_STORES)) >= 0) { + INTEL_CTRL_STOP(ctr_idx); + } else { + goto INTEL_STOP_FAILED; + } + break; + case V3_PMON_CACHE_MISS_COUNT: + if((ctr_idx = intel_find_idx(INTEL_MEM_LOAD_RETIRED, INTEL_L3_MISS)) >= 0) { + INTEL_CTRL_STOP(ctr_idx); + } else { + goto INTEL_STOP_FAILED; + } + break; + case V3_PMON_TLB_MISS_COUNT: + if((ctr_idx = intel_find_idx(INTEL_MEM_LOAD_RETIRED, INTEL_DTLB_MISS)) >= 0) { + INTEL_CTRL_STOP(ctr_idx); + } else { + goto INTEL_STOP_FAILED; + } + break; + } + + return 0; + + INTEL_STOP_FAILED: + ERROR("ERROR: no more slot remains for pmon events\n"); + return -1; +} + +static void intel_pmu_init(void) { + int i; + struct msr control; + + if ((get_cpu_var(pmu_refcount)++) > 1) { + put_cpu_var(pmu_refcount); + // only the first init clears the pmu + return; + } + put_cpu_var(pmu_refcount); + + + control.q=0x0; + + /* + * per Intel PMU architecture, + * there are two class of counters + * fixed ones (3 counters) and programmable ones (4 counters) + * events for fixed coutners are determined, so enabling or not is the option + * whereas, programmable ones are litterally programmable. + */ + + /* + * enable fixed counters in global + */ + MSR_READ(control, INTEL_IA32_PERF_GLOBAL_CTRL); + control.q |= 0x70000000f; // enable fix counters (3 for the intel model) + MSR_WRITE(control, INTEL_IA32_PERF_GLOBAL_CTRL); + + /* + * disable in fixed counters control + */ + + INTEL_FIXED_CTRL_WRITE(control); + + /* + * clean up programmable counter control + */ + for (i=0; i>AMD_EVENT_BIT) & 0xff) == event) && + (((control.l>>AMD_UMASK_BIT) & 0xff) == mask)) { + return i; + } + } + + return -1; +} + + +static uint64_t amd_get_value(v3_pmon_ctr_t ctr) { + int ctr_idx; + struct msr count; + + count.q = 0x0; + + switch(ctr) { + case V3_PMON_CLOCK_COUNT: + if((ctr_idx = amd_find_idx(AMD_CLK_NOT_HALTED, 0x0)) >= 0) { + AMD_CTR_READ(count, ctr_idx); + } else { + goto AMD_READ_FAILED; + } + break; + case V3_PMON_RETIRED_INST_COUNT: + if((ctr_idx = amd_find_idx(AMD_RETIRED_INSTRUCTIONS, 0x0)) >= 0) { + AMD_CTR_READ(count, ctr_idx); + } else { + goto AMD_READ_FAILED; + } + break; + case V3_PMON_MEM_LOAD_COUNT: + if((ctr_idx = amd_find_idx(AMD_PREFETCH_INST_DISPATCHED, AMD_LOAD)) >= 0) { + AMD_CTR_READ(count, ctr_idx); + } else { + goto AMD_READ_FAILED; + } + break; + case V3_PMON_MEM_STORE_COUNT: + if((ctr_idx = amd_find_idx(AMD_PREFETCH_INST_DISPATCHED, AMD_STORE)) >= 0) { + AMD_CTR_READ(count, ctr_idx); + } else { + goto AMD_READ_FAILED; + } + break; + case V3_PMON_CACHE_MISS_COUNT: + if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_MISSES, 0x0)) >= 0) { + AMD_CTR_READ(count, ctr_idx); + } else { + goto AMD_READ_FAILED; + } + break; + case V3_PMON_TLB_MISS_COUNT: + if((ctr_idx = amd_find_idx(AMD_L1_DTLB_AND_L2_DTLB_MISS, 0x0)) >= 0) { + AMD_CTR_READ(count, ctr_idx); + } else { + goto AMD_READ_FAILED; + } + break; + } + + return (uint64_t)count.q; + + AMD_READ_FAILED: + return 0; +} + +static int amd_start_tracking(v3_pmon_ctr_t ctr) { + + int ctr_idx; + + switch(ctr) { + case V3_PMON_CLOCK_COUNT: + if((ctr_idx = amd_get_slot()) >= 0) { + AMD_CTRL_START(AMD_CLK_NOT_HALTED, 0x0, ctr_idx); + } else { + goto AMD_START_FAILED; + } + break; + case V3_PMON_RETIRED_INST_COUNT: + if((ctr_idx = amd_get_slot()) >= 0) { + AMD_CTRL_START(AMD_RETIRED_INSTRUCTIONS, 0x0, ctr_idx); + } else { + goto AMD_START_FAILED; + } + break; + case V3_PMON_MEM_LOAD_COUNT: + if((ctr_idx = amd_get_slot()) >= 0) { + AMD_CTRL_START(AMD_PREFETCH_INST_DISPATCHED, AMD_LOAD, ctr_idx); + } else { + goto AMD_START_FAILED; + } + break; + case V3_PMON_MEM_STORE_COUNT: + if((ctr_idx = amd_get_slot()) >= 0) { + AMD_CTRL_START(AMD_PREFETCH_INST_DISPATCHED, AMD_STORE, ctr_idx); + } else { + goto AMD_START_FAILED; + } + break; + case V3_PMON_CACHE_MISS_COUNT: + if((ctr_idx = amd_get_slot()) >= 0) { + AMD_CTRL_START(AMD_DATA_CACHE_MISSES, 0x0, ctr_idx); + } else { + goto AMD_START_FAILED; + } + break; + case V3_PMON_TLB_MISS_COUNT: + if((ctr_idx = amd_get_slot()) >= 0) { + AMD_CTRL_START(AMD_L1_DTLB_AND_L2_DTLB_MISS, 0x0, ctr_idx); + } else { + goto AMD_START_FAILED; + } + break; + } + + return 0; + + AMD_START_FAILED: + ERROR("ERROR: no more slot remains for pmon events\n"); + return -1; +} + + +static int amd_stop_tracking(v3_pmon_ctr_t ctr) { + + int ctr_idx = -1; + + + switch(ctr) { + case V3_PMON_CLOCK_COUNT: + if((ctr_idx = amd_find_idx(AMD_CLK_NOT_HALTED, 0x0)) >= 0) { + AMD_CTRL_STOP(ctr_idx); + } else { + goto AMD_STOP_FAILED; + } + break; + case V3_PMON_RETIRED_INST_COUNT: + if((ctr_idx = amd_find_idx(AMD_RETIRED_INSTRUCTIONS, 0x0)) >= 0) { + AMD_CTRL_STOP(ctr_idx); + } else { + goto AMD_STOP_FAILED; + } + break; + case V3_PMON_MEM_LOAD_COUNT: + if((ctr_idx = amd_find_idx(AMD_PREFETCH_INST_DISPATCHED, AMD_LOAD)) >= 0) { + AMD_CTRL_STOP(ctr_idx); + } else { + goto AMD_STOP_FAILED; + } + break; + case V3_PMON_MEM_STORE_COUNT: + if((ctr_idx = amd_find_idx(AMD_PREFETCH_INST_DISPATCHED, AMD_STORE)) >= 0) { + AMD_CTRL_STOP(ctr_idx); + } else { + goto AMD_STOP_FAILED; + } + break; + case V3_PMON_CACHE_MISS_COUNT: + if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_MISSES, 0x0)) >= 0) { + AMD_CTRL_STOP(ctr_idx); + } else { + goto AMD_STOP_FAILED; + } + break; + case V3_PMON_TLB_MISS_COUNT: + if((ctr_idx = amd_find_idx(AMD_L1_DTLB_AND_L2_DTLB_MISS, 0x0)) >= 0) { + AMD_CTRL_STOP(ctr_idx); + } else { + goto AMD_STOP_FAILED; + } + break; + } + + return 0; + + AMD_STOP_FAILED: + ERROR("ERROR: no more slot remains for pmon events\n"); + return -1; +} + + +static void amd_pmu_init(void) { + + int i; + struct msr control; + + + if ((get_cpu_var(pmu_refcount)++) > 1) { + put_cpu_var(pmu_refcount); + // only the first init clears the pmu + return; + } + put_cpu_var(pmu_refcount); + + + + // initialize variables + control.q=0x0; + + /* + * clean up programmable counter control + */ + for (i=0; i + * All rights reserved. + * + * Author: Chang S. Bae + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + +#ifndef __VMM_PMU +#define __VMM_PMU + +#include + +/* + * defines + */ + +/* + * The following is the set of performance + * counters available in Palacios. The implementation + * of the interface translates these names to + * the underlying counters needed on the specific platform + */ +typedef enum { + V3_PMON_RETIRED_INST_COUNT=0, + V3_PMON_CLOCK_COUNT, + V3_PMON_MEM_LOAD_COUNT, + V3_PMON_MEM_STORE_COUNT, + V3_PMON_CACHE_MISS_COUNT, + V3_PMON_TLB_MISS_COUNT + + //V3_PMON_TLB_INVALIDATION_COUNT + /* you can add more here, but then need to implement them + in the interface */ + +} v3_pmon_ctr_t; + + +struct v3_pmu_iface { + /* init/deinit pmu data on the core on which it is called */ + + + void (*init)(void); + void (*deinit)(void); + + // Request tracking of a counter, returns -1 if it is not possible + int (*start_tracking)(v3_pmon_ctr_t ctr); + // Get the counter value, provided it being tracked + uint64_t (*get_value)(v3_pmon_ctr_t ctr); + // Stop tracking a counter + int (*stop_tracking)(v3_pmon_ctr_t ctr); + +}; + + +/* + * function prototypes + */ + +extern void V3_Init_PMU(struct v3_pmu_iface * palacios_pmu); + +#ifdef __V3VEE__ + +/* This is a PER PHYSICAL CORE init/deinit */ +void v3_pmu_init(void); + +// Call these after an init +int v3_pmu_start_tracking(v3_pmon_ctr_t ctr); +int v3_pmu_stop_tracking(v3_pmon_ctr_t ctr); +uint64_t v3_pmu_get_value(v3_pmon_ctr_t ctr); + +// Call this after you are done with the PMU +void v3_pmu_deinit(void); + + + +#endif + +#endif diff --git a/palacios/src/interfaces/Kconfig b/palacios/src/interfaces/Kconfig index 5f86790..7535376 100644 --- a/palacios/src/interfaces/Kconfig +++ b/palacios/src/interfaces/Kconfig @@ -1,7 +1,7 @@ menu "Host Interfaces" config FILE - bool "Host Support for file operations" + bool "Host support for file operations" default n help Select this if your host OS supports file operatoins and you want Palacios to be able to use them. @@ -14,19 +14,21 @@ config KEYED_STREAMS Palacios Checkpoint/Restore and Migration depends on this feature config STREAM - bool "Stream support" + bool "Host support for streams" default n - + help + Select this if your host OS supports streams + Palacios serial ports and similar functions depend on this feature config CONSOLE - bool "Host Support for VM text-mode console" + bool "Host support for VM text-mode console" default n help Select this if you want to forward a guest console interface to some host OS service This is for a TEXT MODE console. Select the framebuffer console for graphics and text config GRAPHICS_CONSOLE - bool "Host Support for VM graphics and text-mode console based on a frame buffer" + bool "Host support for VM graphics and text-mode console based on a frame buffer" default n help Select this if you want to forward a guest graphics-mode (and text-mode) console @@ -51,7 +53,7 @@ config PACKET config HOST_PCI - bool "Host PCI Support" + bool "Host PCI support" depends on EXPERIMENTAL default y help @@ -73,4 +75,10 @@ config HOST_HYPERCALL to register host-based implementations of hypercalls, for example, implemented in Linux kernel modules +config HOST_PMU + bool "Host PMU support" + default n + help + Select this if you would like to access performance + counters (the PMU) within Palacios endmenu diff --git a/palacios/src/interfaces/Makefile b/palacios/src/interfaces/Makefile index c04193f..d0c7aa2 100644 --- a/palacios/src/interfaces/Makefile +++ b/palacios/src/interfaces/Makefile @@ -8,6 +8,7 @@ obj-$(V3_CONFIG_KEYED_STREAMS) += vmm_keyed_stream.o obj-$(V3_CONFIG_HOST_DEVICE) += vmm_host_dev.o obj-$(V3_CONFIG_HOST_HYPERCALL) += vmm_host_hypercall.o obj-$(V3_CONFIG_HOST_PCI) += host_pci.o +obj-$(V3_CONFIG_HOST_PMU) += vmm_pmu.o obj-y += null.o diff --git a/palacios/src/interfaces/vmm_pmu.c b/palacios/src/interfaces/vmm_pmu.c new file mode 100644 index 0000000..a9b2fe1 --- /dev/null +++ b/palacios/src/interfaces/vmm_pmu.c @@ -0,0 +1,102 @@ +/* + * This file is part of the Palacios Virtual Machine Monitor developed + * by the V3VEE Project with funding from the United States National + * Science Foundation and the Department of Energy. + * + * The V3VEE Project is a joint project between Northwestern University + * and the University of New Mexico. You can find out more at + * http://www.v3vee.org + * + * Copyright (c) 2013, The V3VEE Project + * All rights reserved. + * + * Author: Chang S. Bae + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + + +#include +#include +#include +#include +#include +#include + +struct v3_pmu_iface * palacios_pmu = 0; + +/* + * functions + */ + +/* + * description: init pmu through the interface on this core + */ + +void v3_pmu_init(void) { + + V3_ASSERT(VM_NONE, VCORE_NONE, palacios_pmu != NULL); + V3_ASSERT(VM_NONE, VCORE_NONE, palacios_pmu->init != NULL); + + palacios_pmu->init(); +} + +/* + * description: actually stop pmu running through the interface + * on this core + */ +void v3_pmu_deinit(void) { + + V3_ASSERT(VM_NONE, VCORE_NONE, palacios_pmu != NULL); + V3_ASSERT(VM_NONE, VCORE_NONE, palacios_pmu->deinit != NULL); + + palacios_pmu->deinit(); +} + +/* + * description: init pmu through the interface + */ + +int v3_pmu_start_tracking(v3_pmon_ctr_t ctr) { + + V3_ASSERT(VM_NONE, VCORE_NONE, palacios_pmu != NULL); + V3_ASSERT(VM_NONE, VCORE_NONE, palacios_pmu->start_tracking != NULL); + + return palacios_pmu->start_tracking(ctr); +} + +/* + * description: actually stop pmu running through the interface + */ +int v3_pmu_stop_tracking(v3_pmon_ctr_t ctr) { + + V3_ASSERT(VM_NONE, VCORE_NONE, palacios_pmu != NULL); + V3_ASSERT(VM_NONE, VCORE_NONE, palacios_pmu->stop_tracking != NULL); + + return palacios_pmu->stop_tracking(ctr); +} + +/* + * description: actually stop pmu running through the interface + */ +uint64_t v3_pmu_get_value(v3_pmon_ctr_t ctr) { + + V3_ASSERT(VM_NONE, VCORE_NONE, palacios_pmu != NULL); + V3_ASSERT(VM_NONE, VCORE_NONE, palacios_pmu->get_value != NULL); + + return palacios_pmu->get_value(ctr); +} + + +/* + * description: init whole interface to pmu + */ + +void V3_Init_PMU(struct v3_pmu_iface * pmu_iface) { + palacios_pmu = pmu_iface; + + return; +} + +