1 #include <darwintest.h> 2 #include <inttypes.h> 3 #if __arm64__ 4 #include <mach/arm/processor_info.h> 5 #endif /* __arm64__ */ 6 #include <mach/mach.h> 7 #include <stdlib.h> 8 #include <unistd.h> 9 10 T_GLOBAL_META(T_META_ASROOT(true), 11 T_META_RUN_CONCURRENTLY(true)); 12 13 T_DECL(processor_cpu_stat64, 14 "ensure 64-bit processor statistics are reported correctly", 15 T_META_NAMESPACE("xnu.arm"), 16 T_META_RADAR_COMPONENT_NAME("xnu"), 17 T_META_RADAR_COMPONENT_VERSION("arm"), 18 T_META_OWNER("mwm")) 19 { 20 #if !__arm64__ 21 T_SKIP("processor statistics only available on ARM"); 22 #else /* !__arm64__ */ 23 host_t host = mach_host_self(); 24 host_t priv_port = MACH_PORT_NULL; 25 26 kern_return_t kr = host_get_host_priv_port(host, &priv_port); 27 T_QUIET; 28 T_ASSERT_MACH_SUCCESS(kr, "host_get_host_priv_port"); 29 T_QUIET; 30 T_ASSERT_NE(priv_port, MACH_PORT_NULL, "valid host priv port"); 31 32 processor_port_array_t cpu_ports = NULL; 33 mach_msg_type_number_t cpu_count = 0; 34 kr = host_processors(priv_port, &cpu_ports, &cpu_count); 35 T_QUIET; 36 T_ASSERT_MACH_SUCCESS(kr, "host_processors"); 37 T_QUIET; 38 T_ASSERT_NOTNULL(cpu_ports, "valid processor port array"); 39 T_QUIET; 40 T_ASSERT_GT(cpu_count, (mach_msg_type_number_t)0, 41 "non-zero CPU count"); 42 43 T_LOG("found %d CPUs", cpu_count); 44 45 struct processor_cpu_stat64 *prestats = calloc(cpu_count, 46 sizeof(*prestats)); 47 T_WITH_ERRNO; 48 T_QUIET; 49 T_ASSERT_NOTNULL(prestats, "allocate space for stats (pre)"); 50 memset(prestats, 0xff, cpu_count * sizeof(*prestats)); 51 52 for (int i = 0; i < (int)cpu_count; i++) { 53 mach_msg_type_number_t info_count = PROCESSOR_CPU_STAT64_COUNT; 54 kr = processor_info(cpu_ports[i], PROCESSOR_CPU_STAT64, &host, 55 (processor_info_t)&prestats[i], &info_count); 56 T_ASSERT_MACH_SUCCESS(kr, 57 "processor_info(%d, PROCESSOR_CPU_STAT64, ...)", i); 58 59 T_QUIET; 60 T_ASSERT_EQ(info_count, PROCESSOR_CPU_STAT64_COUNT, 61 "received enough CPU statistics"); 62 } 63 64 sleep(1); 65 66 struct processor_cpu_stat64 *poststats = calloc(cpu_count - 1, 67 sizeof(*poststats)); 68 T_WITH_ERRNO; 69 T_QUIET; 70 T_ASSERT_NOTNULL(poststats, "allocate space for stats (post)"); 71 72 for (int i = 0; i < (int)cpu_count; i++) { 73 mach_msg_type_number_t info_count = PROCESSOR_CPU_STAT64_COUNT; 74 kr = processor_info(cpu_ports[i], PROCESSOR_CPU_STAT64, &host, 75 (processor_info_t)&poststats[i], &info_count); 76 T_ASSERT_MACH_SUCCESS(kr, 77 "processor_info(%d, PROCESSOR_CPU_STAT64, ...)", i); 78 79 T_QUIET; 80 T_ASSERT_EQ(info_count, PROCESSOR_CPU_STAT64_COUNT, 81 "received enough CPU statistics"); 82 } 83 84 for (int i = 0; i < (int)cpu_count; i++) { 85 #define CHECK_STAT_FIELD(field) \ 86 T_EXPECT_GE(poststats[i].field, prestats[i].field, \ 87 "CPU %d's " #field " is monotonically increasing (+%" PRIu64 \ 88 ")", i, poststats[i].field - prestats[i].field) 89 90 CHECK_STAT_FIELD(irq_ex_cnt); 91 CHECK_STAT_FIELD(ipi_cnt); 92 CHECK_STAT_FIELD(timer_cnt); 93 CHECK_STAT_FIELD(undef_ex_cnt); 94 CHECK_STAT_FIELD(unaligned_cnt); 95 CHECK_STAT_FIELD(vfp_cnt); 96 CHECK_STAT_FIELD(vfp_shortv_cnt); 97 CHECK_STAT_FIELD(data_ex_cnt); 98 CHECK_STAT_FIELD(instr_ex_cnt); 99 CHECK_STAT_FIELD(pmi_cnt); 100 101 #undef CHECK_STAT_FIELD 102 } 103 104 free(prestats); 105 free(poststats); 106 #endif /* __arm64__ */ 107 } 108 109 110 T_DECL(processor_cpu_info_order, 111 "ensure host_processor_info iterates CPU in CPU ID order") 112 { 113 host_t host = mach_host_self(); 114 host_t priv_port = MACH_PORT_NULL; 115 116 kern_return_t kr = host_get_host_priv_port(host, &priv_port); 117 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "host_get_host_priv_port"); 118 T_QUIET; T_ASSERT_NE(priv_port, MACH_PORT_NULL, "valid host priv port"); 119 120 processor_info_array_t info_array = NULL; 121 mach_msg_type_number_t info_count = 0; 122 natural_t processor_count = 0; 123 124 kr = host_processor_info(mach_host_self(), PROCESSOR_BASIC_INFO, &processor_count, 125 &info_array, &info_count); 126 127 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "host_processor_info(PROCESSOR_BASIC_INFO)"); 128 T_QUIET; T_ASSERT_NOTNULL(info_array, "valid processor port array"); 129 T_QUIET; T_ASSERT_GT(info_count, (mach_msg_type_number_t)0, "non-zero array"); 130 T_QUIET; T_ASSERT_GT(processor_count, (natural_t)0, "non-zero processor_count"); 131 132 processor_basic_info_t basic_info_array = (processor_basic_info_t)info_array; 133 134 for (natural_t i = 0; i < processor_count; i++) { 135 struct processor_basic_info* processor_info = &basic_info_array[i]; 136 137 natural_t slot_num = (natural_t)processor_info->slot_num; 138 139 T_ASSERT_EQ(slot_num, i, "CPU ID must equal array index"); 140 } 141 } 142