18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <inttypes.h> 38c2ecf20Sopenharmony_ci#include <unistd.h> 48c2ecf20Sopenharmony_ci#include <sys/syscall.h> 58c2ecf20Sopenharmony_ci#include <sys/types.h> 68c2ecf20Sopenharmony_ci#include <sys/mman.h> 78c2ecf20Sopenharmony_ci#include <pthread.h> 88c2ecf20Sopenharmony_ci#include <stdlib.h> 98c2ecf20Sopenharmony_ci#include <stdio.h> 108c2ecf20Sopenharmony_ci#include "debug.h" 118c2ecf20Sopenharmony_ci#include "event.h" 128c2ecf20Sopenharmony_ci#include "tests.h" 138c2ecf20Sopenharmony_ci#include "machine.h" 148c2ecf20Sopenharmony_ci#include "thread_map.h" 158c2ecf20Sopenharmony_ci#include "map.h" 168c2ecf20Sopenharmony_ci#include "symbol.h" 178c2ecf20Sopenharmony_ci#include "util/synthetic-events.h" 188c2ecf20Sopenharmony_ci#include "thread.h" 198c2ecf20Sopenharmony_ci#include <internal/lib.h> // page_size 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define THREADS 4 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic int go_away; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct thread_data { 268c2ecf20Sopenharmony_ci pthread_t pt; 278c2ecf20Sopenharmony_ci pid_t tid; 288c2ecf20Sopenharmony_ci void *map; 298c2ecf20Sopenharmony_ci int ready[2]; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic struct thread_data threads[THREADS]; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int thread_init(struct thread_data *td) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci void *map; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci map = mmap(NULL, page_size, 398c2ecf20Sopenharmony_ci PROT_READ|PROT_WRITE|PROT_EXEC, 408c2ecf20Sopenharmony_ci MAP_SHARED|MAP_ANONYMOUS, -1, 0); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (map == MAP_FAILED) { 438c2ecf20Sopenharmony_ci perror("mmap failed"); 448c2ecf20Sopenharmony_ci return -1; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci td->map = map; 488c2ecf20Sopenharmony_ci td->tid = syscall(SYS_gettid); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci pr_debug("tid = %d, map = %p\n", td->tid, map); 518c2ecf20Sopenharmony_ci return 0; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic void *thread_fn(void *arg) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct thread_data *td = arg; 578c2ecf20Sopenharmony_ci ssize_t ret; 588c2ecf20Sopenharmony_ci int go = 0; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (thread_init(td)) 618c2ecf20Sopenharmony_ci return NULL; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* Signal thread_create thread is initialized. */ 648c2ecf20Sopenharmony_ci ret = write(td->ready[1], &go, sizeof(int)); 658c2ecf20Sopenharmony_ci if (ret != sizeof(int)) { 668c2ecf20Sopenharmony_ci pr_err("failed to notify\n"); 678c2ecf20Sopenharmony_ci return NULL; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci while (!go_away) { 718c2ecf20Sopenharmony_ci /* Waiting for main thread to kill us. */ 728c2ecf20Sopenharmony_ci usleep(100); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci munmap(td->map, page_size); 768c2ecf20Sopenharmony_ci return NULL; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int thread_create(int i) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct thread_data *td = &threads[i]; 828c2ecf20Sopenharmony_ci int err, go; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (pipe(td->ready)) 858c2ecf20Sopenharmony_ci return -1; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci err = pthread_create(&td->pt, NULL, thread_fn, td); 888c2ecf20Sopenharmony_ci if (!err) { 898c2ecf20Sopenharmony_ci /* Wait for thread initialization. */ 908c2ecf20Sopenharmony_ci ssize_t ret = read(td->ready[0], &go, sizeof(int)); 918c2ecf20Sopenharmony_ci err = ret != sizeof(int); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci close(td->ready[0]); 958c2ecf20Sopenharmony_ci close(td->ready[1]); 968c2ecf20Sopenharmony_ci return err; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int threads_create(void) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct thread_data *td0 = &threads[0]; 1028c2ecf20Sopenharmony_ci int i, err = 0; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci go_away = 0; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* 0 is main thread */ 1078c2ecf20Sopenharmony_ci if (thread_init(td0)) 1088c2ecf20Sopenharmony_ci return -1; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci for (i = 1; !err && i < THREADS; i++) 1118c2ecf20Sopenharmony_ci err = thread_create(i); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return err; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int threads_destroy(void) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct thread_data *td0 = &threads[0]; 1198c2ecf20Sopenharmony_ci int i, err = 0; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* cleanup the main thread */ 1228c2ecf20Sopenharmony_ci munmap(td0->map, page_size); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci go_away = 1; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci for (i = 1; !err && i < THREADS; i++) 1278c2ecf20Sopenharmony_ci err = pthread_join(threads[i].pt, NULL); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return err; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_citypedef int (*synth_cb)(struct machine *machine); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int synth_all(struct machine *machine) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci return perf_event__synthesize_threads(NULL, 1378c2ecf20Sopenharmony_ci perf_event__process, 1388c2ecf20Sopenharmony_ci machine, 0, 1); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int synth_process(struct machine *machine) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct perf_thread_map *map; 1448c2ecf20Sopenharmony_ci int err; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci map = thread_map__new_by_pid(getpid()); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci err = perf_event__synthesize_thread_map(NULL, map, 1498c2ecf20Sopenharmony_ci perf_event__process, 1508c2ecf20Sopenharmony_ci machine, 0); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci perf_thread_map__put(map); 1538c2ecf20Sopenharmony_ci return err; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic int mmap_events(synth_cb synth) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct machine *machine; 1598c2ecf20Sopenharmony_ci int err, i; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* 1628c2ecf20Sopenharmony_ci * The threads_create will not return before all threads 1638c2ecf20Sopenharmony_ci * are spawned and all created memory map. 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * They will loop until threads_destroy is called, so we 1668c2ecf20Sopenharmony_ci * can safely run synthesizing function. 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_ci TEST_ASSERT_VAL("failed to create threads", !threads_create()); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci machine = machine__new_host(); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci dump_trace = verbose > 1 ? 1 : 0; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci err = synth(machine); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci dump_trace = 0; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci TEST_ASSERT_VAL("failed to destroy threads", !threads_destroy()); 1798c2ecf20Sopenharmony_ci TEST_ASSERT_VAL("failed to synthesize maps", !err); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* 1828c2ecf20Sopenharmony_ci * All data is synthesized, try to find map for each 1838c2ecf20Sopenharmony_ci * thread object. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci for (i = 0; i < THREADS; i++) { 1868c2ecf20Sopenharmony_ci struct thread_data *td = &threads[i]; 1878c2ecf20Sopenharmony_ci struct addr_location al; 1888c2ecf20Sopenharmony_ci struct thread *thread; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci thread = machine__findnew_thread(machine, getpid(), td->tid); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci pr_debug("looking for map %p\n", td->map); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci thread__find_map(thread, PERF_RECORD_MISC_USER, 1958c2ecf20Sopenharmony_ci (unsigned long) (td->map + 1), &al); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci thread__put(thread); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (!al.map) { 2008c2ecf20Sopenharmony_ci pr_debug("failed, couldn't find map\n"); 2018c2ecf20Sopenharmony_ci err = -1; 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci pr_debug("map %p, addr %" PRIx64 "\n", al.map, al.map->start); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci machine__delete_threads(machine); 2098c2ecf20Sopenharmony_ci machine__delete(machine); 2108c2ecf20Sopenharmony_ci return err; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* 2148c2ecf20Sopenharmony_ci * This test creates 'THREADS' number of threads (including 2158c2ecf20Sopenharmony_ci * main thread) and each thread creates memory map. 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * When threads are created, we synthesize them with both 2188c2ecf20Sopenharmony_ci * (separate tests): 2198c2ecf20Sopenharmony_ci * perf_event__synthesize_thread_map (process based) 2208c2ecf20Sopenharmony_ci * perf_event__synthesize_threads (global) 2218c2ecf20Sopenharmony_ci * 2228c2ecf20Sopenharmony_ci * We test we can find all memory maps via: 2238c2ecf20Sopenharmony_ci * thread__find_map 2248c2ecf20Sopenharmony_ci * 2258c2ecf20Sopenharmony_ci * by using all thread objects. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_ciint test__mmap_thread_lookup(struct test *test __maybe_unused, int subtest __maybe_unused) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci /* perf_event__synthesize_threads synthesize */ 2308c2ecf20Sopenharmony_ci TEST_ASSERT_VAL("failed with sythesizing all", 2318c2ecf20Sopenharmony_ci !mmap_events(synth_all)); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* perf_event__synthesize_thread_map synthesize */ 2348c2ecf20Sopenharmony_ci TEST_ASSERT_VAL("failed with sythesizing process", 2358c2ecf20Sopenharmony_ci !mmap_events(synth_process)); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 239