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