diff --git a/apps/memory.c b/apps/memory.c index 2107c3a8..143980a8 100644 --- a/apps/memory.c +++ b/apps/memory.c @@ -333,62 +333,87 @@ int bench(void) // setup PMCs pmc_stop_all(); - pmc_config(0, PMC_EVT_PAGE_WALK_CLKS, PMC_EVTSEL_OS | PMC_EVTSEL_EN, 0, 0); - pmc_config(1, PMC_EVT_PAGE_WALK_COUNT, PMC_EVTSEL_OS | PMC_EVTSEL_EN, 0, 0); + pmc_gp_config(0, PMC_EVT_PAGE_WALK_CLKS, PMC_EVTSEL_OS | PMC_EVTSEL_EN, 0, 0); + pmc_gp_config(1, PMC_EVT_PAGE_WALK_COUNT, PMC_EVTSEL_OS | PMC_EVTSEL_EN, 0, 0); - // allocate space for results - uint64_t *data = kmalloc(ITERATIONS * sizeof(uint64_t)); - if (!data) - return -1; - - // clear caches - tlb_flush(); - flush_cache(); + size_t phyaddr = get_page(); + size_t viraddr; + size_t pages = 512*511; + size_t virbase = 2*KERNEL_SPACE; + kprintf("virbase %#llx KERNEL_SPACE %#llx\n", virbase, KERNEL_SPACE); + for (viraddr = virbase; viraddr < virbase+pages*PAGE_SIZE; viraddr += PAGE_SIZE) { + kprintf("map at %#llx\n", viraddr); + size_t ret = map_region(viraddr, phyaddr, 1, MAP_KERNEL_SPACE); + if (ret != viraddr) { + kprintf("map failed at %#llx\n", viraddr); + break; + } + } int i; for (i=0; i < ITERATIONS; i++) { - pmc_write(0, 0); - pmc_write(1, 0); + tlb_flush(); + pmc_reset_all(); pmc_start_all(); -#if 0 - int i = 100; - while (i--) { - tlb_flush(); - page_stats(0); + for (viraddr = virbase; viraddr < virbase+pages*PAGE_SIZE; viraddr += PAGE_SIZE) { + char * p = (char *) viraddr; + (*p)++; } -#else - //flush_cache(); - //tlb_flush(); - page_stats(0); -#endif pmc_stop_all(); - uint64_t clks = pmc_read(0); - uint64_t count = pmc_read(1); + uint64_t clks = pmc_gp_read(0); + uint64_t count = pmc_gp_read(1); - /*kprintf("Number of Page table walks: %lu\n", count); - kprintf("Page table walks clock cycles: %lu\n", clks); - kprintf("Cycles per table walk: %lu.%u\n", clks / count, (1000 * clks / count) % 1000 );*/ - - data[i] = 1000000 * clks / count; + kprintf("%llu\n", 1000000 * clks / count); } - // dump results - for (i=0; i INST_RETIRED.ANY @@ -89,6 +92,14 @@ #define PMC_EVT_PAGE_WALK_COUNT 0x010C // Number of page-walks executed #define PMC_EVT_PAGE_WALK_CLKS 0x020C // Duration of page-walks in core cycles +#define PMC_EVT_MEM_LOAD_RETIRED_L1D_MISS 0x01CB // Retired loads that miss the L1 data cache (precise event) +#define PMC_EVT_MEM_LOAD_RETIRED_L1D_LINE_MISS 0x02CB // L1 data cache line missed by retired loads (precise event) + +#define PMC_EVT_MEM_LOAD_RETIRED_L2_MISS 0x04CB // Retired loads that miss the L2 cache (precise event) +#define PMC_EVT_MEM_LOAD_RETIRED_L2_LINE_MISS 0x08CB // L2 cache line missed by retired loads (precise event) + +#define PMC_EVT_MEM_LOAD_RETIRED_DTLB_MISS 0x10CB // Retired loads that miss the DTLB (precise event) + struct pmc { uint8_t id; @@ -134,7 +145,17 @@ struct pmc_caps* pmc_init(); * - 0 on success * - else failure (invalid counter or flags) */ -int pmc_config(uint8_t i, uint16_t event, uint32_t flags, uint8_t umask, uint8_t cmask); +int pmc_gp_config(uint8_t i, uint16_t event, uint32_t flags, uint8_t umask, uint8_t cmask); + +/** @brief Setups and stops the fixed function PMCs + * + * @param i The counter number to configure (positive for gp PMCs, negative for ff PMCs) + * @param flags Flags for the MSR_PERF_FIXED_CTR_CTRL register + * @return + * - 0 on success + * - else failure (invalid counter or flags) + */ +int pmc_ff_config(uint8_t i, uint8_t flags); /** @brief Start a single general purpose PMC * @@ -143,7 +164,7 @@ int pmc_config(uint8_t i, uint16_t event, uint32_t flags, uint8_t umask, uint8_t * - 0 on success * - -EINVAL on invalid counter number */ -inline int pmc_start(uint8_t i); +inline int pmc_gp_start(uint8_t i); /** @brief Stop a single general purpose PMC * @@ -152,11 +173,28 @@ inline int pmc_start(uint8_t i); * - 0 on success * - -EINVAL on invalid counter number */ -inline int pmc_stop(uint8_t i); +inline int pmc_gp_stop(uint8_t i); + +/** @brief Start a single fixed function PMC + * + * @param i The counter number + * @return + * - 0 on success + * - -EINVAL on invalid counter number + */ +inline int pmc_ff_start(uint8_t i); + +/** @brief Stop a single fixed function PMC + * + * @param i The counter number + * @return + * - 0 on success + * - -EINVAL on invalid counter number + */ +inline int pmc_ff_stop(uint8_t i); /** @brief Start all PMCs at the same time * - * @param i The counter number * @return * - 0 on success * - -EINVAL on invalid counter number @@ -165,19 +203,33 @@ inline int pmc_start_all(); /** @brief Stop all PMCs at the same time * - * @param i The counter number * @return * - 0 on success * - -EINVAL on invalid counter number */ inline int pmc_stop_all(); +/** @brief Reset all PMCs to zero + * + * @return + * - 0 on success + * - -EINVAL on invalid counter number + */ +inline int pmc_reset_all(); + /** @brief Read a single general purpose PMC * * @param i The counter number * @return The counter value (see struct pmc_caps.gp_width) */ -inline uint64_t pmc_read(uint8_t i); +inline uint64_t pmc_gp_read(uint8_t i); + +/** @brief Read a single fixed function PMC + * + * @param i The counter number + * @return The counter value (see struct pmc_caps.gp_width) + */ +inline uint64_t pmc_ff_read(uint8_t i); /** @brief Write a single general purpose PMC value * @@ -188,6 +240,13 @@ inline uint64_t pmc_read(uint8_t i); * @param i The counter number * @param val The counter value (see struct pmc_caps.gp_width) */ -inline int pmc_write(uint8_t i, uint64_t val); +inline int pmc_gp_write(uint8_t i, uint64_t val); + +/** @brief Write a single fixed function PMC value + * + * @param i The counter number + * @param val The counter value (see struct pmc_caps.ff_width) + */ +inline int pmc_ff_write(uint8_t i, uint64_t val); #endif diff --git a/arch/x86/kernel/pmc.c b/arch/x86/kernel/pmc.c index a87280b4..6d891276 100644 --- a/arch/x86/kernel/pmc.c +++ b/arch/x86/kernel/pmc.c @@ -23,6 +23,8 @@ * @brief Simple interface to IA32 Performance Monitor Counters * * This implementation is in parts specific for Intel Core 2 Duo Processors! + * General purpose PMCS => pmc_gp_*() + * Fixed function PMCs => pmc_ff_*() */ #include @@ -45,8 +47,8 @@ struct pmc_caps* pmc_init() caps.arch_events = (b >> 0) & 0x3f; // check if IA32_PERF_CAPABILITIES MSR is available - cpuid(0x01, &a, &b, &c, &d); if (caps.version >= 2) { + cpuid(0x01, &a, &b, &c, &d); if (c & (1 << 15 /* PDCM */)) caps.msr = rdmsr(IA32_PERF_CAPABILITIES); } @@ -55,7 +57,7 @@ struct pmc_caps* pmc_init() return ∩︀ } -int pmc_config(uint8_t i, uint16_t event, uint32_t flags, uint8_t umask, uint8_t cmask) +int pmc_gp_config(uint8_t i, uint16_t event, uint32_t flags, uint8_t umask, uint8_t cmask) { if (BUILTIN_EXPECT(i > caps.gp_count, 0)) return -EINVAL; @@ -64,12 +66,28 @@ int pmc_config(uint8_t i, uint16_t event, uint32_t flags, uint8_t umask, uint8_t evtsel |= (cmask << PMC_EVTSEL_CMASK) | (umask << PMC_EVTSEL_UMASK); wrmsr(IA32_PERFEVTSEL(i), evtsel); - wrmsr(IA32_PMC(i), 0); + wrmsr(IA32_PMC(i), 0); // reset counter return 0; } -inline int pmc_start(uint8_t i) +int pmc_ff_config(uint8_t i, uint8_t flags) +{ + if (BUILTIN_EXPECT(i > caps.ff_count, 0)) + return -EINVAL; + + + uint64_t ctrl = rdmsr(MSR_PERF_FIXED_CTR_CTRL); + + ctrl &= ~(0x0f << i*4); // clear flags + ctrl |= (flags & 0xf) << i*4; + + wrmsr(MSR_PERF_FIXED_CTR_CTRL, ctrl); + + return 0; +} + +inline int pmc_gp_start(uint8_t i) { if (BUILTIN_EXPECT(i > caps.gp_count, 0)) return -EINVAL; @@ -79,7 +97,7 @@ inline int pmc_start(uint8_t i) return 0; } -inline int pmc_stop(uint8_t i) +inline int pmc_gp_stop(uint8_t i) { if (BUILTIN_EXPECT(i > caps.gp_count, 0)) return -EINVAL; @@ -89,6 +107,26 @@ inline int pmc_stop(uint8_t i) return 0; } +inline int pmc_ff_start(uint8_t i) +{ + if (BUILTIN_EXPECT(i > caps.ff_count, 0)) + return -EINVAL; + + // TODO + + return 0; +} + +inline int pmc_ff_stop(uint8_t i) +{ + if (BUILTIN_EXPECT(i > caps.ff_count, 0)) + return -EINVAL; + + // TODO + + return 0; +} + inline int pmc_start_all() { if (BUILTIN_EXPECT(caps.version < 2, 0)) @@ -109,7 +147,22 @@ inline int pmc_stop_all() return 0; } -inline uint64_t pmc_read(uint8_t i) +inline int pmc_reset_all() +{ + if (BUILTIN_EXPECT(caps.version < 2, 0)) + return -EINVAL; + + int i; + for (i = 0; i < caps.gp_count; i++) + pmc_gp_write(i, 0); + + for (i = 0; i < caps.ff_count; i++) + pmc_ff_write(i, 0); + + return 0; +} + +inline uint64_t pmc_gp_read(uint8_t i) { if (BUILTIN_EXPECT(i > caps.gp_count, 0)) return 0; @@ -119,7 +172,17 @@ inline uint64_t pmc_read(uint8_t i) return 0; } -inline int pmc_write(uint8_t i, uint64_t val) +inline uint64_t pmc_ff_read(uint8_t i) +{ + if (BUILTIN_EXPECT(i > caps.ff_count, 0)) + return 0; + + return rdmsr(MSR_PERF_FIXED_CTR(i)); + + return 0; +} + +inline int pmc_gp_write(uint8_t i, uint64_t val) { if (BUILTIN_EXPECT(i > caps.gp_count, 0)) return -EINVAL; @@ -131,3 +194,13 @@ inline int pmc_write(uint8_t i, uint64_t val) return 0; } + +inline int pmc_ff_write(uint8_t i, uint64_t val) +{ + if (BUILTIN_EXPECT(i > caps.ff_count, 0)) + return -EINVAL; + + wrmsr(MSR_PERF_FIXED_CTR(i), val); + + return 0; +} diff --git a/mm/malloc.c b/mm/malloc.c index ae512bc5..48120441 100644 --- a/mm/malloc.c +++ b/mm/malloc.c @@ -17,6 +17,10 @@ * This file is part of MetalSVM. */ +/** + * @author Steffen Vogel + */ + #include #include #include