1 // SPDX-License-Identifier: GPL-2.0 2 #include <string.h> 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include <perf/cpumap.h> 6 #include "tests.h" 7 #include "util.h" 8 #include "session.h" 9 #include "evlist.h" 10 #include "debug.h" 11 12 #define TEMPL "/tmp/perf-test-XXXXXX" 13 #define DATA_SIZE 10 14 15 static int get_temp(char *path) 16 { 17 int fd; 18 19 strcpy(path, TEMPL); 20 21 fd = mkstemp(path); 22 if (fd < 0) { 23 perror("mkstemp failed"); 24 return -1; 25 } 26 27 close(fd); 28 return 0; 29 } 30 31 static int session_write_header(char *path) 32 { 33 struct perf_session *session; 34 struct perf_data data = { 35 .file = { 36 .path = path, 37 }, 38 .mode = PERF_DATA_MODE_WRITE, 39 }; 40 41 session = perf_session__new(&data, false, NULL); 42 TEST_ASSERT_VAL("can't get session", session); 43 44 session->evlist = perf_evlist__new_default(); 45 TEST_ASSERT_VAL("can't get evlist", session->evlist); 46 47 perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY); 48 perf_header__set_feat(&session->header, HEADER_NRCPUS); 49 perf_header__set_feat(&session->header, HEADER_ARCH); 50 51 session->header.data_size += DATA_SIZE; 52 53 TEST_ASSERT_VAL("failed to write header", 54 !perf_session__write_header(session, session->evlist, data.file.fd, true)); 55 56 perf_session__delete(session); 57 58 return 0; 59 } 60 61 static int check_cpu_topology(char *path, struct perf_cpu_map *map) 62 { 63 struct perf_session *session; 64 struct perf_data data = { 65 .file = { 66 .path = path, 67 }, 68 .mode = PERF_DATA_MODE_READ, 69 }; 70 int i; 71 72 session = perf_session__new(&data, false, NULL); 73 TEST_ASSERT_VAL("can't get session", session); 74 75 /* On platforms with large numbers of CPUs process_cpu_topology() 76 * might issue an error while reading the perf.data file section 77 * HEADER_CPU_TOPOLOGY and the cpu_topology_map pointed to by member 78 * cpu is a NULL pointer. 79 * Example: On s390 80 * CPU 0 is on core_id 0 and physical_package_id 6 81 * CPU 1 is on core_id 1 and physical_package_id 3 82 * 83 * Core_id and physical_package_id are platform and architecture 84 * dependend and might have higher numbers than the CPU id. 85 * This actually depends on the configuration. 86 * 87 * In this case process_cpu_topology() prints error message: 88 * "socket_id number is too big. You may need to upgrade the 89 * perf tool." 90 * 91 * This is the reason why this test might be skipped. 92 */ 93 if (!session->header.env.cpu) 94 return TEST_SKIP; 95 96 for (i = 0; i < session->header.env.nr_cpus_avail; i++) { 97 if (!cpu_map__has(map, i)) 98 continue; 99 pr_debug("CPU %d, core %d, socket %d\n", i, 100 session->header.env.cpu[i].core_id, 101 session->header.env.cpu[i].socket_id); 102 } 103 104 for (i = 0; i < map->nr; i++) { 105 TEST_ASSERT_VAL("Core ID doesn't match", 106 (session->header.env.cpu[map->map[i]].core_id == (cpu_map__get_core(map, i, NULL) & 0xffff))); 107 108 TEST_ASSERT_VAL("Socket ID doesn't match", 109 (session->header.env.cpu[map->map[i]].socket_id == cpu_map__get_socket(map, i, NULL))); 110 } 111 112 perf_session__delete(session); 113 114 return 0; 115 } 116 117 int test__session_topology(struct test *test __maybe_unused, int subtest __maybe_unused) 118 { 119 char path[PATH_MAX]; 120 struct perf_cpu_map *map; 121 int ret = TEST_FAIL; 122 123 TEST_ASSERT_VAL("can't get templ file", !get_temp(path)); 124 125 pr_debug("templ file: %s\n", path); 126 127 if (session_write_header(path)) 128 goto free_path; 129 130 map = perf_cpu_map__new(NULL); 131 if (map == NULL) { 132 pr_debug("failed to get system cpumap\n"); 133 goto free_path; 134 } 135 136 ret = check_cpu_topology(path, map); 137 perf_cpu_map__put(map); 138 139 free_path: 140 unlink(path); 141 return ret; 142 } 143