1*1b191cb5SApple OSS Distributions // Copyright (c) 2020 Apple Computer, Inc. All rights reserved. 2*1b191cb5SApple OSS Distributions 3*1b191cb5SApple OSS Distributions #include <darwintest.h> 4*1b191cb5SApple OSS Distributions #include <errno.h> 5*1b191cb5SApple OSS Distributions #include <inttypes.h> 6*1b191cb5SApple OSS Distributions #include <stdint.h> 7*1b191cb5SApple OSS Distributions 8*1b191cb5SApple OSS Distributions #include "rump.h" 9*1b191cb5SApple OSS Distributions 10*1b191cb5SApple OSS Distributions #include <sys/perfmon_private.h> 11*1b191cb5SApple OSS Distributions 12*1b191cb5SApple OSS Distributions #define CONFIG_PERFMON 1 13*1b191cb5SApple OSS Distributions #define CPMU_PMC_COUNT 10 14*1b191cb5SApple OSS Distributions #define HAS_UPMU 1 15*1b191cb5SApple OSS Distributions #define UPMU_PMC_COUNT 16 16*1b191cb5SApple OSS Distributions 17*1b191cb5SApple OSS Distributions #include "../osfmk/kern/perfmon.h" 18*1b191cb5SApple OSS Distributions #include "../osfmk/arm64/perfmon_arm64_regs.h" 19*1b191cb5SApple OSS Distributions #include "../osfmk/machine/machine_perfmon.h" 20*1b191cb5SApple OSS Distributions #include "../osfmk/kern/kern_perfmon.c" 21*1b191cb5SApple OSS Distributions #include "../osfmk/arm64/perfmon_arm64.c" 22*1b191cb5SApple OSS Distributions 23*1b191cb5SApple OSS Distributions T_GLOBAL_META(T_META_NAMESPACE("xnu.perfmon")); 24*1b191cb5SApple OSS Distributions 25*1b191cb5SApple OSS Distributions struct perfmon_event test_events[2] = { 26*1b191cb5SApple OSS Distributions { 27*1b191cb5SApple OSS Distributions .pe_name = "test", 28*1b191cb5SApple OSS Distributions .pe_number = 1, 29*1b191cb5SApple OSS Distributions .pe_counter = 3, 30*1b191cb5SApple OSS Distributions }, { 31*1b191cb5SApple OSS Distributions .pe_name = "second", 32*1b191cb5SApple OSS Distributions .pe_number = 2, 33*1b191cb5SApple OSS Distributions .pe_counter = 4, 34*1b191cb5SApple OSS Distributions }, 35*1b191cb5SApple OSS Distributions }; 36*1b191cb5SApple OSS Distributions 37*1b191cb5SApple OSS Distributions T_DECL(config_add_event_spec, "ensure events can be added to a configuration") 38*1b191cb5SApple OSS Distributions { 39*1b191cb5SApple OSS Distributions T_SETUPBEGIN; 40*1b191cb5SApple OSS Distributions perfmon_machine_startup(); 41*1b191cb5SApple OSS Distributions perfmon_config_t config = perfmon_config_create(&perfmon_sources[0]); 42*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(config, "created config"); 43*1b191cb5SApple OSS Distributions T_SETUPEND; 44*1b191cb5SApple OSS Distributions 45*1b191cb5SApple OSS Distributions struct perfmon_event event = test_events[0]; 46*1b191cb5SApple OSS Distributions 47*1b191cb5SApple OSS Distributions int error = perfmon_config_add_event(config, &event); 48*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ZERO(error, "should add event to config"); 49*1b191cb5SApple OSS Distributions const struct perfmon_spec *spec = perfmon_config_specify(config); 50*1b191cb5SApple OSS Distributions T_ASSERT_EQ(spec->ps_event_count, (unsigned short)1, 51*1b191cb5SApple OSS Distributions "one event added to config"); 52*1b191cb5SApple OSS Distributions 53*1b191cb5SApple OSS Distributions error = perfmon_config_add_event(config, &event); 54*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ERROR(error, EALREADY, 55*1b191cb5SApple OSS Distributions "should not add event to already-used counter"); 56*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_EQ(spec->ps_event_count, (unsigned short)1, 57*1b191cb5SApple OSS Distributions "still one event added to config"); 58*1b191cb5SApple OSS Distributions 59*1b191cb5SApple OSS Distributions event = test_events[1]; 60*1b191cb5SApple OSS Distributions error = perfmon_config_add_event(config, &event); 61*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ZERO(error, "should add second event to config"); 62*1b191cb5SApple OSS Distributions T_ASSERT_EQ(spec->ps_event_count, (unsigned short)2, 63*1b191cb5SApple OSS Distributions "two events added to config"); 64*1b191cb5SApple OSS Distributions 65*1b191cb5SApple OSS Distributions event.pe_counter = 20; 66*1b191cb5SApple OSS Distributions error = perfmon_config_add_event(config, &event); 67*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ERROR(error, ERANGE, 68*1b191cb5SApple OSS Distributions "should not add event to counter out of range"); 69*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_EQ(spec->ps_event_count, (unsigned short)2, 70*1b191cb5SApple OSS Distributions "still two events added to config"); 71*1b191cb5SApple OSS Distributions 72*1b191cb5SApple OSS Distributions event.pe_counter = 0; 73*1b191cb5SApple OSS Distributions error = perfmon_config_add_event(config, &event); 74*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ERROR(error, ENODEV, 75*1b191cb5SApple OSS Distributions "should not add event to fixed counter, error was %d", error); 76*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_EQ(spec->ps_event_count, (unsigned short)2, 77*1b191cb5SApple OSS Distributions "still two events added to config"); 78*1b191cb5SApple OSS Distributions 79*1b191cb5SApple OSS Distributions error = perfmon_configure(config); 80*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ZERO(error, "configured CPMU"); 81*1b191cb5SApple OSS Distributions 82*1b191cb5SApple OSS Distributions event.pe_counter = 4; 83*1b191cb5SApple OSS Distributions error = perfmon_config_add_event(config, &event); 84*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ERROR(error, EBUSY, 85*1b191cb5SApple OSS Distributions "should not add event to already-configured config"); 86*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_EQ(spec->ps_event_count, (unsigned short)2, 87*1b191cb5SApple OSS Distributions "still two events added to config"); 88*1b191cb5SApple OSS Distributions 89*1b191cb5SApple OSS Distributions const struct perfmon_event *read_events = spec->ps_events; 90*1b191cb5SApple OSS Distributions for (unsigned short i = 0; i < spec->ps_event_count; i++) { 91*1b191cb5SApple OSS Distributions T_QUIET; 92*1b191cb5SApple OSS Distributions T_ASSERT_EQ_STR(read_events[i].pe_name, test_events[i].pe_name, 93*1b191cb5SApple OSS Distributions "event %hu name matches", i); 94*1b191cb5SApple OSS Distributions T_QUIET; 95*1b191cb5SApple OSS Distributions T_ASSERT_EQ(read_events[i].pe_number, test_events[i].pe_number, 96*1b191cb5SApple OSS Distributions "event %hu number matches", i); 97*1b191cb5SApple OSS Distributions T_QUIET; 98*1b191cb5SApple OSS Distributions T_ASSERT_EQ(read_events[i].pe_counter, test_events[i].pe_counter, 99*1b191cb5SApple OSS Distributions "event %hu counter matches", i); 100*1b191cb5SApple OSS Distributions T_PASS("event %hu in config matches what was set", i); 101*1b191cb5SApple OSS Distributions } 102*1b191cb5SApple OSS Distributions 103*1b191cb5SApple OSS Distributions perfmon_config_destroy(config); 104*1b191cb5SApple OSS Distributions } 105*1b191cb5SApple OSS Distributions 106*1b191cb5SApple OSS Distributions struct perfmon_attr test_attrs[2] = { 107*1b191cb5SApple OSS Distributions { 108*1b191cb5SApple OSS Distributions .pa_name = "PMCR2", 109*1b191cb5SApple OSS Distributions .pa_value = 0x123 110*1b191cb5SApple OSS Distributions }, { 111*1b191cb5SApple OSS Distributions .pa_name = "OPMAT0", 112*1b191cb5SApple OSS Distributions .pa_value = 0x123, 113*1b191cb5SApple OSS Distributions }, 114*1b191cb5SApple OSS Distributions }; 115*1b191cb5SApple OSS Distributions 116*1b191cb5SApple OSS Distributions T_DECL(config_set_attr_spec, "ensure attributes can be set on a configuration") 117*1b191cb5SApple OSS Distributions { 118*1b191cb5SApple OSS Distributions T_SETUPBEGIN; 119*1b191cb5SApple OSS Distributions perfmon_machine_startup(); 120*1b191cb5SApple OSS Distributions perfmon_config_t config = perfmon_config_create(&perfmon_sources[0]); 121*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(config, "created config"); 122*1b191cb5SApple OSS Distributions T_SETUPEND; 123*1b191cb5SApple OSS Distributions 124*1b191cb5SApple OSS Distributions struct perfmon_attr attr = test_attrs[0]; 125*1b191cb5SApple OSS Distributions 126*1b191cb5SApple OSS Distributions int error = perfmon_config_set_attr(config, &attr); 127*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ZERO(error, "should set attr in config"); 128*1b191cb5SApple OSS Distributions struct perfmon_spec *spec = perfmon_config_specify(config); 129*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_EQ(spec->ps_attr_count, (unsigned short)1, 130*1b191cb5SApple OSS Distributions "one attr set in config"); 131*1b191cb5SApple OSS Distributions 132*1b191cb5SApple OSS Distributions error = perfmon_config_set_attr(config, &attr); 133*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ERROR(error, EALREADY, 134*1b191cb5SApple OSS Distributions "should not set same attribute to config"); 135*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_EQ(spec->ps_attr_count, (unsigned short)1, 136*1b191cb5SApple OSS Distributions "still one attr set in config"); 137*1b191cb5SApple OSS Distributions 138*1b191cb5SApple OSS Distributions attr = test_attrs[1]; 139*1b191cb5SApple OSS Distributions error = perfmon_config_set_attr(config, &attr); 140*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ZERO(error, "should set second attr in config"); 141*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_EQ(spec->ps_attr_count, (unsigned short)2, 142*1b191cb5SApple OSS Distributions "two attrs set in config"); 143*1b191cb5SApple OSS Distributions 144*1b191cb5SApple OSS Distributions strlcpy(attr.pa_name, "ENOATTR", sizeof(attr.pa_name)); 145*1b191cb5SApple OSS Distributions error = perfmon_config_set_attr(config, &attr); 146*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ERROR(error, ENOATTR, 147*1b191cb5SApple OSS Distributions "should not set non-existent attr in config"); 148*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_EQ(spec->ps_attr_count, (unsigned short)2, 149*1b191cb5SApple OSS Distributions "still two attrs set in config"); 150*1b191cb5SApple OSS Distributions 151*1b191cb5SApple OSS Distributions error = perfmon_configure(config); 152*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ZERO(error, "configured CPMU"); 153*1b191cb5SApple OSS Distributions 154*1b191cb5SApple OSS Distributions strlcpy(attr.pa_name, "PMCR3", sizeof(attr.pa_name)); 155*1b191cb5SApple OSS Distributions error = perfmon_config_set_attr(config, &attr); 156*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ERROR(error, EBUSY, 157*1b191cb5SApple OSS Distributions "should not set attr on already-configured config"); 158*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_EQ(spec->ps_attr_count, (unsigned short)2, 159*1b191cb5SApple OSS Distributions "still two attrs added to config"); 160*1b191cb5SApple OSS Distributions 161*1b191cb5SApple OSS Distributions const struct perfmon_attr *read_attrs = spec->ps_attrs; 162*1b191cb5SApple OSS Distributions for (unsigned short i = 0; i < spec->ps_attr_count; i++) { 163*1b191cb5SApple OSS Distributions T_QUIET; 164*1b191cb5SApple OSS Distributions T_ASSERT_EQ_STR(read_attrs[i].pa_name, test_attrs[i].pa_name, 165*1b191cb5SApple OSS Distributions "attr %hu name matches", i); 166*1b191cb5SApple OSS Distributions T_QUIET; 167*1b191cb5SApple OSS Distributions T_ASSERT_EQ(read_attrs[i].pa_value, test_attrs[i].pa_value, 168*1b191cb5SApple OSS Distributions "attr %hu number matches", i); 169*1b191cb5SApple OSS Distributions T_PASS("attr %hu in config matches what was set", i); 170*1b191cb5SApple OSS Distributions } 171*1b191cb5SApple OSS Distributions 172*1b191cb5SApple OSS Distributions perfmon_config_destroy(config); 173*1b191cb5SApple OSS Distributions } 174*1b191cb5SApple OSS Distributions 175*1b191cb5SApple OSS Distributions T_DECL(config_arm64_cpmu, "ensure the ARM64 configuration is correct") 176*1b191cb5SApple OSS Distributions { 177*1b191cb5SApple OSS Distributions T_SETUPBEGIN; 178*1b191cb5SApple OSS Distributions perfmon_machine_startup(); 179*1b191cb5SApple OSS Distributions struct perfmon_source *cpmu_source = &perfmon_sources[0]; 180*1b191cb5SApple OSS Distributions perfmon_config_t config = perfmon_config_create(cpmu_source); 181*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(config, "created config"); 182*1b191cb5SApple OSS Distributions 183*1b191cb5SApple OSS Distributions for (size_t i = 0; i < ARRAYLEN(test_events); i++) { 184*1b191cb5SApple OSS Distributions int error = perfmon_config_add_event(config, &test_events[i]); 185*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(error, "add event %zu to config", i); 186*1b191cb5SApple OSS Distributions } 187*1b191cb5SApple OSS Distributions 188*1b191cb5SApple OSS Distributions T_SETUPEND; 189*1b191cb5SApple OSS Distributions 190*1b191cb5SApple OSS Distributions int error = perfmon_configure(config); 191*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ZERO(error, "configured CPMU"); 192*1b191cb5SApple OSS Distributions 193*1b191cb5SApple OSS Distributions T_LOG("PMCR0 = 0x%016" PRIx64 ", PMESR0 = 0x%016" PRIx64 ", PMESR1 = 0x%016" 194*1b191cb5SApple OSS Distributions PRIx64, cpmu_reg_state.pcr_pmcr0, cpmu_reg_state.pcr_pmesr[0], 195*1b191cb5SApple OSS Distributions cpmu_reg_state.pcr_pmesr[1]); 196*1b191cb5SApple OSS Distributions unsigned short fixed_count = cpmu_source->ps_layout.pl_fixed_count; 197*1b191cb5SApple OSS Distributions for (size_t i = 0; i < ARRAYLEN(test_events); i++) { 198*1b191cb5SApple OSS Distributions T_EXPECT_BITS_SET(cpmu_reg_state.pcr_pmcr0, 199*1b191cb5SApple OSS Distributions 1ULL << test_events[i].pe_counter, "PMCR0 enabled event %zu", i); 200*1b191cb5SApple OSS Distributions T_EXPECT_BITS_SET(cpmu_reg_state.pcr_pmcr0, 201*1b191cb5SApple OSS Distributions 1ULL << (test_events[i].pe_counter + 12), 202*1b191cb5SApple OSS Distributions "PMCR0 enabled PMIs for event %zu", i); 203*1b191cb5SApple OSS Distributions 204*1b191cb5SApple OSS Distributions uint64_t event_shift = (test_events[i].pe_counter - fixed_count) * 8; 205*1b191cb5SApple OSS Distributions T_EXPECT_EQ((cpmu_reg_state.pcr_pmesr[0] >> event_shift) & 0xff, 206*1b191cb5SApple OSS Distributions test_events[i].pe_number, "PMESR0 has event %zu set", i); 207*1b191cb5SApple OSS Distributions } 208*1b191cb5SApple OSS Distributions 209*1b191cb5SApple OSS Distributions perfmon_config_destroy(config); 210*1b191cb5SApple OSS Distributions } 211*1b191cb5SApple OSS Distributions 212*1b191cb5SApple OSS Distributions T_DECL(config_lock, "ensure only one config can be active at a time") 213*1b191cb5SApple OSS Distributions { 214*1b191cb5SApple OSS Distributions T_SETUPBEGIN; 215*1b191cb5SApple OSS Distributions perfmon_machine_startup(); 216*1b191cb5SApple OSS Distributions struct perfmon_source *cpmu_source = &perfmon_sources[0]; 217*1b191cb5SApple OSS Distributions perfmon_config_t config = perfmon_config_create(cpmu_source); 218*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(config, "created config"); 219*1b191cb5SApple OSS Distributions perfmon_config_t config_later = perfmon_config_create(cpmu_source); 220*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(config_later, "created later config"); 221*1b191cb5SApple OSS Distributions 222*1b191cb5SApple OSS Distributions int error = perfmon_configure(config); 223*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ZERO(error, "configured CPMU"); 224*1b191cb5SApple OSS Distributions 225*1b191cb5SApple OSS Distributions T_SETUPEND; 226*1b191cb5SApple OSS Distributions 227*1b191cb5SApple OSS Distributions error = perfmon_configure(config_later); 228*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ERROR(error, EBUSY, 229*1b191cb5SApple OSS Distributions "later config should be unable to configure CPMU"); 230*1b191cb5SApple OSS Distributions 231*1b191cb5SApple OSS Distributions perfmon_config_destroy(config); 232*1b191cb5SApple OSS Distributions perfmon_config_destroy(config_later); 233*1b191cb5SApple OSS Distributions } 234*1b191cb5SApple OSS Distributions 235*1b191cb5SApple OSS Distributions T_DECL(config_release, "ensure the active config releases control") 236*1b191cb5SApple OSS Distributions { 237*1b191cb5SApple OSS Distributions T_SETUPBEGIN; 238*1b191cb5SApple OSS Distributions perfmon_machine_startup(); 239*1b191cb5SApple OSS Distributions struct perfmon_source *cpmu_source = &perfmon_sources[0]; 240*1b191cb5SApple OSS Distributions perfmon_config_t config = perfmon_config_create(cpmu_source); 241*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(config, "created config"); 242*1b191cb5SApple OSS Distributions perfmon_config_t config_later = perfmon_config_create(cpmu_source); 243*1b191cb5SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(config_later, "created later config"); 244*1b191cb5SApple OSS Distributions 245*1b191cb5SApple OSS Distributions int error = perfmon_configure(config); 246*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ZERO(error, "configured CPMU"); 247*1b191cb5SApple OSS Distributions 248*1b191cb5SApple OSS Distributions perfmon_config_destroy(config); 249*1b191cb5SApple OSS Distributions T_LOG("destroyed first config"); 250*1b191cb5SApple OSS Distributions 251*1b191cb5SApple OSS Distributions T_SETUPEND; 252*1b191cb5SApple OSS Distributions 253*1b191cb5SApple OSS Distributions error = perfmon_configure(config_later); 254*1b191cb5SApple OSS Distributions T_ASSERT_POSIX_ZERO(error, "later config configured CPMU"); 255*1b191cb5SApple OSS Distributions 256*1b191cb5SApple OSS Distributions perfmon_config_destroy(config_later); 257*1b191cb5SApple OSS Distributions } 258