From 3286984f711cfb5cb5ae9bba783481e55a14829b Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Wed, 7 Aug 2024 15:20:03 -0400 Subject: [PATCH 01/20] perf_event: added subdbg to mmap_read_self --- src/components/perf_event/perf_helpers.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/perf_event/perf_helpers.h b/src/components/perf_event/perf_helpers.h index 59c8a2fc8..e3d244a4e 100644 --- a/src/components/perf_event/perf_helpers.h +++ b/src/components/perf_event/perf_helpers.h @@ -247,6 +247,9 @@ static inline unsigned long long mmap_read_self(void *addr, unsigned long long *en, unsigned long long *ru) { + SUBDBG("ENTER: addr: %p, user_reset_flag: %d, reset: %llu, en: %llu, ru: %llu\n", + addr, user_reset_flag, reset, *en, *ru); + struct perf_event_mmap_page *pc = addr; uint32_t seq, time_mult = 0, time_shift = 0, index, width; From 2e03da387299c8c74f707532a4c4c136b04916a2 Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Thu, 8 Aug 2024 13:07:45 -0400 Subject: [PATCH 02/20] validation_tests: Began stub validation test for validating topdown events --- src/validation_tests/Makefile.recipies | 3 + src/validation_tests/topdown_validation.c | 169 ++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 src/validation_tests/topdown_validation.c diff --git a/src/validation_tests/Makefile.recipies b/src/validation_tests/Makefile.recipies index f4b62298c..6d81f713c 100644 --- a/src/validation_tests/Makefile.recipies +++ b/src/validation_tests/Makefile.recipies @@ -1,5 +1,6 @@ ALL = fp_validation_hl \ cycles_validation flops_validation \ + topdown_validation \ papi_br_cn papi_br_ins papi_br_msp \ papi_br_ntk papi_br_prc papi_br_tkn papi_br_ucn \ papi_dp_ops papi_fp_ops papi_sp_ops papi_hw_int \ @@ -47,6 +48,8 @@ cycles_validation: cycles_validation.o $(TESTLIB) $(PAPILIB) display_error.o ins flops_validation: flops_validation.o $(TESTLIB) $(PAPILIB) display_error.o branches_testcode.o flops_testcode.o $(CC) -o flops_validation flops_validation.o $(TESTLIB) display_error.o branches_testcode.o flops_testcode.o $(PAPILIB) $(LDFLAGS) $(EXTRALIB) +topdown_validation: topdown_validation.o $(TESTLIB) $(PAPILIB) instructions_testcode.o + $(CC) -o topdown_validation topdown_validation.o $(TESTLIB) instructions_testcode.o $(PAPILIB) $(LDFLAGS) $(EXTRALIB) memleak_check: memleak_check.o $(TESTLIB) $(PAPILIB) display_error.o branches_testcode.o $(CC) -o memleak_check memleak_check.o $(TESTLIB) display_error.o branches_testcode.o $(PAPILIB) $(LDFLAGS) $(LDFLAGS) $(EXTRALIB) diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c new file mode 100644 index 000000000..52f808331 --- /dev/null +++ b/src/validation_tests/topdown_validation.c @@ -0,0 +1,169 @@ +/* topdown_validation.c */ + +/* TODO: Explain */ + +#include +#include + +#include "papi.h" +#include "papi_test.h" +#include "testcode.h" + +#define NUM_EVENTS 4 +#define NUM_LOOPS 100 + +/* + * Applies bitshifts to the metric counter value to extract a topdown metric, + * and scales the result into a percentage + */ +float get_metric(u_int64_t m, int i) +{ + return (float)(((m) >> (i * 8)) & 0xff) / 0xff * 100.0; +} + +/* print metric percentages */ +void print_metrics(u_int64_t m) +{ + printf("Metrics:\n\tretiring:\t%02f\n\tbadspec:\t%02f\n\tfrontend bound:\t%02f\n\tbackend bound:\t%02f\n", + get_metric(m, 0), get_metric(m, 1), get_metric(m, 2), get_metric(m, 3)); +} + +/* ensure a metric is internally consistent */ +void assert_metrics_percentages(u_int64_t m) +{ + double sum = get_metric(m, 0) + get_metric(m, 1) + get_metric(m, 2) + get_metric(m, 3); + if (!approx_equals(sum, 100)) + { + test_fail(__FILE__, __LINE__, "Metrics percentages do not sum to 100", 1); + } +} + +int main(int argc, char **argv) +{ + // Set up and call the topdown events + // Then parse as percentages and ensure it makes some sense + + int retval, tmp, result, i; + int EventSet1 = PAPI_NULL; + long long values[NUM_EVENTS]; + long long elapsed_us, elapsed_cyc, elapsed_virt_us, elapsed_virt_cyc; + double cycles_error; + int quiet = 0; + + /* Set TESTS_QUIET variable */ + quiet = tests_quiet(argc, argv); + + /* Init the PAPI library */ + retval = PAPI_library_init(PAPI_VER_CURRENT); + if (retval != PAPI_VER_CURRENT) + { + test_fail(__FILE__, __LINE__, "PAPI_library_init", retval); + } + + /* Initialize the EventSet */ + retval = PAPI_create_eventset(&EventSet1); + if (retval != PAPI_OK) + { + test_fail(__FILE__, __LINE__, "PAPI_create_eventset", retval); + } + + /* Add TOPDOWN:SLOTS first - slots must be the first event in a set */ + retval = PAPI_add_named_event(EventSet1, "TOPDOWN:SLOTS"); + if (retval != PAPI_OK) + { + if (!quiet) + printf("Trouble adding TOPDOWN:SLOTS\n"); + test_skip(__FILE__, __LINE__, "adding TOPDOWN:SLOTS", retval); + } + + /* Add TOPDOWN:RETIRING_SLOTS */ + retval = PAPI_add_named_event(EventSet1, "TOPDOWN:RETIRING_SLOTS"); + if (retval != PAPI_OK) + { + if (!quiet) + printf("Trouble adding TOPDOWN:RETIRING_SLOTS\n"); + test_skip(__FILE__, __LINE__, "adding TOPDOWN:RETIRING_SLOTS", retval); + } + + /* Add TOPDOWN:BACKEND_BOUND_SLOTS */ + retval = PAPI_add_named_event(EventSet1, "TOPDOWN:BACKEND_BOUND_SLOTS"); + if (retval != PAPI_OK) + { + if (!quiet) + printf("Trouble adding TOPDOWN:BACKEND_BOUND_SLOTS\n"); + test_skip(__FILE__, __LINE__, "adding TOPDOWN:BACKEND_BOUND_SLOTS", retval); + } + + /* Add TOPDOWN:BAD_SPEC_SLOTS */ + retval = PAPI_add_named_event(EventSet1, "TOPDOWN:BAD_SPEC_SLOTS"); + if (retval != PAPI_OK) + { + if (!quiet) + printf("Trouble adding TOPDOWN:BAD_SPEC_SLOTS\n"); + test_skip(__FILE__, __LINE__, "adding TOPDOWN:BAD_SPEC_SLOTS", retval); + } + + /* warm up the processor to pull it out of idle state */ + for (i = 0; i < 100; i++) + { + result = instructions_million(); + } + + if (result == CODE_UNIMPLEMENTED) + { + if (!quiet) + printf("Instructions testcode not available\n"); + test_skip(__FILE__, __LINE__, "No instructions code", retval); + } + + /* Gather before stats */ + elapsed_us = PAPI_get_real_usec(); + elapsed_cyc = PAPI_get_real_cyc(); + elapsed_virt_us = PAPI_get_virt_usec(); + elapsed_virt_cyc = PAPI_get_virt_cyc(); + + /* Start PAPI */ + retval = PAPI_start(EventSet1); + if (retval != PAPI_OK) + { + test_fail(__FILE__, __LINE__, "PAPI_start", retval); + } + + /* our work code */ + for (i = 0; i < NUM_LOOPS; i++) + { + instructions_million(); + } + + /* Stop PAPI */ + retval = PAPI_stop(EventSet1, values); + if (retval != PAPI_OK) + { + test_fail(__FILE__, __LINE__, "PAPI_stop", retval); + } + + /* Lets see what we got */ + retval = PAPI_cleanup_eventset(EventSet1); + if (retval != PAPI_OK) + { + test_fail(__FILE__, __LINE__, "PAPI_cleanup_eventset", retval); + } + + retval = PAPI_destroy_eventset(&EventSet1); + if (retval != PAPI_OK) + { + test_fail(__FILE__, __LINE__, "PAPI_destroy_eventset", retval); + } + + printf("Slots: %d\n", values[0]); + printf("\t%#0x\n\t%#0x\n\t%#0x\n\t#0x\n", values[1], values[2], values[3]); + + print_metrics(values[1]); + assert_metrics_percentages(values[1]); + + print_metrics(values[2]); + assert_metrics_percentages(values[2]); + + print_metrics(values[3]); + assert_metrics_percentages(values[3]); +} \ No newline at end of file From 30496eae319734cad3cbc2d614e9ab9a63999626 Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Thu, 8 Aug 2024 14:01:42 -0400 Subject: [PATCH 03/20] validation_tests: added calculations for the case when rdpmc is disabled --- src/validation_tests/topdown_validation.c | 38 ++++++++++++++--------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index 52f808331..1d7e013b4 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -13,31 +13,38 @@ #define NUM_LOOPS 100 /* + * When the counter is read with rdpmc, each td event is embedded in the value. * Applies bitshifts to the metric counter value to extract a topdown metric, * and scales the result into a percentage */ -float get_metric(u_int64_t m, int i) +float rdpmc_get_metric(u_int64_t m, int i) { return (float)(((m) >> (i * 8)) & 0xff) / 0xff * 100.0; } -/* print metric percentages */ -void print_metrics(u_int64_t m) +/* print metric percentages for topdown rdpmc reads */ +void rdpmc_print_metrics(u_int64_t m) { printf("Metrics:\n\tretiring:\t%02f\n\tbadspec:\t%02f\n\tfrontend bound:\t%02f\n\tbackend bound:\t%02f\n", - get_metric(m, 0), get_metric(m, 1), get_metric(m, 2), get_metric(m, 3)); + rdpmc_get_metric(m, 0), rdpmc_get_metric(m, 1), rdpmc_get_metric(m, 2), rdpmc_get_metric(m, 3)); } -/* ensure a metric is internally consistent */ -void assert_metrics_percentages(u_int64_t m) +/* ensure a metric is internally consistent for topdown rdpmc reads */ +void rdpmc_assert_metrics_percentages(u_int64_t m) { - double sum = get_metric(m, 0) + get_metric(m, 1) + get_metric(m, 2) + get_metric(m, 3); + double sum = rdpmc_get_metric(m, 0) + rdpmc_get_metric(m, 1) + rdpmc_get_metric(m, 2) + rdpmc_get_metric(m, 3); if (!approx_equals(sum, 100)) { test_fail(__FILE__, __LINE__, "Metrics percentages do not sum to 100", 1); } } +/* get precentages for non-rdpmc */ +void non_rdpmc_assert_percentages(u_int64_t slots, u_int64_t re, u_int64_t be, u_int64_t bs) +{ + printf("%02f %02f %02f\n", (float)re / slots * 100.0, (float)be / slots * 100.0, (float)bs / slots * 100.0); +} + int main(int argc, char **argv) { // Set up and call the topdown events @@ -156,14 +163,17 @@ int main(int argc, char **argv) } printf("Slots: %d\n", values[0]); - printf("\t%#0x\n\t%#0x\n\t%#0x\n\t#0x\n", values[1], values[2], values[3]); + printf("\tRETIRING_SLOTS:\t%#0x\n\tBACKEND_BOUND_SLOTS:\t%#0x\n\tBAD_SPEC_SLOTS:\t%#0x\n\tsum:\t%#0x\n", + values[1], values[2], values[3], values[1] + values[2] + values[3]); + + non_rdpmc_assert_percentages(values[0], values[1], values[2], values[3]); - print_metrics(values[1]); - assert_metrics_percentages(values[1]); + rdpmc_print_metrics(values[1]); + rdpmc_assert_metrics_percentages(values[1]); - print_metrics(values[2]); - assert_metrics_percentages(values[2]); + rdpmc_print_metrics(values[2]); + rdpmc_assert_metrics_percentages(values[2]); - print_metrics(values[3]); - assert_metrics_percentages(values[3]); + rdpmc_print_metrics(values[3]); + rdpmc_assert_metrics_percentages(values[3]); } \ No newline at end of file From 61dcd5b34d8d40e773314c410bface771619859d Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Mon, 12 Aug 2024 15:52:09 -0400 Subject: [PATCH 04/20] validation_tests: topdown test now compares rdpmc instruction results with papi results As using the rdpmc instruction directly has consistently reported reasonable results, it is used as the ground truth for this test --- src/validation_tests/topdown_validation.c | 180 +++++++++++++++++----- 1 file changed, 139 insertions(+), 41 deletions(-) diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index 1d7e013b4..6bc3ecd29 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -9,9 +9,57 @@ #include "papi_test.h" #include "testcode.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + #define NUM_EVENTS 4 #define NUM_LOOPS 100 +/* + * perf_event _rdpmc code + */ + +#define RDPMC_FIXED (1 << 30) /* return fixed counters */ +#define RDPMC_METRIC (1 << 29) /* return metric counters */ + +#define FIXED_COUNTER_SLOTS 3 /* on raptorlake it is fiex counter 3 */ +#define METRIC_COUNTER_TOPDOWN_L1_L2 0 + +__attribute__((weak)) +int perf_event_open(struct perf_event_attr *attr, pid_t pid, + int cpu, int group_fd, unsigned long flags) +{ + return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); +} + +static inline uint64_t read_slots(void) +{ + return _rdpmc(RDPMC_FIXED | FIXED_COUNTER_SLOTS); +} + +/* +The value reported by read_metrics() contains four 8 bit fields +that represent a scaled ratio that represent the Level 1 bottleneck. +All four fields add up to 0xff (= 100%) +*/ +static inline uint64_t read_metrics(void) +{ + return _rdpmc(RDPMC_METRIC | METRIC_COUNTER_TOPDOWN_L1_L2); +} + +static inline int reset_metrics(int fd) +{ + return ioctl(fd, PERF_EVENT_IOC_RESET, 0); +} + /* * When the counter is read with rdpmc, each td event is embedded in the value. * Applies bitshifts to the metric counter value to extract a topdown metric, @@ -22,27 +70,30 @@ float rdpmc_get_metric(u_int64_t m, int i) return (float)(((m) >> (i * 8)) & 0xff) / 0xff * 100.0; } -/* print metric percentages for topdown rdpmc reads */ -void rdpmc_print_metrics(u_int64_t m) +/* takes a metric integer and populates the array with individual percentages */ +/* in order: retiring, bad spec, fe bound, be bound */ +void topdown_get_from_metrics(double *percentages, uint64_t metrics) { - printf("Metrics:\n\tretiring:\t%02f\n\tbadspec:\t%02f\n\tfrontend bound:\t%02f\n\tbackend bound:\t%02f\n", - rdpmc_get_metric(m, 0), rdpmc_get_metric(m, 1), rdpmc_get_metric(m, 2), rdpmc_get_metric(m, 3)); + percentages[0] = rdpmc_get_metric(metrics, 0); + percentages[1] = rdpmc_get_metric(metrics, 1); + percentages[2] = rdpmc_get_metric(metrics, 2); + percentages[3] = rdpmc_get_metric(metrics, 3); } -/* ensure a metric is internally consistent for topdown rdpmc reads */ -void rdpmc_assert_metrics_percentages(u_int64_t m) +/* takes papi events and populates the array with individual percentages */ +/* in order: retiring, bad spec, fe bound, be bound */ +void topdown_get_from_events(double *percentages, uint64_t slots, uint64_t retiring, uint64_t badspec, uint64_t be_bound) { - double sum = rdpmc_get_metric(m, 0) + rdpmc_get_metric(m, 1) + rdpmc_get_metric(m, 2) + rdpmc_get_metric(m, 3); - if (!approx_equals(sum, 100)) - { - test_fail(__FILE__, __LINE__, "Metrics percentages do not sum to 100", 1); - } + percentages[0] = (double)retiring / (double)slots * 100.0; + percentages[1] = (double)badspec / (double)slots * 100.0; + percentages[3] = (double)be_bound / (double)slots * 100.0; + percentages[2] = slots - percentages[0] - percentages[1] - percentages[3]; } -/* get precentages for non-rdpmc */ -void non_rdpmc_assert_percentages(u_int64_t slots, u_int64_t re, u_int64_t be, u_int64_t bs) +void print_percs(double *percs) { - printf("%02f %02f %02f\n", (float)re / slots * 100.0, (float)be / slots * 100.0, (float)bs / slots * 100.0); + printf("\tretiring:\t%02f\n\tbadspec:\t%02f\n\tfe_bound:\t%02f\n\tbe_bound:\t%02f\n", + percs[0], percs[1], percs[2], percs[3]); } int main(int argc, char **argv) @@ -51,15 +102,63 @@ int main(int argc, char **argv) // Then parse as percentages and ensure it makes some sense int retval, tmp, result, i; + uint64_t rdpmc_slots, rdpmc_metrics; int EventSet1 = PAPI_NULL; long long values[NUM_EVENTS]; - long long elapsed_us, elapsed_cyc, elapsed_virt_us, elapsed_virt_cyc; + double rdpmc_percs[4], papi_rdpmc_percs[4], papi_events_percs[4]; + double percentages[NUM_EVENTS]; double cycles_error; int quiet = 0; /* Set TESTS_QUIET variable */ quiet = tests_quiet(argc, argv); + /******************************/ + /* Set up perf_event syscalls */ + /******************************/ + + /* Open slots counter file descriptor for current task. */ + struct perf_event_attr slots = { + .type = PERF_TYPE_RAW, + .size = sizeof(struct perf_event_attr), + .config = 0x400, + .exclude_kernel = 1, + }; + + int slots_fd = perf_event_open(&slots, 0, -1, -1, 0); + if (slots_fd < 0) + printf("Error opening the perf event slots\n"); + + /* Memory mapping the fd permits _rdpmc calls from userspace */ + void *slots_p = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, slots_fd, 0); + if (!slots_p) + printf("Error memory mapping the fd permits for _rdpmc\n"); + + /* + * Open metrics event file descriptor for current task. + * Set slots event as the leader of the group. + */ + struct perf_event_attr metrics = { + .type = PERF_TYPE_RAW, + .size = sizeof(struct perf_event_attr), + .config = 0x8000, + .exclude_kernel = 1, + }; + + int metrics_fd = perf_event_open(&metrics, 0, -1, slots_fd, 0); + if (metrics_fd < 0) + printf("Failed to open the metrics fd\n"); + + /* Memory mapping the fd permits _rdpmc calls from userspace */ + void *metrics_p = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, metrics_fd, 0); + if (!metrics_p) + printf("Failed to memory map the metrics\n"); + + + /***************/ + /* Set up PAPI */ + /***************/ + /* Init the PAPI library */ retval = PAPI_library_init(PAPI_VER_CURRENT); if (retval != PAPI_VER_CURRENT) @@ -123,57 +222,56 @@ int main(int argc, char **argv) test_skip(__FILE__, __LINE__, "No instructions code", retval); } - /* Gather before stats */ - elapsed_us = PAPI_get_real_usec(); - elapsed_cyc = PAPI_get_real_cyc(); - elapsed_virt_us = PAPI_get_virt_usec(); - elapsed_virt_cyc = PAPI_get_virt_cyc(); + /* make sure the metrics are cleared */ + reset_metrics(slots_fd); + reset_metrics(metrics_fd); - /* Start PAPI */ + /* lets start the actual test code */ retval = PAPI_start(EventSet1); if (retval != PAPI_OK) { test_fail(__FILE__, __LINE__, "PAPI_start", retval); } - /* our work code */ for (i = 0; i < NUM_LOOPS; i++) { - instructions_million(); + result = instructions_million(); } - /* Stop PAPI */ retval = PAPI_stop(EventSet1, values); if (retval != PAPI_OK) { test_fail(__FILE__, __LINE__, "PAPI_stop", retval); } - /* Lets see what we got */ + /* Check and see what _rdpmc got */ + rdpmc_slots = read_slots(); + rdpmc_metrics = read_metrics(); + topdown_get_from_metrics(rdpmc_percs, rdpmc_metrics); + + /* Lets see what we got with PAPI */ + topdown_get_from_metrics(papi_rdpmc_percs, values[1]); + topdown_get_from_events(papi_events_percs, values[0], values[1], values[2], values[3]); + + printf("rdpmc\n"); + print_percs(rdpmc_percs); + printf("papi rdpmc\n"); + print_percs(papi_rdpmc_percs); + printf("papi events\n"); + print_percs(papi_events_percs); + + /* Clean up everything */ + close(slots_fd); + close(metrics_fd); + retval = PAPI_cleanup_eventset(EventSet1); if (retval != PAPI_OK) { test_fail(__FILE__, __LINE__, "PAPI_cleanup_eventset", retval); } - retval = PAPI_destroy_eventset(&EventSet1); if (retval != PAPI_OK) { test_fail(__FILE__, __LINE__, "PAPI_destroy_eventset", retval); } - - printf("Slots: %d\n", values[0]); - printf("\tRETIRING_SLOTS:\t%#0x\n\tBACKEND_BOUND_SLOTS:\t%#0x\n\tBAD_SPEC_SLOTS:\t%#0x\n\tsum:\t%#0x\n", - values[1], values[2], values[3], values[1] + values[2] + values[3]); - - non_rdpmc_assert_percentages(values[0], values[1], values[2], values[3]); - - rdpmc_print_metrics(values[1]); - rdpmc_assert_metrics_percentages(values[1]); - - rdpmc_print_metrics(values[2]); - rdpmc_assert_metrics_percentages(values[2]); - - rdpmc_print_metrics(values[3]); - rdpmc_assert_metrics_percentages(values[3]); } \ No newline at end of file From daaf301277f225de44dec9721780b2cdebff6f15 Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Tue, 13 Aug 2024 09:31:08 -0400 Subject: [PATCH 05/20] vaidation_tests: added percentage comparison code to topdown_validation --- src/validation_tests/topdown_validation.c | 135 ++++++++++++++-------- 1 file changed, 87 insertions(+), 48 deletions(-) diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index 6bc3ecd29..2936beaa6 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -22,27 +22,29 @@ #define NUM_EVENTS 4 #define NUM_LOOPS 100 +#define NUM_TESTS 1000 + +#define PERCENTAGES_TOLERANCE 0.1 /* * perf_event _rdpmc code */ -#define RDPMC_FIXED (1 << 30) /* return fixed counters */ -#define RDPMC_METRIC (1 << 29) /* return metric counters */ +#define RDPMC_FIXED (1 << 30) /* return fixed counters */ +#define RDPMC_METRIC (1 << 29) /* return metric counters */ -#define FIXED_COUNTER_SLOTS 3 /* on raptorlake it is fiex counter 3 */ -#define METRIC_COUNTER_TOPDOWN_L1_L2 0 +#define FIXED_COUNTER_SLOTS 3 /* on raptorlake it is fiex counter 3 */ +#define METRIC_COUNTER_TOPDOWN_L1_L2 0 -__attribute__((weak)) -int perf_event_open(struct perf_event_attr *attr, pid_t pid, - int cpu, int group_fd, unsigned long flags) +__attribute__((weak)) int perf_event_open(struct perf_event_attr *attr, pid_t pid, + int cpu, int group_fd, unsigned long flags) { - return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); + return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); } static inline uint64_t read_slots(void) { - return _rdpmc(RDPMC_FIXED | FIXED_COUNTER_SLOTS); + return _rdpmc(RDPMC_FIXED | FIXED_COUNTER_SLOTS); } /* @@ -52,7 +54,7 @@ All four fields add up to 0xff (= 100%) */ static inline uint64_t read_metrics(void) { - return _rdpmc(RDPMC_METRIC | METRIC_COUNTER_TOPDOWN_L1_L2); + return _rdpmc(RDPMC_METRIC | METRIC_COUNTER_TOPDOWN_L1_L2); } static inline int reset_metrics(int fd) @@ -93,7 +95,29 @@ void topdown_get_from_events(double *percentages, uint64_t slots, uint64_t retir void print_percs(double *percs) { printf("\tretiring:\t%02f\n\tbadspec:\t%02f\n\tfe_bound:\t%02f\n\tbe_bound:\t%02f\n", - percs[0], percs[1], percs[2], percs[3]); + percs[0], percs[1], percs[2], percs[3]); +} + +int eq_within_tolerance(double a, double b, double tolerance) +{ + if (a + tolerance >= b && a - tolerance <= b) + return 1; + + return 0; +} + +int are_percs_equivalent(double *percs_a, double *percs_b) +{ + if (!eq_within_tolerance(percs_a[0], percs_b[0], PERCENTAGES_TOLERANCE)) + return 0; + if (!eq_within_tolerance(percs_a[1], percs_b[1], PERCENTAGES_TOLERANCE)) + return 0; + if (!eq_within_tolerance(percs_a[2], percs_b[2], PERCENTAGES_TOLERANCE)) + return 0; + if (!eq_within_tolerance(percs_a[3], percs_b[3], PERCENTAGES_TOLERANCE)) + return 0; + + return 1; } int main(int argc, char **argv) @@ -101,7 +125,7 @@ int main(int argc, char **argv) // Set up and call the topdown events // Then parse as percentages and ensure it makes some sense - int retval, tmp, result, i; + int retval, tmp, result, i, j, failures; uint64_t rdpmc_slots, rdpmc_metrics; int EventSet1 = PAPI_NULL; long long values[NUM_EVENTS]; @@ -135,9 +159,9 @@ int main(int argc, char **argv) printf("Error memory mapping the fd permits for _rdpmc\n"); /* - * Open metrics event file descriptor for current task. - * Set slots event as the leader of the group. - */ + * Open metrics event file descriptor for current task. + * Set slots event as the leader of the group. + */ struct perf_event_attr metrics = { .type = PERF_TYPE_RAW, .size = sizeof(struct perf_event_attr), @@ -153,7 +177,6 @@ int main(int argc, char **argv) void *metrics_p = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, metrics_fd, 0); if (!metrics_p) printf("Failed to memory map the metrics\n"); - /***************/ /* Set up PAPI */ @@ -222,48 +245,64 @@ int main(int argc, char **argv) test_skip(__FILE__, __LINE__, "No instructions code", retval); } - /* make sure the metrics are cleared */ - reset_metrics(slots_fd); - reset_metrics(metrics_fd); - - /* lets start the actual test code */ - retval = PAPI_start(EventSet1); - if (retval != PAPI_OK) + /* now lets run our tests */ + failures = 0; + for (i = 0; i < NUM_TESTS; i++) { - test_fail(__FILE__, __LINE__, "PAPI_start", retval); - } - for (i = 0; i < NUM_LOOPS; i++) - { - result = instructions_million(); + /* make sure the metrics are cleared */ + reset_metrics(slots_fd); + reset_metrics(metrics_fd); + + /* lets start the actual test code */ + retval = PAPI_start(EventSet1); + if (retval != PAPI_OK) + { + test_fail(__FILE__, __LINE__, "PAPI_start", retval); + } + + for (i = 0; i < NUM_LOOPS; i++) + { + result = instructions_million(); + } + + retval = PAPI_stop(EventSet1, values); + if (retval != PAPI_OK) + { + test_fail(__FILE__, __LINE__, "PAPI_stop", retval); + } + + /* Check and see what _rdpmc got */ + rdpmc_slots = read_slots(); + rdpmc_metrics = read_metrics(); + topdown_get_from_metrics(rdpmc_percs, rdpmc_metrics); + + /* Lets see what we got with PAPI */ + topdown_get_from_metrics(papi_rdpmc_percs, values[1]); + topdown_get_from_events(papi_events_percs, values[0], values[1], values[2], values[3]); + + if (are_percs_equivalent(rdpmc_percs, papi_rdpmc_percs) + are_percs_equivalent(rdpmc_percs, papi_events_percs) != 1) + { + //printf("rdpmc\n"); + //print_percs(rdpmc_percs); + //printf("papi rdpmc, equivalent=%d\n", are_percs_equivalent(rdpmc_percs, papi_rdpmc_percs)); + //print_percs(papi_rdpmc_percs); + //printf("papi events, equivalent=%d\n", are_percs_equivalent(rdpmc_percs, papi_events_percs)); + //print_percs(papi_events_percs); + failures++; + } } - retval = PAPI_stop(EventSet1, values); - if (retval != PAPI_OK) + printf("There were %d failures\n", failures); + if (failures > 0) { - test_fail(__FILE__, __LINE__, "PAPI_stop", retval); + test_fail(__FILE__, __LINE__, "Papi results did not match perf results at least once", 1); } - /* Check and see what _rdpmc got */ - rdpmc_slots = read_slots(); - rdpmc_metrics = read_metrics(); - topdown_get_from_metrics(rdpmc_percs, rdpmc_metrics); - - /* Lets see what we got with PAPI */ - topdown_get_from_metrics(papi_rdpmc_percs, values[1]); - topdown_get_from_events(papi_events_percs, values[0], values[1], values[2], values[3]); - - printf("rdpmc\n"); - print_percs(rdpmc_percs); - printf("papi rdpmc\n"); - print_percs(papi_rdpmc_percs); - printf("papi events\n"); - print_percs(papi_events_percs); - /* Clean up everything */ close(slots_fd); close(metrics_fd); - + retval = PAPI_cleanup_eventset(EventSet1); if (retval != PAPI_OK) { From 4d373658f0f30484ff9109028bed7418546747cf Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Tue, 13 Aug 2024 09:38:32 -0400 Subject: [PATCH 06/20] validation_tests: fixed infinite loop in topdown_validation --- src/validation_tests/topdown_validation.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index 2936beaa6..051fa8bba 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -247,9 +247,8 @@ int main(int argc, char **argv) /* now lets run our tests */ failures = 0; - for (i = 0; i < NUM_TESTS; i++) + for (j = 0; j < NUM_TESTS; j++) { - /* make sure the metrics are cleared */ reset_metrics(slots_fd); reset_metrics(metrics_fd); From d01aa15e456943f0f1bb6a03cb303c16cc556e3c Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Wed, 14 Aug 2024 16:27:34 -0400 Subject: [PATCH 07/20] validation_tests: topdown_validation now collects absolute error --- src/validation_tests/topdown_validation.c | 91 ++++++++++++++++------- 1 file changed, 65 insertions(+), 26 deletions(-) diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index 051fa8bba..e91ce8753 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -22,7 +22,7 @@ #define NUM_EVENTS 4 #define NUM_LOOPS 100 -#define NUM_TESTS 1000 +#define NUM_TESTS 100 #define PERCENTAGES_TOLERANCE 0.1 @@ -89,7 +89,7 @@ void topdown_get_from_events(double *percentages, uint64_t slots, uint64_t retir percentages[0] = (double)retiring / (double)slots * 100.0; percentages[1] = (double)badspec / (double)slots * 100.0; percentages[3] = (double)be_bound / (double)slots * 100.0; - percentages[2] = slots - percentages[0] - percentages[1] - percentages[3]; + percentages[2] = 100.0 - percentages[0] - percentages[1] - percentages[3]; } void print_percs(double *percs) @@ -106,18 +106,20 @@ int eq_within_tolerance(double a, double b, double tolerance) return 0; } -int are_percs_equivalent(double *percs_a, double *percs_b) +int are_percs_equivalent(double *percs_gt, double *percs_b, double *abs_error, int n_percs) { - if (!eq_within_tolerance(percs_a[0], percs_b[0], PERCENTAGES_TOLERANCE)) - return 0; - if (!eq_within_tolerance(percs_a[1], percs_b[1], PERCENTAGES_TOLERANCE)) - return 0; - if (!eq_within_tolerance(percs_a[2], percs_b[2], PERCENTAGES_TOLERANCE)) - return 0; - if (!eq_within_tolerance(percs_a[3], percs_b[3], PERCENTAGES_TOLERANCE)) - return 0; - - return 1; + int i; + int eq = 1; + for (i = 0; i < n_percs; i++) + { + if (!eq_within_tolerance(percs_gt[i], percs_b[i], PERCENTAGES_TOLERANCE)) + { + abs_error[i] = (percs_gt[i] - percs_b[i] > 0) ? percs_gt[i] - percs_b[i] : percs_b[i] - percs_gt[i]; + eq = 0; + } + } + + return eq; } int main(int argc, char **argv) @@ -129,8 +131,11 @@ int main(int argc, char **argv) uint64_t rdpmc_slots, rdpmc_metrics; int EventSet1 = PAPI_NULL; long long values[NUM_EVENTS]; - double rdpmc_percs[4], papi_rdpmc_percs[4], papi_events_percs[4]; - double percentages[NUM_EVENTS]; + + double rdpmc_percs[NUM_EVENTS], papi_rdpmc_percs[NUM_EVENTS], papi_event_percs[NUM_EVENTS]; + double avg_rdpmc_percs[NUM_EVENTS], avg_papi_rdpmc_percs[NUM_EVENTS], avg_papi_event_percs[NUM_EVENTS]; + double err_papi_rdpmc_percs[NUM_EVENTS], err_papi_event_percs[NUM_EVENTS]; + double cycles_error; int quiet = 0; @@ -275,23 +280,57 @@ int main(int argc, char **argv) rdpmc_slots = read_slots(); rdpmc_metrics = read_metrics(); topdown_get_from_metrics(rdpmc_percs, rdpmc_metrics); + for (i = 0; i < NUM_EVENTS; i++) + avg_rdpmc_percs[i] += rdpmc_percs[i]; - /* Lets see what we got with PAPI */ + /* Lets see what we got with PAPI rdpmc */ topdown_get_from_metrics(papi_rdpmc_percs, values[1]); - topdown_get_from_events(papi_events_percs, values[0], values[1], values[2], values[3]); + for (i = 0; i < NUM_EVENTS; i++) + avg_papi_rdpmc_percs[i] += papi_rdpmc_percs[i]; + + /* And with PAPI events */ + topdown_get_from_events(papi_event_percs, values[0], values[1], values[2], values[3]); + for (i = 0; i < NUM_EVENTS; i++) + avg_papi_event_percs[i] += papi_event_percs[i]; - if (are_percs_equivalent(rdpmc_percs, papi_rdpmc_percs) + are_percs_equivalent(rdpmc_percs, papi_events_percs) != 1) + if ((are_percs_equivalent(rdpmc_percs, papi_rdpmc_percs, err_papi_rdpmc_percs, NUM_EVENTS) + + are_percs_equivalent(rdpmc_percs, papi_event_percs, err_papi_event_percs, NUM_EVENTS)) < 1) { - //printf("rdpmc\n"); - //print_percs(rdpmc_percs); - //printf("papi rdpmc, equivalent=%d\n", are_percs_equivalent(rdpmc_percs, papi_rdpmc_percs)); - //print_percs(papi_rdpmc_percs); - //printf("papi events, equivalent=%d\n", are_percs_equivalent(rdpmc_percs, papi_events_percs)); - //print_percs(papi_events_percs); - failures++; - } + printf("Failed: %#0x\n", values[1]); + + printf("rdpmc err: "); + for (i = 0; i < NUM_EVENTS; i++) + { + printf("%f\t", err_papi_rdpmc_percs[i]); + } + printf("\nevent err: "); + for (i = 0; i < NUM_EVENTS; i++) + { + printf("%f\t", err_papi_event_percs[i]); + } + putchar('\n'); + failures++; + } + + } + // get averages + for (i = 0; i < NUM_EVENTS; i++) + { + avg_rdpmc_percs[i] /= NUM_TESTS; + avg_papi_rdpmc_percs[i] /= NUM_TESTS; + avg_papi_event_percs[i] /= NUM_TESTS; + } + + // print averages + printf("Averaged percentages for _rdpmc:\n"); + print_percs(avg_rdpmc_percs); + printf("Averaged percentages for PAPI rdpmc:\n"); + print_percs(avg_papi_rdpmc_percs); + printf("Averaged percentages for PAPI events:\n"); + print_percs(avg_papi_event_percs); + printf("There were %d failures\n", failures); if (failures > 0) { From 8e7e56667696736b61931f2caab635dd167c1f9d Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Thu, 15 Aug 2024 10:56:44 -0400 Subject: [PATCH 08/20] perf_event: commenting out pe_ctl->reset_flag=0 fixes rdpmc enabled topdown metrics --- src/components/perf_event/perf_event.c | 2 +- src/validation_tests/topdown_validation.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/components/perf_event/perf_event.c b/src/components/perf_event/perf_event.c index 7c16b6d0c..c8efefb33 100644 --- a/src/components/perf_event/perf_event.c +++ b/src/components/perf_event/perf_event.c @@ -1469,7 +1469,7 @@ _pe_start( hwd_context_t *ctx, hwd_control_state_t *ctl ) PERF_EVENT_IOC_ENABLE, NULL) ; if (_perf_event_vector.cmp_info.fast_counter_read) { pe_ctl->reset_counts[i] = 0LL; - pe_ctl->reset_flag = 0; + //pe_ctl->reset_flag = 0; } /* ioctls always return -1 on failure */ diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index e91ce8753..28785cb49 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -127,7 +127,7 @@ int main(int argc, char **argv) // Set up and call the topdown events // Then parse as percentages and ensure it makes some sense - int retval, tmp, result, i, j, failures; + int retval, tmp, result, i, j, failures, mismatches; uint64_t rdpmc_slots, rdpmc_metrics; int EventSet1 = PAPI_NULL; long long values[NUM_EVENTS]; @@ -252,8 +252,11 @@ int main(int argc, char **argv) /* now lets run our tests */ failures = 0; + mismatches = 0; for (j = 0; j < NUM_TESTS; j++) { + printf("Loop #%d:\n", j); + /* make sure the metrics are cleared */ reset_metrics(slots_fd); reset_metrics(metrics_fd); @@ -293,6 +296,15 @@ int main(int argc, char **argv) for (i = 0; i < NUM_EVENTS; i++) avg_papi_event_percs[i] += papi_event_percs[i]; + /* check if the values are identical (for rdpmc enabled, they should be) */ + if (!(values[1] == values[2] && values[2] == values[3])) + { + printf("Values mismatch!\n"); + mismatches++; + } + + + /* check that the percentages match _rdpmc syscall */ if ((are_percs_equivalent(rdpmc_percs, papi_rdpmc_percs, err_papi_rdpmc_percs, NUM_EVENTS) + are_percs_equivalent(rdpmc_percs, papi_event_percs, err_papi_event_percs, NUM_EVENTS)) < 1) { @@ -331,6 +343,7 @@ int main(int argc, char **argv) printf("Averaged percentages for PAPI events:\n"); print_percs(avg_papi_event_percs); + printf("There were %d mismatches\n", mismatches); printf("There were %d failures\n", failures); if (failures > 0) { From 2b5a7442543f25d1d74a9d3969a374ac9e954fd4 Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Fri, 30 Aug 2024 10:34:11 -0400 Subject: [PATCH 09/20] validation_tests: separated _rdpmc and papi reads in topdown_validation so that papi doesnt pollute rdpmc --- src/validation_tests/topdown_validation.c | 46 ++++++++++++++--------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index 28785cb49..1a5aa71f0 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -21,8 +21,7 @@ #include #define NUM_EVENTS 4 -#define NUM_LOOPS 100 -#define NUM_TESTS 100 +#define NUM_TESTS 1 #define PERCENTAGES_TOLERANCE 0.1 @@ -122,6 +121,21 @@ int are_percs_equivalent(double *percs_gt, double *percs_b, double *abs_error, i return eq; } +// fibbonacci function +int fib(int n) +{ + long i, a = 0; + int b = 1; + for (i=0; i Date: Fri, 30 Aug 2024 13:49:14 -0400 Subject: [PATCH 10/20] topdown_validation: added macro to select what test to run in topdown_validation While investigating the topdown rdpmc issues, it made sense to have more than one type of code to test. This was later removed once the issue was identified and resolved. --- src/validation_tests/topdown_validation.c | 41 ++++++++++++++++------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index 1a5aa71f0..a37a90d8a 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -22,6 +22,7 @@ #define NUM_EVENTS 4 #define NUM_TESTS 1 +#define TEST_FIB 0 // select whether to make teh test fib() or instructions_million() #define PERCENTAGES_TOLERANCE 0.1 @@ -233,22 +234,22 @@ int main(int argc, char **argv) test_skip(__FILE__, __LINE__, "adding TOPDOWN:RETIRING_SLOTS", retval); } - /* Add TOPDOWN:BACKEND_BOUND_SLOTS */ - retval = PAPI_add_named_event(EventSet1, "TOPDOWN:BACKEND_BOUND_SLOTS"); + /* Add TOPDOWN:BAD_SPEC_SLOTS */ + retval = PAPI_add_named_event(EventSet1, "TOPDOWN:BAD_SPEC_SLOTS"); if (retval != PAPI_OK) { if (!quiet) - printf("Trouble adding TOPDOWN:BACKEND_BOUND_SLOTS\n"); - test_skip(__FILE__, __LINE__, "adding TOPDOWN:BACKEND_BOUND_SLOTS", retval); + printf("Trouble adding TOPDOWN:BAD_SPEC_SLOTS\n"); + test_skip(__FILE__, __LINE__, "adding TOPDOWN:BAD_SPEC_SLOTS", retval); } - /* Add TOPDOWN:BAD_SPEC_SLOTS */ - retval = PAPI_add_named_event(EventSet1, "TOPDOWN:BAD_SPEC_SLOTS"); + /* Add TOPDOWN:BACKEND_BOUND_SLOTS */ + retval = PAPI_add_named_event(EventSet1, "TOPDOWN:BACKEND_BOUND_SLOTS"); if (retval != PAPI_OK) { if (!quiet) - printf("Trouble adding TOPDOWN:BAD_SPEC_SLOTS\n"); - test_skip(__FILE__, __LINE__, "adding TOPDOWN:BAD_SPEC_SLOTS", retval); + printf("Trouble adding TOPDOWN:BACKEND_BOUND_SLOTS\n"); + test_skip(__FILE__, __LINE__, "adding TOPDOWN:BACKEND_BOUND_SLOTS", retval); } /* warm up the processor to pull it out of idle state */ @@ -275,29 +276,43 @@ int main(int argc, char **argv) reset_metrics(slots_fd); reset_metrics(metrics_fd); +#if TEST_FIB printf("fib: %d\n", fib(6000000)); - +#else + for (i = 0; i < 100; i++) + { + result = instructions_million(); + } +#endif + /* Check and see what _rdpmc got */ rdpmc_slots = read_slots(); rdpmc_metrics = read_metrics(); topdown_get_from_metrics(rdpmc_percs, rdpmc_metrics); + for (i = 0; i < NUM_EVENTS; i++) + avg_rdpmc_percs[i] += rdpmc_percs[i]; + /* Stat the test with PAPI */ retval = PAPI_start(EventSet1); if (retval != PAPI_OK) { test_fail(__FILE__, __LINE__, "PAPI_start", retval); } - +#if TEST_FIB printf("fib: %d\n", fib(6000000)); - +#else + for (i = 0; i < 100; i++) + { + result = instructions_million(); + } +#endif + retval = PAPI_stop(EventSet1, values); if (retval != PAPI_OK) { test_fail(__FILE__, __LINE__, "PAPI_stop", retval); } - for (i = 0; i < NUM_EVENTS; i++) - avg_rdpmc_percs[i] += rdpmc_percs[i]; /* Lets see what we got with PAPI rdpmc */ topdown_get_from_metrics(papi_rdpmc_percs, values[1]); From 6da16c077e1008ed6c3a2640a1f98b209e4e22f8 Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Fri, 30 Aug 2024 13:56:33 -0400 Subject: [PATCH 11/20] validation_tests: increased tolerance for percentages in topdown_validation to +-1.5 --- src/validation_tests/topdown_validation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index a37a90d8a..9e2e7561b 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -21,10 +21,10 @@ #include #define NUM_EVENTS 4 -#define NUM_TESTS 1 +#define NUM_TESTS 100 #define TEST_FIB 0 // select whether to make teh test fib() or instructions_million() -#define PERCENTAGES_TOLERANCE 0.1 +#define PERCENTAGES_TOLERANCE 1.5 /* * perf_event _rdpmc code From 5b293627dbc4416b92e3fa9aac99cd5798fa5d3d Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Tue, 3 Sep 2024 10:55:57 -0400 Subject: [PATCH 12/20] validation_tests: fixed error calculation bug in topdown_validation The tolerance for percentage comparisons was also raised to +-2.5, as there is often a decent amount of error when rdpmc is disabled. 2.5 percentage points is wide enough to account for that noise while still being tight enough to ensure the values are reasonable. --- src/validation_tests/topdown_validation.c | 27 +++++++++++------------ 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index 9e2e7561b..d6f91a928 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -22,9 +22,9 @@ #define NUM_EVENTS 4 #define NUM_TESTS 100 -#define TEST_FIB 0 // select whether to make teh test fib() or instructions_million() +#define TEST_FIB 1 // select whether to make teh test fib() or instructions_million() -#define PERCENTAGES_TOLERANCE 1.5 +#define PERCENTAGES_TOLERANCE 2.5 // +- range of percentage points for success /* * perf_event _rdpmc code @@ -114,9 +114,10 @@ int are_percs_equivalent(double *percs_gt, double *percs_b, double *abs_error, i { if (!eq_within_tolerance(percs_gt[i], percs_b[i], PERCENTAGES_TOLERANCE)) { - abs_error[i] = (percs_gt[i] - percs_b[i] > 0) ? percs_gt[i] - percs_b[i] : percs_b[i] - percs_gt[i]; eq = 0; } + abs_error[i] = (percs_gt[i] - percs_b[i] > 0) ? percs_gt[i] - percs_b[i] : percs_b[i] - percs_gt[i]; + } return eq; @@ -270,16 +271,15 @@ int main(int argc, char **argv) mismatches = 0; for (j = 0; j < NUM_TESTS; j++) { - printf("Loop #%d:\n", j); - /* Stat the test with _rdpmc() */ reset_metrics(slots_fd); reset_metrics(metrics_fd); #if TEST_FIB - printf("fib: %d\n", fib(6000000)); + retval = fib(6000000); + printf("fib: %d\n", retval); #else - for (i = 0; i < 100; i++) + for (i = 0; i < 1000; i++) { result = instructions_million(); } @@ -300,9 +300,10 @@ int main(int argc, char **argv) test_fail(__FILE__, __LINE__, "PAPI_start", retval); } #if TEST_FIB - printf("fib: %d\n", fib(6000000)); + retval = fib(6000000); + printf("fib: %d\n", retval); #else - for (i = 0; i < 100; i++) + for (i = 0; i < 1000; i++) { result = instructions_million(); } @@ -327,7 +328,6 @@ int main(int argc, char **argv) /* check if the values are identical (for rdpmc enabled, they should be) */ if (!(values[1] == values[2] && values[2] == values[3])) { - printf("Values mismatch!\n"); mismatches++; } @@ -335,14 +335,13 @@ int main(int argc, char **argv) if ((are_percs_equivalent(rdpmc_percs, papi_rdpmc_percs, err_papi_rdpmc_percs, NUM_EVENTS) + are_percs_equivalent(rdpmc_percs, papi_event_percs, err_papi_event_percs, NUM_EVENTS)) < 1) { - printf("Failed: %#0x\n", values[1]); - - printf("rdpmc err: "); + printf("Failed:\n"); + printf("\trdpmc err: "); for (i = 0; i < NUM_EVENTS; i++) { printf("%f\t", err_papi_rdpmc_percs[i]); } - printf("\nevent err: "); + printf("\n\tevent err: "); for (i = 0; i < NUM_EVENTS; i++) { printf("%f\t", err_papi_event_percs[i]); From 2f15a8d212563fafe18f5c122118b1c569b6fc73 Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Tue, 10 Sep 2024 10:32:05 -0400 Subject: [PATCH 13/20] libpfm4: added missing topdown events for intel_adl_glc_events.h Added three missing topdown events to libpfm4 in order to enable level 2 event collection with rdpmc disabled. The missing events were TOPDOWN.FRONTEND_BOUND_SLOTS, TOPDOWN.HEAVY_OPS_SLOTS, and TOPDOWN.FETCH_LAT_SLOTS. This commit has also been submitted to libpfm4 as a patch. --- src/libpfm4/lib/events/intel_adl_glc_events.h | 15 ++++++++++ src/validation_tests/topdown_validation.c | 30 +++++++++++-------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/libpfm4/lib/events/intel_adl_glc_events.h b/src/libpfm4/lib/events/intel_adl_glc_events.h index e6cf505d1..805c5ad9b 100644 --- a/src/libpfm4/lib/events/intel_adl_glc_events.h +++ b/src/libpfm4/lib/events/intel_adl_glc_events.h @@ -1566,6 +1566,21 @@ static const intel_x86_umask_t adl_glc_topdown[]={ .ucode = 0x8000ull, .uflags = INTEL_X86_NCOMBO, }, + { .uname = "FRONTEND_BOUND_SLOTS", + .udesc = "TODO", + .ucode = 0x8200ull, + .uflags = INTEL_X86_NCOMBO, + }, + { .uname = "HEAVY_OPS_SLOTS", + .udesc = "TODO", + .ucode = 0x8400ull, + .uflags = INTEL_X86_NCOMBO, + }, + { .uname = "FETCH_LAT_SLOTS", + .udesc = "TODO", + .ucode = 0x8700ull, + .uflags = INTEL_X86_NCOMBO, + }, { .uname = "SLOTS", .udesc = "TMA slots available for an unhalted logical processor. Fixed counter - architectural event", .ucode = 0x0400ull, diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index d6f91a928..bac60f933 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -20,9 +20,9 @@ #include #include -#define NUM_EVENTS 4 +#define NUM_EVENTS 5 #define NUM_TESTS 100 -#define TEST_FIB 1 // select whether to make teh test fib() or instructions_million() +#define TEST_FIB 1 // select whether to make the test fib() or instructions_million() #define PERCENTAGES_TOLERANCE 2.5 // +- range of percentage points for success @@ -33,7 +33,7 @@ #define RDPMC_FIXED (1 << 30) /* return fixed counters */ #define RDPMC_METRIC (1 << 29) /* return metric counters */ -#define FIXED_COUNTER_SLOTS 3 /* on raptorlake it is fiex counter 3 */ +#define FIXED_COUNTER_SLOTS 3 /* on raptorlake it is fixed counter 3 */ #define METRIC_COUNTER_TOPDOWN_L1_L2 0 __attribute__((weak)) int perf_event_open(struct perf_event_attr *attr, pid_t pid, @@ -72,7 +72,7 @@ float rdpmc_get_metric(u_int64_t m, int i) return (float)(((m) >> (i * 8)) & 0xff) / 0xff * 100.0; } -/* takes a metric integer and populates the array with individual percentages */ +/* takes a metric value and populates the array with individual percentages */ /* in order: retiring, bad spec, fe bound, be bound */ void topdown_get_from_metrics(double *percentages, uint64_t metrics) { @@ -89,7 +89,9 @@ void topdown_get_from_events(double *percentages, uint64_t slots, uint64_t retir percentages[0] = (double)retiring / (double)slots * 100.0; percentages[1] = (double)badspec / (double)slots * 100.0; percentages[3] = (double)be_bound / (double)slots * 100.0; - percentages[2] = 100.0 - percentages[0] - percentages[1] - percentages[3]; + + // TODO: Once libpfm4 adds the frontend_bound event, use that instead + percentages[2] = 100.0 - percentages[0] - percentages[1] - percentages[3]; } void print_percs(double *percs) @@ -143,7 +145,7 @@ int main(int argc, char **argv) // Set up and call the topdown events // Then parse as percentages and ensure it makes some sense - int retval, tmp, result, i, j, failures, mismatches; + int retval, tmp, result, i, j, failures; uint64_t rdpmc_slots, rdpmc_metrics; int EventSet1 = PAPI_NULL; long long values[NUM_EVENTS]; @@ -244,6 +246,15 @@ int main(int argc, char **argv) test_skip(__FILE__, __LINE__, "adding TOPDOWN:BAD_SPEC_SLOTS", retval); } + /* Add TOPDOWN:FRONTEND_BOUND_SLOTS */ + retval = PAPI_add_named_event(EventSet1, "TOPDOWN:FRONTEND_BOUND_SLOTS"); + if (retval != PAPI_OK) + { + if (!quiet) + printf("Trouble adding TOPDOWN:FRONTEND_BOUND_SLOTS\n"); + test_skip(__FILE__, __LINE__, "adding TOPDOWN:FRONTEND_BOUND_SLOTS", retval); + } + /* Add TOPDOWN:BACKEND_BOUND_SLOTS */ retval = PAPI_add_named_event(EventSet1, "TOPDOWN:BACKEND_BOUND_SLOTS"); if (retval != PAPI_OK) @@ -325,12 +336,6 @@ int main(int argc, char **argv) for (i = 0; i < NUM_EVENTS; i++) avg_papi_event_percs[i] += papi_event_percs[i]; - /* check if the values are identical (for rdpmc enabled, they should be) */ - if (!(values[1] == values[2] && values[2] == values[3])) - { - mismatches++; - } - /* check that the percentages match _rdpmc syscall */ if ((are_percs_equivalent(rdpmc_percs, papi_rdpmc_percs, err_papi_rdpmc_percs, NUM_EVENTS) + are_percs_equivalent(rdpmc_percs, papi_event_percs, err_papi_event_percs, NUM_EVENTS)) < 1) @@ -367,7 +372,6 @@ int main(int argc, char **argv) printf("Averaged percentages for PAPI events:\n"); print_percs(avg_papi_event_percs); - printf("There were %d mismatches\n", mismatches); printf("There were %d failures\n", failures); if (failures > 0) { From 05a9001ec5a927220cafe0b2f71038c6993ec554 Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Tue, 10 Sep 2024 15:20:51 -0400 Subject: [PATCH 14/20] validation_tests: refactored topdown_validation to enable the testing of topdown L2 events --- src/validation_tests/topdown_validation.c | 384 +++++++++++----------- 1 file changed, 185 insertions(+), 199 deletions(-) diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index bac60f933..742991b3a 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -21,8 +21,7 @@ #include #define NUM_EVENTS 5 -#define NUM_TESTS 100 -#define TEST_FIB 1 // select whether to make the test fib() or instructions_million() +#define NUM_TESTS 1 #define PERCENTAGES_TOLERANCE 2.5 // +- range of percentage points for success @@ -30,10 +29,13 @@ * perf_event _rdpmc code */ +#define SLOTS 0x0400ull +#define METRICS 0x8000ull + #define RDPMC_FIXED (1 << 30) /* return fixed counters */ #define RDPMC_METRIC (1 << 29) /* return metric counters */ -#define FIXED_COUNTER_SLOTS 3 /* on raptorlake it is fixed counter 3 */ +#define FIXED_COUNTER_SLOTS 3 #define METRIC_COUNTER_TOPDOWN_L1_L2 0 __attribute__((weak)) int perf_event_open(struct perf_event_attr *attr, pid_t pid, @@ -47,16 +49,12 @@ static inline uint64_t read_slots(void) return _rdpmc(RDPMC_FIXED | FIXED_COUNTER_SLOTS); } -/* -The value reported by read_metrics() contains four 8 bit fields -that represent a scaled ratio that represent the Level 1 bottleneck. -All four fields add up to 0xff (= 100%) -*/ static inline uint64_t read_metrics(void) { return _rdpmc(RDPMC_METRIC | METRIC_COUNTER_TOPDOWN_L1_L2); } +// clears event metrics static inline int reset_metrics(int fd) { return ioctl(fd, PERF_EVENT_IOC_RESET, 0); @@ -72,34 +70,13 @@ float rdpmc_get_metric(u_int64_t m, int i) return (float)(((m) >> (i * 8)) & 0xff) / 0xff * 100.0; } -/* takes a metric value and populates the array with individual percentages */ -/* in order: retiring, bad spec, fe bound, be bound */ -void topdown_get_from_metrics(double *percentages, uint64_t metrics) -{ - percentages[0] = rdpmc_get_metric(metrics, 0); - percentages[1] = rdpmc_get_metric(metrics, 1); - percentages[2] = rdpmc_get_metric(metrics, 2); - percentages[3] = rdpmc_get_metric(metrics, 3); -} - -/* takes papi events and populates the array with individual percentages */ -/* in order: retiring, bad spec, fe bound, be bound */ -void topdown_get_from_events(double *percentages, uint64_t slots, uint64_t retiring, uint64_t badspec, uint64_t be_bound) -{ - percentages[0] = (double)retiring / (double)slots * 100.0; - percentages[1] = (double)badspec / (double)slots * 100.0; - percentages[3] = (double)be_bound / (double)slots * 100.0; - - // TODO: Once libpfm4 adds the frontend_bound event, use that instead - percentages[2] = 100.0 - percentages[0] - percentages[1] - percentages[3]; -} - void print_percs(double *percs) { - printf("\tretiring:\t%02f\n\tbadspec:\t%02f\n\tfe_bound:\t%02f\n\tbe_bound:\t%02f\n", + printf("retiring: %.02f\tbadspec: %.02f fe_bound: %.02f\tbe_bound: %.02f\n", percs[0], percs[1], percs[2], percs[3]); } +// returns one if a and b are within the tolerance of each other int eq_within_tolerance(double a, double b, double tolerance) { if (a + tolerance >= b && a - tolerance <= b) @@ -108,6 +85,7 @@ int eq_within_tolerance(double a, double b, double tolerance) return 0; } +// returns 1 if the percentages are within PERCENTAGES_TOLERANCE of each other int are_percs_equivalent(double *percs_gt, double *percs_b, double *abs_error, int n_percs) { int i; @@ -119,67 +97,62 @@ int are_percs_equivalent(double *percs_gt, double *percs_b, double *abs_error, i eq = 0; } abs_error[i] = (percs_gt[i] - percs_b[i] > 0) ? percs_gt[i] - percs_b[i] : percs_b[i] - percs_gt[i]; - } return eq; } -// fibbonacci function -int fib(int n) +int main(int argc, char **argv) { - long i, a = 0; - int b = 1; - for (i=0; i 0) + /* warm up the processor to pull it out of idle state */ + for (i = 0; i < 100; i++) { - test_fail(__FILE__, __LINE__, "Papi results did not match perf results at least once", 1); + ret = instructions_million(); + } + if (ret == CODE_UNIMPLEMENTED) + { + if (!quiet) + printf("Instructions testcode not available\n"); + test_skip(__FILE__, __LINE__, "No instructions code", ret); } - /* Clean up everything */ - close(slots_fd); - close(metrics_fd); + /*************************/ + /* Run some test code */ + /*************************/ - retval = PAPI_cleanup_eventset(EventSet1); - if (retval != PAPI_OK) + // test Level 1 topdown events + for (i = 0; i < NUM_TESTS; i++) { - test_fail(__FILE__, __LINE__, "PAPI_cleanup_eventset", retval); + // first get the ground truth (perf_event rdpmc) + reset_metrics(metrics_fd); + for (j = 0; j < 100; j++) + ret = instructions_million(); + slots_val = read_slots(); + metrics_val = read_metrics(); + + // then try out papi + PAPI_start(EventSetL1); + for (j = 0; j < 100; j++) + ret = instructions_million(); + PAPI_stop(EventSetL1, values); + + // get percentages from perf_event rdpmc + printf("perf_event: "); + for (j = 0; j < 4; j++) + { + percs_perf_rdpmc[j] = rdpmc_get_metric(metrics_val, j); + } + print_percs(percs_perf_rdpmc); + + // get percentages from papi_event (assuming rdpmc) + printf("papi_rdpmc: "); + for (j = 1; j < NUM_EVENTS; j++) + { + percs_papi_rdpmc[j] = rdpmc_get_metric(values[j], j); + } + print_percs(percs_papi_rdpmc); + + // get percentages from papi_event (assuming non-rdpmc) + printf("papi_event: "); + for (j = 1; j < NUM_EVENTS; j++) + { + //printf("%llu\t", values[j]); + percs_papi_event[j-1] = (double)values[j] / (double)values[0] * 100.0; + } + print_percs(percs_papi_event); } - retval = PAPI_destroy_eventset(&EventSet1); - if (retval != PAPI_OK) + + return 0; + // test Level 2 topdown events + for (i = 0; i < NUM_TESTS; i++) { - test_fail(__FILE__, __LINE__, "PAPI_destroy_eventset", retval); + // first get the ground truth (perf_event rdpmc) + reset_metrics(metrics_fd); + + for (j = 0; j < 100; j++) + ret = instructions_million(); + + slots_val = read_slots(); + metrics_val = read_metrics(); + + // then try out papi + PAPI_start(EventSetL1); + for (j = 0; j < 100; j++) + ret = instructions_million(); + PAPI_stop(EventSetL1, values); } } From 2e8260bb3945d866d3bfaaf5a4da196731e93b44 Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Tue, 10 Sep 2024 15:39:43 -0400 Subject: [PATCH 15/20] validation_tests: finished rewriting topdown_validation to test both L1 and L2 events --- src/validation_tests/topdown_validation.c | 73 ++++++++++++++++++----- 1 file changed, 57 insertions(+), 16 deletions(-) diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index 742991b3a..6dd3ee699 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -21,9 +21,9 @@ #include #define NUM_EVENTS 5 -#define NUM_TESTS 1 +#define NUM_TESTS 100 -#define PERCENTAGES_TOLERANCE 2.5 // +- range of percentage points for success +#define PERCENTAGES_TOLERANCE 1.5 // +- range of percentage points for success /* * perf_event _rdpmc code @@ -114,6 +114,8 @@ int main(int argc, char **argv) double percs_perf_rdpmc[4] = {0, 0, 0, 0}; double percs_papi_event[4] = {0, 0, 0, 0}; double percs_papi_rdpmc[4] = {0, 0, 0, 0}; + double papi_event_error[4] = {0, 0, 0, 0}; + double papi_rdpmc_error[4] = {0, 0, 0, 0}; long long values[NUM_EVENTS]; @@ -317,7 +319,9 @@ int main(int argc, char **argv) /* Run some test code */ /*************************/ + failures = 0; // test Level 1 topdown events + printf("Testing L1 Topdown Events\n"); for (i = 0; i < NUM_TESTS; i++) { // first get the ground truth (perf_event rdpmc) @@ -334,33 +338,39 @@ int main(int argc, char **argv) PAPI_stop(EventSetL1, values); // get percentages from perf_event rdpmc - printf("perf_event: "); for (j = 0; j < 4; j++) { percs_perf_rdpmc[j] = rdpmc_get_metric(metrics_val, j); } - print_percs(percs_perf_rdpmc); // get percentages from papi_event (assuming rdpmc) - printf("papi_rdpmc: "); - for (j = 1; j < NUM_EVENTS; j++) + for (j = 0; j < NUM_EVENTS-1; j++) { - percs_papi_rdpmc[j] = rdpmc_get_metric(values[j], j); + percs_papi_rdpmc[j] = rdpmc_get_metric(values[j+1], j); } - print_percs(percs_papi_rdpmc); // get percentages from papi_event (assuming non-rdpmc) - printf("papi_event: "); - for (j = 1; j < NUM_EVENTS; j++) + for (j = 0; j < NUM_EVENTS-1; j++) { - //printf("%llu\t", values[j]); - percs_papi_event[j-1] = (double)values[j] / (double)values[0] * 100.0; + percs_papi_event[j] = (double)values[j+1] / (double)values[0] * 100.0; } - print_percs(percs_papi_event); + + // if neither result matches perf_event rdpmc, we fail + if (are_percs_equivalent(percs_perf_rdpmc, percs_papi_rdpmc, papi_rdpmc_error, 4) + + are_percs_equivalent(percs_perf_rdpmc, percs_papi_event, papi_event_error, 4) < 1) { + failures++; + printf("rdpmc error - "); + print_percs(papi_rdpmc_error); + printf("event error - "); + print_percs(papi_event_error); + } } - return 0; + printf("\tPassed %d/%d tests\n", NUM_TESTS-failures, NUM_TESTS); + + failures = 0; // test Level 2 topdown events + printf("Testing L2 Topdown Events\n"); for (i = 0; i < NUM_TESTS; i++) { // first get the ground truth (perf_event rdpmc) @@ -373,9 +383,40 @@ int main(int argc, char **argv) metrics_val = read_metrics(); // then try out papi - PAPI_start(EventSetL1); + PAPI_start(EventSetL2); for (j = 0; j < 100; j++) ret = instructions_million(); - PAPI_stop(EventSetL1, values); + PAPI_stop(EventSetL2, values); + + // get percentages from perf_event rdpmc + for (j = 0; j < 4; j++) + { + percs_perf_rdpmc[j] = rdpmc_get_metric(metrics_val, j+4); + } + + // get percentages from papi_event (assuming rdpmc) + for (j = 0; j < NUM_EVENTS-1; j++) + { + percs_papi_rdpmc[j] = rdpmc_get_metric(values[j+1], j+4); + } + + // get percentages from papi_event (assuming non-rdpmc) + for (j = 0; j < NUM_EVENTS-1; j++) + { + percs_papi_event[j] = (double)values[j+1] / (double)values[0] * 100.0; + } + + // if neither result matches perf_event rdpmc, we fail + if (are_percs_equivalent(percs_perf_rdpmc, percs_papi_rdpmc, papi_rdpmc_error, 4) + + are_percs_equivalent(percs_perf_rdpmc, percs_papi_event, papi_event_error, 4) < 1) { + failures++; + printf("rdpmc error - "); + print_percs(papi_rdpmc_error); + printf("event error - "); + print_percs(papi_event_error); + } } + + printf("\tPassed %d/%d tests\n", NUM_TESTS-failures, NUM_TESTS); + } From 0346ad01936add1f5b3ef2df6a3b63226e6a9471 Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Tue, 10 Sep 2024 16:39:39 -0400 Subject: [PATCH 16/20] libpfm4: added descriptions for the missing topdown events to intel_adl_glc_events.h --- src/libpfm4/lib/events/intel_adl_glc_events.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libpfm4/lib/events/intel_adl_glc_events.h b/src/libpfm4/lib/events/intel_adl_glc_events.h index 805c5ad9b..5132a7176 100644 --- a/src/libpfm4/lib/events/intel_adl_glc_events.h +++ b/src/libpfm4/lib/events/intel_adl_glc_events.h @@ -1552,12 +1552,12 @@ static const intel_x86_umask_t adl_glc_topdown[]={ .uflags = INTEL_X86_NCOMBO, }, { .uname = "BR_MISPREDICT_SLOTS", - .udesc = "TMA slots wasted due to incorrect speculation by branch mispredictions", + .udesc = "TMA slots wasted due to incorrect speculation by branch mispredictions (Topdown L2)", .ucode = 0x8500ull, .uflags = INTEL_X86_NCOMBO, }, { .uname = "MEMORY_BOUND_SLOTS", - .udesc = "TMA slots wasted due to memory accesses (TopdownL2)", + .udesc = "TMA slots wasted due to memory accesses (Topdown L2)", .ucode = 0x8700ull, .uflags = INTEL_X86_NCOMBO, }, @@ -1567,18 +1567,18 @@ static const intel_x86_umask_t adl_glc_topdown[]={ .uflags = INTEL_X86_NCOMBO, }, { .uname = "FRONTEND_BOUND_SLOTS", - .udesc = "TODO", + .udesc = "TMA slots where the front-end did not deliver uops (Topdown L1)", .ucode = 0x8200ull, .uflags = INTEL_X86_NCOMBO, }, { .uname = "HEAVY_OPS_SLOTS", - .udesc = "TODO", + .udesc = "TMA slots where heavy-weight instructions are retiring (Topdown L2)", .ucode = 0x8400ull, .uflags = INTEL_X86_NCOMBO, }, { .uname = "FETCH_LAT_SLOTS", - .udesc = "TODO", - .ucode = 0x8700ull, + .udesc = "TMA slots wasted due to front-end latency issues (Topdown L2)", + .ucode = 0x8600ull, .uflags = INTEL_X86_NCOMBO, }, { .uname = "SLOTS", From 37e9d4da72d6c6655711ab8568e00c84f4fcb3ea Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Tue, 10 Sep 2024 16:40:07 -0400 Subject: [PATCH 17/20] validation_tests: added test_pass call to topdown_validation --- src/components/perf_event/perf_event.c | 2 +- src/validation_tests/topdown_validation.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/perf_event/perf_event.c b/src/components/perf_event/perf_event.c index c8efefb33..262a5f108 100644 --- a/src/components/perf_event/perf_event.c +++ b/src/components/perf_event/perf_event.c @@ -1468,7 +1468,7 @@ _pe_start( hwd_context_t *ctx, hwd_control_state_t *ctl ) ret=ioctl( pe_ctl->events[i].event_fd, PERF_EVENT_IOC_ENABLE, NULL) ; if (_perf_event_vector.cmp_info.fast_counter_read) { - pe_ctl->reset_counts[i] = 0LL; + //pe_ctl->reset_counts[i] = 0LL; //pe_ctl->reset_flag = 0; } diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index 6dd3ee699..fa9daad75 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -419,4 +419,8 @@ int main(int argc, char **argv) printf("\tPassed %d/%d tests\n", NUM_TESTS-failures, NUM_TESTS); -} + test_pass( __FILE__ ); + + return 0; + +} \ No newline at end of file From 2f80b9be333ea17d29eaa7f19d2bd63f4ae6769e Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Wed, 11 Sep 2024 16:05:24 -0400 Subject: [PATCH 18/20] papi_events: added patch that includes preset events for adl_glc top papi_events.csv Because this fix for topdown events was developed on an intel raptorlake machine, preset events needed to be added in order to run the validation tests with make fulltest --- src/papi_events.csv | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/papi_events.csv b/src/papi_events.csv index 5ff4b8373..8f44de071 100644 --- a/src/papi_events.csv +++ b/src/papi_events.csv @@ -979,6 +979,8 @@ PRESET,PAPI_CA_ITV,NOT_DERIVED,OFFCORE_RESPONSE_0:SNP_HIT_WITH_FWD # Intel Ice Lake SP events CPU,icx CPU,icl +# Note: Many Ice Lake events work for Alderlake/Raptorlake P-Core +CPU,adl_glc PRESET,PAPI_TOT_CYC,NOT_DERIVED,CPU_CLK_UNHALTED:THREAD_P PRESET,PAPI_TOT_INS,NOT_DERIVED,INST_RETIRED:ANY_P PRESET,PAPI_REF_CYC,NOT_DERIVED,UNHALTED_REFERENCE_CYCLES @@ -991,18 +993,15 @@ PRESET,PAPI_L1_ICM,NOT_DERIVED,L2_RQSTS:ALL_CODE_RD PRESET,PAPI_L1_DCM,NOT_DERIVED,L1D:REPLACEMENT PRESET,PAPI_L1_TCM,DERIVED_ADD,L1D:REPLACEMENT,L2_RQSTS:ALL_CODE_RD # L2 cache -PRESET,PAPI_L2_DCA,NOT_DERIVED,L2_RQSTS:ALL_DEMAND_REFERENCES PRESET,PAPI_L2_DCR,NOT_DERIVED,L2_RQSTS:ALL_DEMAND_DATA_RD PRESET,PAPI_L2_ICH,NOT_DERIVED,L2_RQSTS:CODE_RD_HIT PRESET,PAPI_L2_ICM,NOT_DERIVED,L2_RQSTS:CODE_RD_MISS PRESET,PAPI_L2_ICR,NOT_DERIVED,L2_RQSTS:ALL_CODE_RD #PRESET,PAPI_L2_TCH,NOT_DERIVED,MEM_LOAD_UOPS_RETIRED:L2_HIT #PRESET,PAPI_L2_TCM,NOT_DERIVED,MEM_LOAD_UOPS_RETIRED:L2_MISS -PRESET,PAPI_L2_DCM,DERIVED_SUB,LLC_REFERENCES,L2_RQSTS:CODE_RD_MISS PRESET,PAPI_L2_ICA,NOT_DERIVED,L2_RQSTS:ALL_CODE_RD #PRESET,PAPI_L2_LDH,NOT_DERIVED,L2_RQSTS:DEMAND_DATA_RD_HIT PRESET,PAPI_L2_LDM,NOT_DERIVED,L2_RQSTS:DEMAND_DATA_RD_MISS -PRESET,PAPI_L2_TCA,DERIVED_ADD,L2_RQSTS:ALL_DEMAND_REFERENCES,L2_RQSTS:ALL_CODE_RD PRESET,PAPI_L2_TCM,NOT_DERIVED,LLC_REFERENCES PRESET,PAPI_L2_TCR,DERIVED_ADD,L2_RQSTS:ALL_DEMAND_DATA_RD,L2_RQSTS:ALL_CODE_RD # L3 cache @@ -1014,8 +1013,6 @@ PRESET,PAPI_L3_ICR,NOT_DERIVED,L2_RQSTS:CODE_RD_MISS PRESET,PAPI_L3_LDM,NOT_DERIVED,MEM_LOAD_RETIRED:L3_MISS PRESET,PAPI_L3_TCA,NOT_DERIVED,LLC_REFERENCES PRESET,PAPI_L3_TCM,NOT_DERIVED,LLC_MISSES -# SMP -PRESET,PAPI_CA_SHR,NOT_DERIVED,OFFCORE_REQUESTS:ALL_DATA_RD # Branches PRESET,PAPI_BR_UCN,DERIVED_SUB,BR_INST_RETIRED:ALL_BRANCHES,BR_INST_RETIRED:COND PRESET,PAPI_BR_CN,NOT_DERIVED,BR_INST_RETIRED:COND @@ -1024,6 +1021,15 @@ PRESET,PAPI_BR_NTK,NOT_DERIVED,BR_INST_RETIRED:COND_NTAKEN PRESET,PAPI_BR_MSP,NOT_DERIVED,BR_MISP_RETIRED:COND PRESET,PAPI_BR_PRC,DERIVED_SUB,BR_INST_RETIRED:COND,BR_MISP_RETIRED:COND PRESET,PAPI_BR_INS,NOT_DERIVED,BR_INST_RETIRED:ALL_BRANCHES + +CPU,icx +CPU,icl +# L2 +PRESET,PAPI_L2_DCA,NOT_DERIVED,L2_RQSTS:ALL_DEMAND_REFERENCES +PRESET,PAPI_L2_TCA,DERIVED_ADD,L2_RQSTS:ALL_DEMAND_REFERENCES,L2_RQSTS:ALL_CODE_RD +PRESET,PAPI_L2_DCM,DERIVED_SUB,LLC_REFERENCES,L2_RQSTS:CODE_RD_MISS +# SMP +PRESET,PAPI_CA_SHR,NOT_DERIVED,OFFCORE_REQUESTS:ALL_DATA_RD #FLOPs # PAPI_DP_OPS = FP_ARITH:SCALAR_DOUBLE + 2*FP_ARITH:128B_PACKED_DOUBLE + 4*256B_PACKED_DOUBLE + 8*512B_PACKED_DOUBLE PRESET,PAPI_DP_OPS,DERIVED_POSTFIX,N0|N1|2|*|+|N2|4|*|+|N3|8|*|+|,FP_ARITH:SCALAR_DOUBLE,FP_ARITH:128B_PACKED_DOUBLE,FP_ARITH:256B_PACKED_DOUBLE,FP_ARITH:512B_PACKED_DOUBLE @@ -1034,7 +1040,23 @@ PRESET,PAPI_FP_INS,DERIVED_POSTFIX,N0|N1|N2|N3|N4|N5|N6|N7|+|+|+|+|+|+|+|,FP_ARI PRESET,PAPI_VEC_DP,DERIVED_POSTFIX,N0|N1|N2|N3|+|+|+|,FP_ARITH:SCALAR_DOUBLE,FP_ARITH:128B_PACKED_DOUBLE,FP_ARITH:256B_PACKED_DOUBLE,FP_ARITH:512B_PACKED_DOUBLE PRESET,PAPI_VEC_SP,DERIVED_POSTFIX,N0|N1|N2|N3|+|+|+|,FP_ARITH:SCALAR_SINGLE,FP_ARITH:128B_PACKED_SINGLE,FP_ARITH:256B_PACKED_SINGLE,FP_ARITH:512B_PACKED_SINGLE PRESET,PAPI_VEC_INS,DERIVED_POSTFIX,N0|N1|N2|N3|N4|N5|+|+|+|+|+|,FP_ARITH_INST_RETIRED:128B_PACKED_SINGLE,FP_ARITH_INST_RETIRED:256B_PACKED_SINGLE,FP_ARITH_INST_RETIRED:512B_PACKED_SINGLE,FP_ARITH_INST_RETIRED:128B_PACKED_DOUBLE,FP_ARITH_INST_RETIRED:256B_PACKED_DOUBLE,FP_ARITH_INST_RETIRED:512B_PACKED_DOUBLE -# End of icx, icl list + +CPU,adl_glc +# L2 +#PRESET,PAPI_L2_DCA,NOT_DERIVED,DERIVED_SUB,L2_RQSTS.REFERENCES,L2_RQSTS.ALL_CODE_RD +PRESET,PAPI_L2_TCA,NOT_DERIVED,L2_RQSTS.REFERENCES +PRESET,PAPI_L2_DCM,NOT_DERIVED,L2_RQSTS.ALL_DEMAND_MISS +# SMP +PRESET,PAPI_CA_SHR,NOT_DERIVED,OFFCORE_REQUESTS:DATA_RD +#FLOPs +PRESET,PAPI_DP_OPS,DERIVED_POSTFIX,N0|N1|2|*|+|N2|4|*|+|,FP_ARITH_INST_RETIRED:SCALAR_DOUBLE,FP_ARITH_INST_RETIRED:128B_PACKED_DOUBLE,FP_ARITH_INST_RETIRED:256B_PACKED_DOUBLE +PRESET,PAPI_SP_OPS,DERIVED_POSTFIX,N0|N1|4|*|+|N2|8|*|+|,FP_ARITH_INST_RETIRED:SCALAR_SINGLE,FP_ARITH_INST_RETIRED:128B_PACKED_SINGLE,FP_ARITH_INST_RETIRED:256B_PACKED_SINGLE +PRESET,PAPI_FP_OPS,DERIVED_POSTFIX,N0|N1|2|*|+|N2|4|*|+|N3|4|*|+|N4|8|*|+|,FP_ARITH_INST_RETIRED:SCALAR,FP_ARITH_INST_RETIRED:128B_PACKED_DOUBLE,FP_ARITH_INST_RETIRED:256B_PACKED_DOUBLE,FP_ARITH_INST_RETIRED:128B_PACKED_SINGLE,FP_ARITH_INST_RETIRED:256B_PACKED_SINGLE +PRESET,PAPI_FP_INS,DERIVED_POSTFIX,N0|N1|N2|N3|N4|+|+|+|+|,FP_ARITH_INST_RETIRED:SCALAR,FP_ARITH_INST_RETIRED:128B_PACKED_SINGLE,FP_ARITH_INST_RETIRED:256B_PACKED_SINGLE,FP_ARITH_INST_RETIRED:128B_PACKED_DOUBLE,FP_ARITH_INST_RETIRED:256B_PACKED_DOUBLE +PRESET,PAPI_VEC_DP,DERIVED_POSTFIX,N0|N1|N2|+|+|,FP_ARITH_INST_RETIRED:SCALAR_DOUBLE,FP_ARITH_INST_RETIRED:128B_PACKED_DOUBLE,FP_ARITH_INST_RETIRED:256B_PACKED_DOUBLE +PRESET,PAPI_VEC_SP,DERIVED_POSTFIX,N0|N1|N2|+|+|,FP_ARITH_INST_RETIRED:SCALAR_SINGLE,FP_ARITH_INST_RETIRED:128B_PACKED_SINGLE,FP_ARITH_INST_RETIRED:256B_PACKED_SINGLE +PRESET,PAPI_VEC_INS,DERIVED_POSTFIX,N0|N1|N2|N3|+|+|+|,FP_ARITH_INST_RETIRED:128B_PACKED_SINGLE,FP_ARITH_INST_RETIRED:256B_PACKED_SINGLE,FP_ARITH_INST_RETIRED:128B_PACKED_DOUBLE,FP_ARITH_INST_RETIRED:256B_PACKED_DOUBLE +# End of icx, icl, adl_glc list # Intel Sapphire Rapids events CPU,spr From 2f83dd691a6d579ac54b6f87b43d950331a5d7c7 Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Thu, 12 Sep 2024 11:24:11 -0400 Subject: [PATCH 19/20] perf_event: added 'metric' field to pe_event_info_t that is set for TOPDOWN events and ensures reset when rdpmc is enabled, if topdown events are allowed to accumulate they produce innacurate results. Therefore, a new field needs to be added for topdown events that ensures their reset flag is not disabled. The field is named 'metric' instead of 'topdown' so that in case events are developed in the future with similar behavior to topdown events, the name will still make sense. --- src/components/perf_event/perf_event.c | 13 +++- src/components/perf_event/perf_event_lib.h | 23 +++---- src/validation_tests/topdown_validation.c | 70 +++++++++++----------- 3 files changed, 58 insertions(+), 48 deletions(-) diff --git a/src/components/perf_event/perf_event.c b/src/components/perf_event/perf_event.c index 262a5f108..148b88d37 100644 --- a/src/components/perf_event/perf_event.c +++ b/src/components/perf_event/perf_event.c @@ -1467,9 +1467,9 @@ _pe_start( hwd_context_t *ctx, hwd_control_state_t *ctl ) pe_ctl->events[i].event_fd); ret=ioctl( pe_ctl->events[i].event_fd, PERF_EVENT_IOC_ENABLE, NULL) ; - if (_perf_event_vector.cmp_info.fast_counter_read) { - //pe_ctl->reset_counts[i] = 0LL; - //pe_ctl->reset_flag = 0; + if (_perf_event_vector.cmp_info.fast_counter_read && !pe_ctl->events[i].metric) { + pe_ctl->reset_counts[i] = 0LL; + pe_ctl->reset_flag = 0; } /* ioctls always return -1 on failure */ @@ -1622,6 +1622,13 @@ _pe_update_control_state( hwd_control_state_t *ctl, // pe_ctl->events[i].attr.exclude_hv = !(pe_ctl->domain & PAPI_DOM_SUPERVISOR); // } + /* Intel's topdown events need to be handled differently than normal events */ + /* They are instantaneous values and should not be accumulated. In case more */ + /* types of events like this are discovered, the 'metric' flag is set to */ + /* handle this behavior. */ + if (strcmp(ntv_evt->base_name, "TOPDOWN") == 0) { + pe_ctl->events[i].metric = 1; + } // set the cpu number provided with an event mask if there was one (will be -1 if mask not provided) pe_ctl->events[i].cpu = ntv_evt->cpu; diff --git a/src/components/perf_event/perf_event_lib.h b/src/components/perf_event/perf_event_lib.h index cfba8ac49..eb30271e7 100644 --- a/src/components/perf_event/perf_event_lib.h +++ b/src/components/perf_event/perf_event_lib.h @@ -8,17 +8,18 @@ typedef struct { - int group_leader_fd; /* fd of group leader */ - int event_fd; /* fd of event */ - int event_opened; /* event successfully opened */ - int profiling; /* event is profiling */ - int sampling; /* event is a sampling event */ - uint32_t nr_mmap_pages; /* number pages in the mmap buffer */ - void *mmap_buf; /* used for control/profiling */ - uint64_t tail; /* current read location in mmap buffer */ - uint64_t mask; /* mask used for wrapping the pages */ - int cpu; /* cpu associated with this event */ - struct perf_event_attr attr; /* perf_event config structure */ + int group_leader_fd; /* fd of group leader */ + int event_fd; /* fd of event */ + int event_opened; /* event successfully opened */ + int profiling; /* event is profiling */ + int sampling; /* event is a sampling event */ + int metric; /* event is a metric event (e.g topdown) */ + uint32_t nr_mmap_pages; /* number pages in the mmap buffer */ + void *mmap_buf; /* used for control/profiling */ + uint64_t tail; /* current read location in mmap buffer */ + uint64_t mask; /* mask used for wrapping the pages */ + int cpu; /* cpu associated with this event */ + struct perf_event_attr attr; /* perf_event config structure */ } pe_event_info_t; diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index fa9daad75..4dc87f14c 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -344,29 +344,31 @@ int main(int argc, char **argv) } // get percentages from papi_event (assuming rdpmc) - for (j = 0; j < NUM_EVENTS-1; j++) + for (j = 0; j < NUM_EVENTS - 1; j++) { - percs_papi_rdpmc[j] = rdpmc_get_metric(values[j+1], j); - } - + percs_papi_rdpmc[j] = rdpmc_get_metric(values[j + 1], j); + } + // get percentages from papi_event (assuming non-rdpmc) - for (j = 0; j < NUM_EVENTS-1; j++) + for (j = 0; j < NUM_EVENTS - 1; j++) { - percs_papi_event[j] = (double)values[j+1] / (double)values[0] * 100.0; - } + percs_papi_event[j] = (double)values[j + 1] / (double)values[0] * 100.0; + } // if neither result matches perf_event rdpmc, we fail - if (are_percs_equivalent(percs_perf_rdpmc, percs_papi_rdpmc, papi_rdpmc_error, 4) + - are_percs_equivalent(percs_perf_rdpmc, percs_papi_event, papi_event_error, 4) < 1) { - failures++; - printf("rdpmc error - "); - print_percs(papi_rdpmc_error); - printf("event error - "); - print_percs(papi_event_error); + if (are_percs_equivalent(percs_perf_rdpmc, percs_papi_rdpmc, papi_rdpmc_error, 4) + + are_percs_equivalent(percs_perf_rdpmc, percs_papi_event, papi_event_error, 4) < + 1) + { + failures++; + printf("rdpmc error - "); + print_percs(papi_rdpmc_error); + printf("event error - "); + print_percs(papi_event_error); } } - printf("\tPassed %d/%d tests\n", NUM_TESTS-failures, NUM_TESTS); + printf("\tPassed %d/%d tests\n", NUM_TESTS - failures, NUM_TESTS); failures = 0; // test Level 2 topdown events @@ -391,36 +393,36 @@ int main(int argc, char **argv) // get percentages from perf_event rdpmc for (j = 0; j < 4; j++) { - percs_perf_rdpmc[j] = rdpmc_get_metric(metrics_val, j+4); + percs_perf_rdpmc[j] = rdpmc_get_metric(metrics_val, j + 4); } // get percentages from papi_event (assuming rdpmc) - for (j = 0; j < NUM_EVENTS-1; j++) + for (j = 0; j < NUM_EVENTS - 1; j++) { - percs_papi_rdpmc[j] = rdpmc_get_metric(values[j+1], j+4); - } - + percs_papi_rdpmc[j] = rdpmc_get_metric(values[j + 1], j + 4); + } + // get percentages from papi_event (assuming non-rdpmc) - for (j = 0; j < NUM_EVENTS-1; j++) + for (j = 0; j < NUM_EVENTS - 1; j++) { - percs_papi_event[j] = (double)values[j+1] / (double)values[0] * 100.0; - } + percs_papi_event[j] = (double)values[j + 1] / (double)values[0] * 100.0; + } // if neither result matches perf_event rdpmc, we fail - if (are_percs_equivalent(percs_perf_rdpmc, percs_papi_rdpmc, papi_rdpmc_error, 4) + - are_percs_equivalent(percs_perf_rdpmc, percs_papi_event, papi_event_error, 4) < 1) { - failures++; - printf("rdpmc error - "); - print_percs(papi_rdpmc_error); - printf("event error - "); - print_percs(papi_event_error); + if (are_percs_equivalent(percs_perf_rdpmc, percs_papi_rdpmc, papi_rdpmc_error, 4) + + are_percs_equivalent(percs_perf_rdpmc, percs_papi_event, papi_event_error, 4) < 1) + { + failures++; + printf("rdpmc error - "); + print_percs(papi_rdpmc_error); + printf("event error - "); + print_percs(papi_event_error); } } - printf("\tPassed %d/%d tests\n", NUM_TESTS-failures, NUM_TESTS); + printf("\tPassed %d/%d tests\n", NUM_TESTS - failures, NUM_TESTS); - test_pass( __FILE__ ); - - return 0; + test_pass(__FILE__); + return 0; } \ No newline at end of file From eefe4328751ab0e1335ae7e573dfdc31c667a3fe Mon Sep 17 00:00:00 2001 From: Willow Cunningham Date: Mon, 16 Sep 2024 14:53:52 -0400 Subject: [PATCH 20/20] validation_tests: finalized topdown_validation test --- src/validation_tests/topdown_validation.c | 156 +++++++++++++++++----- 1 file changed, 119 insertions(+), 37 deletions(-) diff --git a/src/validation_tests/topdown_validation.c b/src/validation_tests/topdown_validation.c index 4dc87f14c..2b8a3b623 100644 --- a/src/validation_tests/topdown_validation.c +++ b/src/validation_tests/topdown_validation.c @@ -1,6 +1,15 @@ /* topdown_validation.c */ -/* TODO: Explain */ +/* + * This file tests Intel's TOPDOWN level 1 and level 2 events + * by making sure that PAPI's values agree with results obtained + * by directly calling rdpmc, and ensuring that the percentages + * obtained correctly add to 100. + * + * Additionally, this validation test can serve as an example of + * how to use topdown events with PAPI, as they have some + * differences and quirks that make them difficult to work with. + */ #include #include @@ -21,13 +30,13 @@ #include #define NUM_EVENTS 5 -#define NUM_TESTS 100 +#define NUM_TESTS 100 /* test many times as fails can occur at a low rate */ #define PERCENTAGES_TOLERANCE 1.5 // +- range of percentage points for success -/* - * perf_event _rdpmc code - */ +/**********************/ +/* rdpmc related code */ +/**********************/ #define SLOTS 0x0400ull #define METRICS 0x8000ull @@ -54,7 +63,6 @@ static inline uint64_t read_metrics(void) return _rdpmc(RDPMC_METRIC | METRIC_COUNTER_TOPDOWN_L1_L2); } -// clears event metrics static inline int reset_metrics(int fd) { return ioctl(fd, PERF_EVENT_IOC_RESET, 0); @@ -70,12 +78,30 @@ float rdpmc_get_metric(u_int64_t m, int i) return (float)(((m) >> (i * 8)) & 0xff) / 0xff * 100.0; } -void print_percs(double *percs) +/*********************/ +/* general functions */ +/*********************/ + +// prints the 4 level 1 topdown event percentages +void print_L1_percs(double *percs_l1) { printf("retiring: %.02f\tbadspec: %.02f fe_bound: %.02f\tbe_bound: %.02f\n", - percs[0], percs[1], percs[2], percs[3]); + percs_l1[0], percs_l1[1], percs_l1[2], percs_l1[3]); } +// prints the 8 level 2 topdown event percentages as derived from L1 and L2 events +void print_L2_percs(double *percs_l1, double *percs_l2) +{ + double light_ops = percs_l1[0] - percs_l2[0]; // retiring - heavy_ops + double machine_clears = percs_l1[1] - percs_l2[1]; // bad_spec - branch_mispredicts + double fetch_bandwidth = percs_l1[2] - percs_l2[2]; // frontend_bound - fetch_latency + double core_bound = percs_l1[3] - percs_l2[3]; // backend_bound - memory_bound + + printf("heavy ops: %.02f\tlight ops: %.02f\tbranch mispred: %.02f\tmachine clears: %.02f\tfetch lat: %.02f\tfetch band: %.02f\tmem bound: %.02f\tcore bound: %.02f\n", + percs_l2[0], light_ops, percs_l2[1], machine_clears, percs_l2[2], fetch_bandwidth, percs_l2[3], core_bound); +} + + // returns one if a and b are within the tolerance of each other int eq_within_tolerance(double a, double b, double tolerance) { @@ -102,6 +128,18 @@ int are_percs_equivalent(double *percs_gt, double *percs_b, double *abs_error, i return eq; } +// returns 1 if the values in the array sum to the target value +int sum_equiv_target(double target, double *percs, int n_percs) +{ + double sum = 0; + int i; + + for (i=0; i 0) { + test_fail(__FILE__, __LINE__, "Topdown level 1 tests failed: ", failures); + } failures = 0; + // test Level 2 topdown events - printf("Testing L2 Topdown Events\n"); + if (!quiet) + printf("Testing L2 Topdown Events\n"); + for (i = 0; i < NUM_TESTS; i++) { // first get the ground truth (perf_event rdpmc) @@ -396,31 +462,47 @@ int main(int argc, char **argv) percs_perf_rdpmc[j] = rdpmc_get_metric(metrics_val, j + 4); } - // get percentages from papi_event (assuming rdpmc) + // get percentages from papi_event (assuming rdpmc was enabled) for (j = 0; j < NUM_EVENTS - 1; j++) { percs_papi_rdpmc[j] = rdpmc_get_metric(values[j + 1], j + 4); } - // get percentages from papi_event (assuming non-rdpmc) + // get percentages from papi_event (assuming rdpmc was disabled) for (j = 0; j < NUM_EVENTS - 1; j++) { percs_papi_event[j] = (double)values[j + 1] / (double)values[0] * 100.0; } + // as the 8 level 2 events are derived from the 4 available level 2 + // events, they will never add to 100%. Therefore there is no point + // therefore there is no point in checking if they do + // (see linux kernel tools/perf/Documentation/topdown.txt) + // if neither result matches perf_event rdpmc, we fail if (are_percs_equivalent(percs_perf_rdpmc, percs_papi_rdpmc, papi_rdpmc_error, 4) + are_percs_equivalent(percs_perf_rdpmc, percs_papi_event, papi_event_error, 4) < 1) { failures++; - printf("rdpmc error - "); - print_percs(papi_rdpmc_error); - printf("event error - "); - print_percs(papi_event_error); + if (!quiet) { + printf("\trdpmc error - "); + for(j = 0; j < NUM_EVENTS - 1; j++) + printf("%.02f\t", papi_rdpmc_error[j]); + printf("\n\tevent error - "); + for(j = 0; j < NUM_EVENTS - 1; j++) + printf("%.02f\t", papi_event_error[j]); + putchar('\n'); + } + + continue; } } - printf("\tPassed %d/%d tests\n", NUM_TESTS - failures, NUM_TESTS); + printf("Passed %d/%d tests\n", NUM_TESTS - failures, NUM_TESTS); + + if (failures > 0) { + test_fail(__FILE__, __LINE__, "Topdown level 2 tests failed.", ret); + } test_pass(__FILE__);