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