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