Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <string.h>
0003 #include <stdlib.h>
0004 #include <stdio.h>
0005 #include <perf/cpumap.h>
0006 #include "cpumap.h"
0007 #include "tests.h"
0008 #include "session.h"
0009 #include "evlist.h"
0010 #include "debug.h"
0011 #include "pmu.h"
0012 #include <linux/err.h>
0013 
0014 #define TEMPL "/tmp/perf-test-XXXXXX"
0015 #define DATA_SIZE   10
0016 
0017 static int get_temp(char *path)
0018 {
0019     int fd;
0020 
0021     strcpy(path, TEMPL);
0022 
0023     fd = mkstemp(path);
0024     if (fd < 0) {
0025         perror("mkstemp failed");
0026         return -1;
0027     }
0028 
0029     close(fd);
0030     return 0;
0031 }
0032 
0033 static int session_write_header(char *path)
0034 {
0035     struct perf_session *session;
0036     struct perf_data data = {
0037         .path = path,
0038         .mode = PERF_DATA_MODE_WRITE,
0039     };
0040 
0041     session = perf_session__new(&data, NULL);
0042     TEST_ASSERT_VAL("can't get session", !IS_ERR(session));
0043 
0044     if (!perf_pmu__has_hybrid()) {
0045         session->evlist = evlist__new_default();
0046         TEST_ASSERT_VAL("can't get evlist", session->evlist);
0047     } else {
0048         struct parse_events_error err;
0049 
0050         session->evlist = evlist__new();
0051         TEST_ASSERT_VAL("can't get evlist", session->evlist);
0052         parse_events_error__init(&err);
0053         parse_events(session->evlist, "cpu_core/cycles/", &err);
0054         parse_events_error__exit(&err);
0055     }
0056 
0057     perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
0058     perf_header__set_feat(&session->header, HEADER_NRCPUS);
0059     perf_header__set_feat(&session->header, HEADER_ARCH);
0060 
0061     session->header.data_size += DATA_SIZE;
0062 
0063     TEST_ASSERT_VAL("failed to write header",
0064             !perf_session__write_header(session, session->evlist, data.file.fd, true));
0065 
0066     evlist__delete(session->evlist);
0067     perf_session__delete(session);
0068 
0069     return 0;
0070 }
0071 
0072 static int check_cpu_topology(char *path, struct perf_cpu_map *map)
0073 {
0074     struct perf_session *session;
0075     struct perf_data data = {
0076         .path = path,
0077         .mode = PERF_DATA_MODE_READ,
0078     };
0079     int i;
0080     struct aggr_cpu_id id;
0081 
0082     session = perf_session__new(&data, NULL);
0083     TEST_ASSERT_VAL("can't get session", !IS_ERR(session));
0084     cpu__setup_cpunode_map();
0085 
0086     /* On platforms with large numbers of CPUs process_cpu_topology()
0087      * might issue an error while reading the perf.data file section
0088      * HEADER_CPU_TOPOLOGY and the cpu_topology_map pointed to by member
0089      * cpu is a NULL pointer.
0090      * Example: On s390
0091      *   CPU 0 is on core_id 0 and physical_package_id 6
0092      *   CPU 1 is on core_id 1 and physical_package_id 3
0093      *
0094      *   Core_id and physical_package_id are platform and architecture
0095      *   dependent and might have higher numbers than the CPU id.
0096      *   This actually depends on the configuration.
0097      *
0098      *  In this case process_cpu_topology() prints error message:
0099      *  "socket_id number is too big. You may need to upgrade the
0100      *  perf tool."
0101      *
0102      *  This is the reason why this test might be skipped. aarch64 and
0103      *  s390 always write this part of the header, even when the above
0104      *  condition is true (see do_core_id_test in header.c). So always
0105      *  run this test on those platforms.
0106      */
0107     if (!session->header.env.cpu
0108             && strncmp(session->header.env.arch, "s390", 4)
0109             && strncmp(session->header.env.arch, "aarch64", 7))
0110         return TEST_SKIP;
0111 
0112     /*
0113      * In powerpc pSeries platform, not all the topology information
0114      * are exposed via sysfs. Due to restriction, detail like
0115      * physical_package_id will be set to -1. Hence skip this
0116      * test if physical_package_id returns -1 for cpu from perf_cpu_map.
0117      */
0118     if (!strncmp(session->header.env.arch, "ppc64le", 7)) {
0119         if (cpu__get_socket_id(perf_cpu_map__cpu(map, 0)) == -1)
0120             return TEST_SKIP;
0121     }
0122 
0123     TEST_ASSERT_VAL("Session header CPU map not set", session->header.env.cpu);
0124 
0125     for (i = 0; i < session->header.env.nr_cpus_avail; i++) {
0126         struct perf_cpu cpu = { .cpu = i };
0127 
0128         if (!perf_cpu_map__has(map, cpu))
0129             continue;
0130         pr_debug("CPU %d, core %d, socket %d\n", i,
0131              session->header.env.cpu[i].core_id,
0132              session->header.env.cpu[i].socket_id);
0133     }
0134 
0135     // Test that CPU ID contains socket, die, core and CPU
0136     for (i = 0; i < perf_cpu_map__nr(map); i++) {
0137         id = aggr_cpu_id__cpu(perf_cpu_map__cpu(map, i), NULL);
0138         TEST_ASSERT_VAL("Cpu map - CPU ID doesn't match",
0139                 perf_cpu_map__cpu(map, i).cpu == id.cpu.cpu);
0140 
0141         TEST_ASSERT_VAL("Cpu map - Core ID doesn't match",
0142             session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].core_id == id.core);
0143         TEST_ASSERT_VAL("Cpu map - Socket ID doesn't match",
0144             session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].socket_id ==
0145             id.socket);
0146 
0147         TEST_ASSERT_VAL("Cpu map - Die ID doesn't match",
0148             session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].die_id == id.die);
0149         TEST_ASSERT_VAL("Cpu map - Node ID is set", id.node == -1);
0150         TEST_ASSERT_VAL("Cpu map - Thread is set", id.thread == -1);
0151     }
0152 
0153     // Test that core ID contains socket, die and core
0154     for (i = 0; i < perf_cpu_map__nr(map); i++) {
0155         id = aggr_cpu_id__core(perf_cpu_map__cpu(map, i), NULL);
0156         TEST_ASSERT_VAL("Core map - Core ID doesn't match",
0157             session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].core_id == id.core);
0158 
0159         TEST_ASSERT_VAL("Core map - Socket ID doesn't match",
0160             session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].socket_id ==
0161             id.socket);
0162 
0163         TEST_ASSERT_VAL("Core map - Die ID doesn't match",
0164             session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].die_id == id.die);
0165         TEST_ASSERT_VAL("Core map - Node ID is set", id.node == -1);
0166         TEST_ASSERT_VAL("Core map - Thread is set", id.thread == -1);
0167     }
0168 
0169     // Test that die ID contains socket and die
0170     for (i = 0; i < perf_cpu_map__nr(map); i++) {
0171         id = aggr_cpu_id__die(perf_cpu_map__cpu(map, i), NULL);
0172         TEST_ASSERT_VAL("Die map - Socket ID doesn't match",
0173             session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].socket_id ==
0174             id.socket);
0175 
0176         TEST_ASSERT_VAL("Die map - Die ID doesn't match",
0177             session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].die_id == id.die);
0178 
0179         TEST_ASSERT_VAL("Die map - Node ID is set", id.node == -1);
0180         TEST_ASSERT_VAL("Die map - Core is set", id.core == -1);
0181         TEST_ASSERT_VAL("Die map - CPU is set", id.cpu.cpu == -1);
0182         TEST_ASSERT_VAL("Die map - Thread is set", id.thread == -1);
0183     }
0184 
0185     // Test that socket ID contains only socket
0186     for (i = 0; i < perf_cpu_map__nr(map); i++) {
0187         id = aggr_cpu_id__socket(perf_cpu_map__cpu(map, i), NULL);
0188         TEST_ASSERT_VAL("Socket map - Socket ID doesn't match",
0189             session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].socket_id ==
0190             id.socket);
0191 
0192         TEST_ASSERT_VAL("Socket map - Node ID is set", id.node == -1);
0193         TEST_ASSERT_VAL("Socket map - Die ID is set", id.die == -1);
0194         TEST_ASSERT_VAL("Socket map - Core is set", id.core == -1);
0195         TEST_ASSERT_VAL("Socket map - CPU is set", id.cpu.cpu == -1);
0196         TEST_ASSERT_VAL("Socket map - Thread is set", id.thread == -1);
0197     }
0198 
0199     // Test that node ID contains only node
0200     for (i = 0; i < perf_cpu_map__nr(map); i++) {
0201         id = aggr_cpu_id__node(perf_cpu_map__cpu(map, i), NULL);
0202         TEST_ASSERT_VAL("Node map - Node ID doesn't match",
0203                 cpu__get_node(perf_cpu_map__cpu(map, i)) == id.node);
0204         TEST_ASSERT_VAL("Node map - Socket is set", id.socket == -1);
0205         TEST_ASSERT_VAL("Node map - Die ID is set", id.die == -1);
0206         TEST_ASSERT_VAL("Node map - Core is set", id.core == -1);
0207         TEST_ASSERT_VAL("Node map - CPU is set", id.cpu.cpu == -1);
0208         TEST_ASSERT_VAL("Node map - Thread is set", id.thread == -1);
0209     }
0210     perf_session__delete(session);
0211 
0212     return 0;
0213 }
0214 
0215 static int test__session_topology(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
0216 {
0217     char path[PATH_MAX];
0218     struct perf_cpu_map *map;
0219     int ret = TEST_FAIL;
0220 
0221     TEST_ASSERT_VAL("can't get templ file", !get_temp(path));
0222 
0223     pr_debug("templ file: %s\n", path);
0224 
0225     if (session_write_header(path))
0226         goto free_path;
0227 
0228     map = perf_cpu_map__new(NULL);
0229     if (map == NULL) {
0230         pr_debug("failed to get system cpumap\n");
0231         goto free_path;
0232     }
0233 
0234     ret = check_cpu_topology(path, map);
0235     perf_cpu_map__put(map);
0236 
0237 free_path:
0238     unlink(path);
0239     return ret;
0240 }
0241 
0242 DEFINE_SUITE("Session topology", session_topology);