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