18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include "util/debug.h" 48c2ecf20Sopenharmony_ci#include "util/dso.h" 58c2ecf20Sopenharmony_ci#include "util/event.h" 68c2ecf20Sopenharmony_ci#include "util/evlist.h" 78c2ecf20Sopenharmony_ci#include "util/machine.h" 88c2ecf20Sopenharmony_ci#include "util/map.h" 98c2ecf20Sopenharmony_ci#include "util/map_symbol.h" 108c2ecf20Sopenharmony_ci#include "util/branch.h" 118c2ecf20Sopenharmony_ci#include "util/memswap.h" 128c2ecf20Sopenharmony_ci#include "util/namespaces.h" 138c2ecf20Sopenharmony_ci#include "util/session.h" 148c2ecf20Sopenharmony_ci#include "util/stat.h" 158c2ecf20Sopenharmony_ci#include "util/symbol.h" 168c2ecf20Sopenharmony_ci#include "util/synthetic-events.h" 178c2ecf20Sopenharmony_ci#include "util/target.h" 188c2ecf20Sopenharmony_ci#include "util/time-utils.h" 198c2ecf20Sopenharmony_ci#include "util/cgroup.h" 208c2ecf20Sopenharmony_ci#include <linux/bitops.h> 218c2ecf20Sopenharmony_ci#include <linux/kernel.h> 228c2ecf20Sopenharmony_ci#include <linux/string.h> 238c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 248c2ecf20Sopenharmony_ci#include <linux/perf_event.h> 258c2ecf20Sopenharmony_ci#include <asm/bug.h> 268c2ecf20Sopenharmony_ci#include <perf/evsel.h> 278c2ecf20Sopenharmony_ci#include <internal/cpumap.h> 288c2ecf20Sopenharmony_ci#include <perf/cpumap.h> 298c2ecf20Sopenharmony_ci#include <internal/lib.h> // page_size 308c2ecf20Sopenharmony_ci#include <internal/threadmap.h> 318c2ecf20Sopenharmony_ci#include <perf/threadmap.h> 328c2ecf20Sopenharmony_ci#include <symbol/kallsyms.h> 338c2ecf20Sopenharmony_ci#include <dirent.h> 348c2ecf20Sopenharmony_ci#include <errno.h> 358c2ecf20Sopenharmony_ci#include <inttypes.h> 368c2ecf20Sopenharmony_ci#include <stdio.h> 378c2ecf20Sopenharmony_ci#include <string.h> 388c2ecf20Sopenharmony_ci#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ 398c2ecf20Sopenharmony_ci#include <api/fs/fs.h> 408c2ecf20Sopenharmony_ci#include <api/io.h> 418c2ecf20Sopenharmony_ci#include <sys/types.h> 428c2ecf20Sopenharmony_ci#include <sys/stat.h> 438c2ecf20Sopenharmony_ci#include <fcntl.h> 448c2ecf20Sopenharmony_ci#include <unistd.h> 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define DEFAULT_PROC_MAP_PARSE_TIMEOUT 500 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ciunsigned int proc_map_timeout = DEFAULT_PROC_MAP_PARSE_TIMEOUT; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciint perf_tool__process_synth_event(struct perf_tool *tool, 518c2ecf20Sopenharmony_ci union perf_event *event, 528c2ecf20Sopenharmony_ci struct machine *machine, 538c2ecf20Sopenharmony_ci perf_event__handler_t process) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct perf_sample synth_sample = { 568c2ecf20Sopenharmony_ci .pid = -1, 578c2ecf20Sopenharmony_ci .tid = -1, 588c2ecf20Sopenharmony_ci .time = -1, 598c2ecf20Sopenharmony_ci .stream_id = -1, 608c2ecf20Sopenharmony_ci .cpu = -1, 618c2ecf20Sopenharmony_ci .period = 1, 628c2ecf20Sopenharmony_ci .cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK, 638c2ecf20Sopenharmony_ci }; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return process(tool, event, &synth_sample, machine); 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* 698c2ecf20Sopenharmony_ci * Assumes that the first 4095 bytes of /proc/pid/stat contains 708c2ecf20Sopenharmony_ci * the comm, tgid and ppid. 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_cistatic int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len, 738c2ecf20Sopenharmony_ci pid_t *tgid, pid_t *ppid) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci char bf[4096]; 768c2ecf20Sopenharmony_ci int fd; 778c2ecf20Sopenharmony_ci size_t size = 0; 788c2ecf20Sopenharmony_ci ssize_t n; 798c2ecf20Sopenharmony_ci char *name, *tgids, *ppids; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci *tgid = -1; 828c2ecf20Sopenharmony_ci *ppid = -1; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci snprintf(bf, sizeof(bf), "/proc/%d/status", pid); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci fd = open(bf, O_RDONLY); 878c2ecf20Sopenharmony_ci if (fd < 0) { 888c2ecf20Sopenharmony_ci pr_debug("couldn't open %s\n", bf); 898c2ecf20Sopenharmony_ci return -1; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci n = read(fd, bf, sizeof(bf) - 1); 938c2ecf20Sopenharmony_ci close(fd); 948c2ecf20Sopenharmony_ci if (n <= 0) { 958c2ecf20Sopenharmony_ci pr_warning("Couldn't get COMM, tigd and ppid for pid %d\n", 968c2ecf20Sopenharmony_ci pid); 978c2ecf20Sopenharmony_ci return -1; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci bf[n] = '\0'; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci name = strstr(bf, "Name:"); 1028c2ecf20Sopenharmony_ci tgids = strstr(bf, "Tgid:"); 1038c2ecf20Sopenharmony_ci ppids = strstr(bf, "PPid:"); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (name) { 1068c2ecf20Sopenharmony_ci char *nl; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci name = skip_spaces(name + 5); /* strlen("Name:") */ 1098c2ecf20Sopenharmony_ci nl = strchr(name, '\n'); 1108c2ecf20Sopenharmony_ci if (nl) 1118c2ecf20Sopenharmony_ci *nl = '\0'; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci size = strlen(name); 1148c2ecf20Sopenharmony_ci if (size >= len) 1158c2ecf20Sopenharmony_ci size = len - 1; 1168c2ecf20Sopenharmony_ci memcpy(comm, name, size); 1178c2ecf20Sopenharmony_ci comm[size] = '\0'; 1188c2ecf20Sopenharmony_ci } else { 1198c2ecf20Sopenharmony_ci pr_debug("Name: string not found for pid %d\n", pid); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (tgids) { 1238c2ecf20Sopenharmony_ci tgids += 5; /* strlen("Tgid:") */ 1248c2ecf20Sopenharmony_ci *tgid = atoi(tgids); 1258c2ecf20Sopenharmony_ci } else { 1268c2ecf20Sopenharmony_ci pr_debug("Tgid: string not found for pid %d\n", pid); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (ppids) { 1308c2ecf20Sopenharmony_ci ppids += 5; /* strlen("PPid:") */ 1318c2ecf20Sopenharmony_ci *ppid = atoi(ppids); 1328c2ecf20Sopenharmony_ci } else { 1338c2ecf20Sopenharmony_ci pr_debug("PPid: string not found for pid %d\n", pid); 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int perf_event__prepare_comm(union perf_event *event, pid_t pid, 1408c2ecf20Sopenharmony_ci struct machine *machine, 1418c2ecf20Sopenharmony_ci pid_t *tgid, pid_t *ppid) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci size_t size; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci *ppid = -1; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci memset(&event->comm, 0, sizeof(event->comm)); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (machine__is_host(machine)) { 1508c2ecf20Sopenharmony_ci if (perf_event__get_comm_ids(pid, event->comm.comm, 1518c2ecf20Sopenharmony_ci sizeof(event->comm.comm), 1528c2ecf20Sopenharmony_ci tgid, ppid) != 0) { 1538c2ecf20Sopenharmony_ci return -1; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci } else { 1568c2ecf20Sopenharmony_ci *tgid = machine->pid; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (*tgid < 0) 1608c2ecf20Sopenharmony_ci return -1; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci event->comm.pid = *tgid; 1638c2ecf20Sopenharmony_ci event->comm.header.type = PERF_RECORD_COMM; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci size = strlen(event->comm.comm) + 1; 1668c2ecf20Sopenharmony_ci size = PERF_ALIGN(size, sizeof(u64)); 1678c2ecf20Sopenharmony_ci memset(event->comm.comm + size, 0, machine->id_hdr_size); 1688c2ecf20Sopenharmony_ci event->comm.header.size = (sizeof(event->comm) - 1698c2ecf20Sopenharmony_ci (sizeof(event->comm.comm) - size) + 1708c2ecf20Sopenharmony_ci machine->id_hdr_size); 1718c2ecf20Sopenharmony_ci event->comm.tid = pid; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cipid_t perf_event__synthesize_comm(struct perf_tool *tool, 1778c2ecf20Sopenharmony_ci union perf_event *event, pid_t pid, 1788c2ecf20Sopenharmony_ci perf_event__handler_t process, 1798c2ecf20Sopenharmony_ci struct machine *machine) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci pid_t tgid, ppid; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (perf_event__prepare_comm(event, pid, machine, &tgid, &ppid) != 0) 1848c2ecf20Sopenharmony_ci return -1; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (perf_tool__process_synth_event(tool, event, machine, process) != 0) 1878c2ecf20Sopenharmony_ci return -1; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return tgid; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic void perf_event__get_ns_link_info(pid_t pid, const char *ns, 1938c2ecf20Sopenharmony_ci struct perf_ns_link_info *ns_link_info) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct stat64 st; 1968c2ecf20Sopenharmony_ci char proc_ns[128]; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns); 1998c2ecf20Sopenharmony_ci if (stat64(proc_ns, &st) == 0) { 2008c2ecf20Sopenharmony_ci ns_link_info->dev = st.st_dev; 2018c2ecf20Sopenharmony_ci ns_link_info->ino = st.st_ino; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ciint perf_event__synthesize_namespaces(struct perf_tool *tool, 2068c2ecf20Sopenharmony_ci union perf_event *event, 2078c2ecf20Sopenharmony_ci pid_t pid, pid_t tgid, 2088c2ecf20Sopenharmony_ci perf_event__handler_t process, 2098c2ecf20Sopenharmony_ci struct machine *machine) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci u32 idx; 2128c2ecf20Sopenharmony_ci struct perf_ns_link_info *ns_link_info; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (!tool || !tool->namespace_events) 2158c2ecf20Sopenharmony_ci return 0; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci memset(&event->namespaces, 0, (sizeof(event->namespaces) + 2188c2ecf20Sopenharmony_ci (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 2198c2ecf20Sopenharmony_ci machine->id_hdr_size)); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci event->namespaces.pid = tgid; 2228c2ecf20Sopenharmony_ci event->namespaces.tid = pid; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci event->namespaces.nr_namespaces = NR_NAMESPACES; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci ns_link_info = event->namespaces.link_info; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci for (idx = 0; idx < event->namespaces.nr_namespaces; idx++) 2298c2ecf20Sopenharmony_ci perf_event__get_ns_link_info(pid, perf_ns__name(idx), 2308c2ecf20Sopenharmony_ci &ns_link_info[idx]); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci event->namespaces.header.type = PERF_RECORD_NAMESPACES; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci event->namespaces.header.size = (sizeof(event->namespaces) + 2358c2ecf20Sopenharmony_ci (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 2368c2ecf20Sopenharmony_ci machine->id_hdr_size); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (perf_tool__process_synth_event(tool, event, machine, process) != 0) 2398c2ecf20Sopenharmony_ci return -1; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return 0; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int perf_event__synthesize_fork(struct perf_tool *tool, 2458c2ecf20Sopenharmony_ci union perf_event *event, 2468c2ecf20Sopenharmony_ci pid_t pid, pid_t tgid, pid_t ppid, 2478c2ecf20Sopenharmony_ci perf_event__handler_t process, 2488c2ecf20Sopenharmony_ci struct machine *machine) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* 2538c2ecf20Sopenharmony_ci * for main thread set parent to ppid from status file. For other 2548c2ecf20Sopenharmony_ci * threads set parent pid to main thread. ie., assume main thread 2558c2ecf20Sopenharmony_ci * spawns all threads in a process 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci if (tgid == pid) { 2588c2ecf20Sopenharmony_ci event->fork.ppid = ppid; 2598c2ecf20Sopenharmony_ci event->fork.ptid = ppid; 2608c2ecf20Sopenharmony_ci } else { 2618c2ecf20Sopenharmony_ci event->fork.ppid = tgid; 2628c2ecf20Sopenharmony_ci event->fork.ptid = tgid; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci event->fork.pid = tgid; 2658c2ecf20Sopenharmony_ci event->fork.tid = pid; 2668c2ecf20Sopenharmony_ci event->fork.header.type = PERF_RECORD_FORK; 2678c2ecf20Sopenharmony_ci event->fork.header.misc = PERF_RECORD_MISC_FORK_EXEC; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (perf_tool__process_synth_event(tool, event, machine, process) != 0) 2728c2ecf20Sopenharmony_ci return -1; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return 0; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic bool read_proc_maps_line(struct io *io, __u64 *start, __u64 *end, 2788c2ecf20Sopenharmony_ci u32 *prot, u32 *flags, __u64 *offset, 2798c2ecf20Sopenharmony_ci u32 *maj, u32 *min, 2808c2ecf20Sopenharmony_ci __u64 *inode, 2818c2ecf20Sopenharmony_ci ssize_t pathname_size, char *pathname) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci __u64 temp; 2848c2ecf20Sopenharmony_ci int ch; 2858c2ecf20Sopenharmony_ci char *start_pathname = pathname; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (io__get_hex(io, start) != '-') 2888c2ecf20Sopenharmony_ci return false; 2898c2ecf20Sopenharmony_ci if (io__get_hex(io, end) != ' ') 2908c2ecf20Sopenharmony_ci return false; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* map protection and flags bits */ 2938c2ecf20Sopenharmony_ci *prot = 0; 2948c2ecf20Sopenharmony_ci ch = io__get_char(io); 2958c2ecf20Sopenharmony_ci if (ch == 'r') 2968c2ecf20Sopenharmony_ci *prot |= PROT_READ; 2978c2ecf20Sopenharmony_ci else if (ch != '-') 2988c2ecf20Sopenharmony_ci return false; 2998c2ecf20Sopenharmony_ci ch = io__get_char(io); 3008c2ecf20Sopenharmony_ci if (ch == 'w') 3018c2ecf20Sopenharmony_ci *prot |= PROT_WRITE; 3028c2ecf20Sopenharmony_ci else if (ch != '-') 3038c2ecf20Sopenharmony_ci return false; 3048c2ecf20Sopenharmony_ci ch = io__get_char(io); 3058c2ecf20Sopenharmony_ci if (ch == 'x') 3068c2ecf20Sopenharmony_ci *prot |= PROT_EXEC; 3078c2ecf20Sopenharmony_ci else if (ch != '-') 3088c2ecf20Sopenharmony_ci return false; 3098c2ecf20Sopenharmony_ci ch = io__get_char(io); 3108c2ecf20Sopenharmony_ci if (ch == 's') 3118c2ecf20Sopenharmony_ci *flags = MAP_SHARED; 3128c2ecf20Sopenharmony_ci else if (ch == 'p') 3138c2ecf20Sopenharmony_ci *flags = MAP_PRIVATE; 3148c2ecf20Sopenharmony_ci else 3158c2ecf20Sopenharmony_ci return false; 3168c2ecf20Sopenharmony_ci if (io__get_char(io) != ' ') 3178c2ecf20Sopenharmony_ci return false; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (io__get_hex(io, offset) != ' ') 3208c2ecf20Sopenharmony_ci return false; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (io__get_hex(io, &temp) != ':') 3238c2ecf20Sopenharmony_ci return false; 3248c2ecf20Sopenharmony_ci *maj = temp; 3258c2ecf20Sopenharmony_ci if (io__get_hex(io, &temp) != ' ') 3268c2ecf20Sopenharmony_ci return false; 3278c2ecf20Sopenharmony_ci *min = temp; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci ch = io__get_dec(io, inode); 3308c2ecf20Sopenharmony_ci if (ch != ' ') { 3318c2ecf20Sopenharmony_ci *pathname = '\0'; 3328c2ecf20Sopenharmony_ci return ch == '\n'; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci do { 3358c2ecf20Sopenharmony_ci ch = io__get_char(io); 3368c2ecf20Sopenharmony_ci } while (ch == ' '); 3378c2ecf20Sopenharmony_ci while (true) { 3388c2ecf20Sopenharmony_ci if (ch < 0) 3398c2ecf20Sopenharmony_ci return false; 3408c2ecf20Sopenharmony_ci if (ch == '\0' || ch == '\n' || 3418c2ecf20Sopenharmony_ci (pathname + 1 - start_pathname) >= pathname_size) { 3428c2ecf20Sopenharmony_ci *pathname = '\0'; 3438c2ecf20Sopenharmony_ci return true; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci *pathname++ = ch; 3468c2ecf20Sopenharmony_ci ch = io__get_char(io); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ciint perf_event__synthesize_mmap_events(struct perf_tool *tool, 3518c2ecf20Sopenharmony_ci union perf_event *event, 3528c2ecf20Sopenharmony_ci pid_t pid, pid_t tgid, 3538c2ecf20Sopenharmony_ci perf_event__handler_t process, 3548c2ecf20Sopenharmony_ci struct machine *machine, 3558c2ecf20Sopenharmony_ci bool mmap_data) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci unsigned long long t; 3588c2ecf20Sopenharmony_ci char bf[BUFSIZ]; 3598c2ecf20Sopenharmony_ci struct io io; 3608c2ecf20Sopenharmony_ci bool truncation = false; 3618c2ecf20Sopenharmony_ci unsigned long long timeout = proc_map_timeout * 1000000ULL; 3628c2ecf20Sopenharmony_ci int rc = 0; 3638c2ecf20Sopenharmony_ci const char *hugetlbfs_mnt = hugetlbfs__mountpoint(); 3648c2ecf20Sopenharmony_ci int hugetlbfs_mnt_len = hugetlbfs_mnt ? strlen(hugetlbfs_mnt) : 0; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (machine__is_default_guest(machine)) 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci snprintf(bf, sizeof(bf), "%s/proc/%d/task/%d/maps", 3708c2ecf20Sopenharmony_ci machine->root_dir, pid, pid); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci io.fd = open(bf, O_RDONLY, 0); 3738c2ecf20Sopenharmony_ci if (io.fd < 0) { 3748c2ecf20Sopenharmony_ci /* 3758c2ecf20Sopenharmony_ci * We raced with a task exiting - just return: 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_ci pr_debug("couldn't open %s\n", bf); 3788c2ecf20Sopenharmony_ci return -1; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci io__init(&io, io.fd, bf, sizeof(bf)); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci event->header.type = PERF_RECORD_MMAP2; 3838c2ecf20Sopenharmony_ci t = rdclock(); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci while (!io.eof) { 3868c2ecf20Sopenharmony_ci static const char anonstr[] = "//anon"; 3878c2ecf20Sopenharmony_ci size_t size, aligned_size; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* ensure null termination since stack will be reused. */ 3908c2ecf20Sopenharmony_ci event->mmap2.filename[0] = '\0'; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 3938c2ecf20Sopenharmony_ci if (!read_proc_maps_line(&io, 3948c2ecf20Sopenharmony_ci &event->mmap2.start, 3958c2ecf20Sopenharmony_ci &event->mmap2.len, 3968c2ecf20Sopenharmony_ci &event->mmap2.prot, 3978c2ecf20Sopenharmony_ci &event->mmap2.flags, 3988c2ecf20Sopenharmony_ci &event->mmap2.pgoff, 3998c2ecf20Sopenharmony_ci &event->mmap2.maj, 4008c2ecf20Sopenharmony_ci &event->mmap2.min, 4018c2ecf20Sopenharmony_ci &event->mmap2.ino, 4028c2ecf20Sopenharmony_ci sizeof(event->mmap2.filename), 4038c2ecf20Sopenharmony_ci event->mmap2.filename)) 4048c2ecf20Sopenharmony_ci continue; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if ((rdclock() - t) > timeout) { 4078c2ecf20Sopenharmony_ci pr_warning("Reading %s/proc/%d/task/%d/maps time out. " 4088c2ecf20Sopenharmony_ci "You may want to increase " 4098c2ecf20Sopenharmony_ci "the time limit by --proc-map-timeout\n", 4108c2ecf20Sopenharmony_ci machine->root_dir, pid, pid); 4118c2ecf20Sopenharmony_ci truncation = true; 4128c2ecf20Sopenharmony_ci goto out; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci event->mmap2.ino_generation = 0; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* 4188c2ecf20Sopenharmony_ci * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_ci if (machine__is_host(machine)) 4218c2ecf20Sopenharmony_ci event->header.misc = PERF_RECORD_MISC_USER; 4228c2ecf20Sopenharmony_ci else 4238c2ecf20Sopenharmony_ci event->header.misc = PERF_RECORD_MISC_GUEST_USER; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if ((event->mmap2.prot & PROT_EXEC) == 0) { 4268c2ecf20Sopenharmony_ci if (!mmap_data || (event->mmap2.prot & PROT_READ) == 0) 4278c2ecf20Sopenharmony_ci continue; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci event->header.misc |= PERF_RECORD_MISC_MMAP_DATA; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ciout: 4338c2ecf20Sopenharmony_ci if (truncation) 4348c2ecf20Sopenharmony_ci event->header.misc |= PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (!strcmp(event->mmap2.filename, "")) 4378c2ecf20Sopenharmony_ci strcpy(event->mmap2.filename, anonstr); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (hugetlbfs_mnt_len && 4408c2ecf20Sopenharmony_ci !strncmp(event->mmap2.filename, hugetlbfs_mnt, 4418c2ecf20Sopenharmony_ci hugetlbfs_mnt_len)) { 4428c2ecf20Sopenharmony_ci strcpy(event->mmap2.filename, anonstr); 4438c2ecf20Sopenharmony_ci event->mmap2.flags |= MAP_HUGETLB; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci size = strlen(event->mmap2.filename) + 1; 4478c2ecf20Sopenharmony_ci aligned_size = PERF_ALIGN(size, sizeof(u64)); 4488c2ecf20Sopenharmony_ci event->mmap2.len -= event->mmap.start; 4498c2ecf20Sopenharmony_ci event->mmap2.header.size = (sizeof(event->mmap2) - 4508c2ecf20Sopenharmony_ci (sizeof(event->mmap2.filename) - aligned_size)); 4518c2ecf20Sopenharmony_ci memset(event->mmap2.filename + size, 0, machine->id_hdr_size + 4528c2ecf20Sopenharmony_ci (aligned_size - size)); 4538c2ecf20Sopenharmony_ci event->mmap2.header.size += machine->id_hdr_size; 4548c2ecf20Sopenharmony_ci event->mmap2.pid = tgid; 4558c2ecf20Sopenharmony_ci event->mmap2.tid = pid; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { 4588c2ecf20Sopenharmony_ci rc = -1; 4598c2ecf20Sopenharmony_ci break; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (truncation) 4638c2ecf20Sopenharmony_ci break; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci close(io.fd); 4678c2ecf20Sopenharmony_ci return rc; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci#ifdef HAVE_FILE_HANDLE 4718c2ecf20Sopenharmony_cistatic int perf_event__synthesize_cgroup(struct perf_tool *tool, 4728c2ecf20Sopenharmony_ci union perf_event *event, 4738c2ecf20Sopenharmony_ci char *path, size_t mount_len, 4748c2ecf20Sopenharmony_ci perf_event__handler_t process, 4758c2ecf20Sopenharmony_ci struct machine *machine) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci size_t event_size = sizeof(event->cgroup) - sizeof(event->cgroup.path); 4788c2ecf20Sopenharmony_ci size_t path_len = strlen(path) - mount_len + 1; 4798c2ecf20Sopenharmony_ci struct { 4808c2ecf20Sopenharmony_ci struct file_handle fh; 4818c2ecf20Sopenharmony_ci uint64_t cgroup_id; 4828c2ecf20Sopenharmony_ci } handle; 4838c2ecf20Sopenharmony_ci int mount_id; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci while (path_len % sizeof(u64)) 4868c2ecf20Sopenharmony_ci path[mount_len + path_len++] = '\0'; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci memset(&event->cgroup, 0, event_size); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci event->cgroup.header.type = PERF_RECORD_CGROUP; 4918c2ecf20Sopenharmony_ci event->cgroup.header.size = event_size + path_len + machine->id_hdr_size; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci handle.fh.handle_bytes = sizeof(handle.cgroup_id); 4948c2ecf20Sopenharmony_ci if (name_to_handle_at(AT_FDCWD, path, &handle.fh, &mount_id, 0) < 0) { 4958c2ecf20Sopenharmony_ci pr_debug("stat failed: %s\n", path); 4968c2ecf20Sopenharmony_ci return -1; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci event->cgroup.id = handle.cgroup_id; 5008c2ecf20Sopenharmony_ci strncpy(event->cgroup.path, path + mount_len, path_len); 5018c2ecf20Sopenharmony_ci memset(event->cgroup.path + path_len, 0, machine->id_hdr_size); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (perf_tool__process_synth_event(tool, event, machine, process) < 0) { 5048c2ecf20Sopenharmony_ci pr_debug("process synth event failed\n"); 5058c2ecf20Sopenharmony_ci return -1; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci return 0; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic int perf_event__walk_cgroup_tree(struct perf_tool *tool, 5128c2ecf20Sopenharmony_ci union perf_event *event, 5138c2ecf20Sopenharmony_ci char *path, size_t mount_len, 5148c2ecf20Sopenharmony_ci perf_event__handler_t process, 5158c2ecf20Sopenharmony_ci struct machine *machine) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci size_t pos = strlen(path); 5188c2ecf20Sopenharmony_ci DIR *d; 5198c2ecf20Sopenharmony_ci struct dirent *dent; 5208c2ecf20Sopenharmony_ci int ret = 0; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (perf_event__synthesize_cgroup(tool, event, path, mount_len, 5238c2ecf20Sopenharmony_ci process, machine) < 0) 5248c2ecf20Sopenharmony_ci return -1; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci d = opendir(path); 5278c2ecf20Sopenharmony_ci if (d == NULL) { 5288c2ecf20Sopenharmony_ci pr_debug("failed to open directory: %s\n", path); 5298c2ecf20Sopenharmony_ci return -1; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci while ((dent = readdir(d)) != NULL) { 5338c2ecf20Sopenharmony_ci if (dent->d_type != DT_DIR) 5348c2ecf20Sopenharmony_ci continue; 5358c2ecf20Sopenharmony_ci if (!strcmp(dent->d_name, ".") || 5368c2ecf20Sopenharmony_ci !strcmp(dent->d_name, "..")) 5378c2ecf20Sopenharmony_ci continue; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* any sane path should be less than PATH_MAX */ 5408c2ecf20Sopenharmony_ci if (strlen(path) + strlen(dent->d_name) + 1 >= PATH_MAX) 5418c2ecf20Sopenharmony_ci continue; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (path[pos - 1] != '/') 5448c2ecf20Sopenharmony_ci strcat(path, "/"); 5458c2ecf20Sopenharmony_ci strcat(path, dent->d_name); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci ret = perf_event__walk_cgroup_tree(tool, event, path, 5488c2ecf20Sopenharmony_ci mount_len, process, machine); 5498c2ecf20Sopenharmony_ci if (ret < 0) 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci path[pos] = '\0'; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci closedir(d); 5568c2ecf20Sopenharmony_ci return ret; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ciint perf_event__synthesize_cgroups(struct perf_tool *tool, 5608c2ecf20Sopenharmony_ci perf_event__handler_t process, 5618c2ecf20Sopenharmony_ci struct machine *machine) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci union perf_event event; 5648c2ecf20Sopenharmony_ci char cgrp_root[PATH_MAX]; 5658c2ecf20Sopenharmony_ci size_t mount_len; /* length of mount point in the path */ 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (!tool || !tool->cgroup_events) 5688c2ecf20Sopenharmony_ci return 0; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (cgroupfs_find_mountpoint(cgrp_root, PATH_MAX, "perf_event") < 0) { 5718c2ecf20Sopenharmony_ci pr_debug("cannot find cgroup mount point\n"); 5728c2ecf20Sopenharmony_ci return -1; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci mount_len = strlen(cgrp_root); 5768c2ecf20Sopenharmony_ci /* make sure the path starts with a slash (after mount point) */ 5778c2ecf20Sopenharmony_ci strcat(cgrp_root, "/"); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (perf_event__walk_cgroup_tree(tool, &event, cgrp_root, mount_len, 5808c2ecf20Sopenharmony_ci process, machine) < 0) 5818c2ecf20Sopenharmony_ci return -1; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return 0; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci#else 5868c2ecf20Sopenharmony_ciint perf_event__synthesize_cgroups(struct perf_tool *tool __maybe_unused, 5878c2ecf20Sopenharmony_ci perf_event__handler_t process __maybe_unused, 5888c2ecf20Sopenharmony_ci struct machine *machine __maybe_unused) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci return -1; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci#endif 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ciint perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process, 5958c2ecf20Sopenharmony_ci struct machine *machine) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci int rc = 0; 5988c2ecf20Sopenharmony_ci struct map *pos; 5998c2ecf20Sopenharmony_ci struct maps *maps = machine__kernel_maps(machine); 6008c2ecf20Sopenharmony_ci union perf_event *event = zalloc((sizeof(event->mmap) + 6018c2ecf20Sopenharmony_ci machine->id_hdr_size)); 6028c2ecf20Sopenharmony_ci if (event == NULL) { 6038c2ecf20Sopenharmony_ci pr_debug("Not enough memory synthesizing mmap event " 6048c2ecf20Sopenharmony_ci "for kernel modules\n"); 6058c2ecf20Sopenharmony_ci return -1; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci event->header.type = PERF_RECORD_MMAP; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* 6118c2ecf20Sopenharmony_ci * kernel uses 0 for user space maps, see kernel/perf_event.c 6128c2ecf20Sopenharmony_ci * __perf_event_mmap 6138c2ecf20Sopenharmony_ci */ 6148c2ecf20Sopenharmony_ci if (machine__is_host(machine)) 6158c2ecf20Sopenharmony_ci event->header.misc = PERF_RECORD_MISC_KERNEL; 6168c2ecf20Sopenharmony_ci else 6178c2ecf20Sopenharmony_ci event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci maps__for_each_entry(maps, pos) { 6208c2ecf20Sopenharmony_ci size_t size; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (!__map__is_kmodule(pos)) 6238c2ecf20Sopenharmony_ci continue; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); 6268c2ecf20Sopenharmony_ci event->mmap.header.type = PERF_RECORD_MMAP; 6278c2ecf20Sopenharmony_ci event->mmap.header.size = (sizeof(event->mmap) - 6288c2ecf20Sopenharmony_ci (sizeof(event->mmap.filename) - size)); 6298c2ecf20Sopenharmony_ci memset(event->mmap.filename + size, 0, machine->id_hdr_size); 6308c2ecf20Sopenharmony_ci event->mmap.header.size += machine->id_hdr_size; 6318c2ecf20Sopenharmony_ci event->mmap.start = pos->start; 6328c2ecf20Sopenharmony_ci event->mmap.len = pos->end - pos->start; 6338c2ecf20Sopenharmony_ci event->mmap.pid = machine->pid; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci memcpy(event->mmap.filename, pos->dso->long_name, 6368c2ecf20Sopenharmony_ci pos->dso->long_name_len + 1); 6378c2ecf20Sopenharmony_ci if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { 6388c2ecf20Sopenharmony_ci rc = -1; 6398c2ecf20Sopenharmony_ci break; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci free(event); 6448c2ecf20Sopenharmony_ci return rc; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic int __event__synthesize_thread(union perf_event *comm_event, 6488c2ecf20Sopenharmony_ci union perf_event *mmap_event, 6498c2ecf20Sopenharmony_ci union perf_event *fork_event, 6508c2ecf20Sopenharmony_ci union perf_event *namespaces_event, 6518c2ecf20Sopenharmony_ci pid_t pid, int full, perf_event__handler_t process, 6528c2ecf20Sopenharmony_ci struct perf_tool *tool, struct machine *machine, bool mmap_data) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci char filename[PATH_MAX]; 6558c2ecf20Sopenharmony_ci DIR *tasks; 6568c2ecf20Sopenharmony_ci struct dirent *dirent; 6578c2ecf20Sopenharmony_ci pid_t tgid, ppid; 6588c2ecf20Sopenharmony_ci int rc = 0; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* special case: only send one comm event using passed in pid */ 6618c2ecf20Sopenharmony_ci if (!full) { 6628c2ecf20Sopenharmony_ci tgid = perf_event__synthesize_comm(tool, comm_event, pid, 6638c2ecf20Sopenharmony_ci process, machine); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (tgid == -1) 6668c2ecf20Sopenharmony_ci return -1; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci if (perf_event__synthesize_namespaces(tool, namespaces_event, pid, 6698c2ecf20Sopenharmony_ci tgid, process, machine) < 0) 6708c2ecf20Sopenharmony_ci return -1; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* 6738c2ecf20Sopenharmony_ci * send mmap only for thread group leader 6748c2ecf20Sopenharmony_ci * see thread__init_maps() 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_ci if (pid == tgid && 6778c2ecf20Sopenharmony_ci perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 6788c2ecf20Sopenharmony_ci process, machine, mmap_data)) 6798c2ecf20Sopenharmony_ci return -1; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci return 0; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (machine__is_default_guest(machine)) 6858c2ecf20Sopenharmony_ci return 0; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci snprintf(filename, sizeof(filename), "%s/proc/%d/task", 6888c2ecf20Sopenharmony_ci machine->root_dir, pid); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci tasks = opendir(filename); 6918c2ecf20Sopenharmony_ci if (tasks == NULL) { 6928c2ecf20Sopenharmony_ci pr_debug("couldn't open %s\n", filename); 6938c2ecf20Sopenharmony_ci return 0; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci while ((dirent = readdir(tasks)) != NULL) { 6978c2ecf20Sopenharmony_ci char *end; 6988c2ecf20Sopenharmony_ci pid_t _pid; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci _pid = strtol(dirent->d_name, &end, 10); 7018c2ecf20Sopenharmony_ci if (*end) 7028c2ecf20Sopenharmony_ci continue; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci rc = -1; 7058c2ecf20Sopenharmony_ci if (perf_event__prepare_comm(comm_event, _pid, machine, 7068c2ecf20Sopenharmony_ci &tgid, &ppid) != 0) 7078c2ecf20Sopenharmony_ci break; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid, 7108c2ecf20Sopenharmony_ci ppid, process, machine) < 0) 7118c2ecf20Sopenharmony_ci break; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid, 7148c2ecf20Sopenharmony_ci tgid, process, machine) < 0) 7158c2ecf20Sopenharmony_ci break; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* 7188c2ecf20Sopenharmony_ci * Send the prepared comm event 7198c2ecf20Sopenharmony_ci */ 7208c2ecf20Sopenharmony_ci if (perf_tool__process_synth_event(tool, comm_event, machine, process) != 0) 7218c2ecf20Sopenharmony_ci break; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci rc = 0; 7248c2ecf20Sopenharmony_ci if (_pid == pid) { 7258c2ecf20Sopenharmony_ci /* process the parent's maps too */ 7268c2ecf20Sopenharmony_ci rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 7278c2ecf20Sopenharmony_ci process, machine, mmap_data); 7288c2ecf20Sopenharmony_ci if (rc) 7298c2ecf20Sopenharmony_ci break; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci closedir(tasks); 7348c2ecf20Sopenharmony_ci return rc; 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ciint perf_event__synthesize_thread_map(struct perf_tool *tool, 7388c2ecf20Sopenharmony_ci struct perf_thread_map *threads, 7398c2ecf20Sopenharmony_ci perf_event__handler_t process, 7408c2ecf20Sopenharmony_ci struct machine *machine, 7418c2ecf20Sopenharmony_ci bool mmap_data) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci union perf_event *comm_event, *mmap_event, *fork_event; 7448c2ecf20Sopenharmony_ci union perf_event *namespaces_event; 7458c2ecf20Sopenharmony_ci int err = -1, thread, j; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 7488c2ecf20Sopenharmony_ci if (comm_event == NULL) 7498c2ecf20Sopenharmony_ci goto out; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); 7528c2ecf20Sopenharmony_ci if (mmap_event == NULL) 7538c2ecf20Sopenharmony_ci goto out_free_comm; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); 7568c2ecf20Sopenharmony_ci if (fork_event == NULL) 7578c2ecf20Sopenharmony_ci goto out_free_mmap; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci namespaces_event = malloc(sizeof(namespaces_event->namespaces) + 7608c2ecf20Sopenharmony_ci (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 7618c2ecf20Sopenharmony_ci machine->id_hdr_size); 7628c2ecf20Sopenharmony_ci if (namespaces_event == NULL) 7638c2ecf20Sopenharmony_ci goto out_free_fork; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci err = 0; 7668c2ecf20Sopenharmony_ci for (thread = 0; thread < threads->nr; ++thread) { 7678c2ecf20Sopenharmony_ci if (__event__synthesize_thread(comm_event, mmap_event, 7688c2ecf20Sopenharmony_ci fork_event, namespaces_event, 7698c2ecf20Sopenharmony_ci perf_thread_map__pid(threads, thread), 0, 7708c2ecf20Sopenharmony_ci process, tool, machine, 7718c2ecf20Sopenharmony_ci mmap_data)) { 7728c2ecf20Sopenharmony_ci err = -1; 7738c2ecf20Sopenharmony_ci break; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci /* 7778c2ecf20Sopenharmony_ci * comm.pid is set to thread group id by 7788c2ecf20Sopenharmony_ci * perf_event__synthesize_comm 7798c2ecf20Sopenharmony_ci */ 7808c2ecf20Sopenharmony_ci if ((int) comm_event->comm.pid != perf_thread_map__pid(threads, thread)) { 7818c2ecf20Sopenharmony_ci bool need_leader = true; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci /* is thread group leader in thread_map? */ 7848c2ecf20Sopenharmony_ci for (j = 0; j < threads->nr; ++j) { 7858c2ecf20Sopenharmony_ci if ((int) comm_event->comm.pid == perf_thread_map__pid(threads, j)) { 7868c2ecf20Sopenharmony_ci need_leader = false; 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci /* if not, generate events for it */ 7928c2ecf20Sopenharmony_ci if (need_leader && 7938c2ecf20Sopenharmony_ci __event__synthesize_thread(comm_event, mmap_event, 7948c2ecf20Sopenharmony_ci fork_event, namespaces_event, 7958c2ecf20Sopenharmony_ci comm_event->comm.pid, 0, 7968c2ecf20Sopenharmony_ci process, tool, machine, 7978c2ecf20Sopenharmony_ci mmap_data)) { 7988c2ecf20Sopenharmony_ci err = -1; 7998c2ecf20Sopenharmony_ci break; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci free(namespaces_event); 8048c2ecf20Sopenharmony_ciout_free_fork: 8058c2ecf20Sopenharmony_ci free(fork_event); 8068c2ecf20Sopenharmony_ciout_free_mmap: 8078c2ecf20Sopenharmony_ci free(mmap_event); 8088c2ecf20Sopenharmony_ciout_free_comm: 8098c2ecf20Sopenharmony_ci free(comm_event); 8108c2ecf20Sopenharmony_ciout: 8118c2ecf20Sopenharmony_ci return err; 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic int __perf_event__synthesize_threads(struct perf_tool *tool, 8158c2ecf20Sopenharmony_ci perf_event__handler_t process, 8168c2ecf20Sopenharmony_ci struct machine *machine, 8178c2ecf20Sopenharmony_ci bool mmap_data, 8188c2ecf20Sopenharmony_ci struct dirent **dirent, 8198c2ecf20Sopenharmony_ci int start, 8208c2ecf20Sopenharmony_ci int num) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci union perf_event *comm_event, *mmap_event, *fork_event; 8238c2ecf20Sopenharmony_ci union perf_event *namespaces_event; 8248c2ecf20Sopenharmony_ci int err = -1; 8258c2ecf20Sopenharmony_ci char *end; 8268c2ecf20Sopenharmony_ci pid_t pid; 8278c2ecf20Sopenharmony_ci int i; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 8308c2ecf20Sopenharmony_ci if (comm_event == NULL) 8318c2ecf20Sopenharmony_ci goto out; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); 8348c2ecf20Sopenharmony_ci if (mmap_event == NULL) 8358c2ecf20Sopenharmony_ci goto out_free_comm; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); 8388c2ecf20Sopenharmony_ci if (fork_event == NULL) 8398c2ecf20Sopenharmony_ci goto out_free_mmap; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci namespaces_event = malloc(sizeof(namespaces_event->namespaces) + 8428c2ecf20Sopenharmony_ci (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 8438c2ecf20Sopenharmony_ci machine->id_hdr_size); 8448c2ecf20Sopenharmony_ci if (namespaces_event == NULL) 8458c2ecf20Sopenharmony_ci goto out_free_fork; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci for (i = start; i < start + num; i++) { 8488c2ecf20Sopenharmony_ci if (!isdigit(dirent[i]->d_name[0])) 8498c2ecf20Sopenharmony_ci continue; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci pid = (pid_t)strtol(dirent[i]->d_name, &end, 10); 8528c2ecf20Sopenharmony_ci /* only interested in proper numerical dirents */ 8538c2ecf20Sopenharmony_ci if (*end) 8548c2ecf20Sopenharmony_ci continue; 8558c2ecf20Sopenharmony_ci /* 8568c2ecf20Sopenharmony_ci * We may race with exiting thread, so don't stop just because 8578c2ecf20Sopenharmony_ci * one thread couldn't be synthesized. 8588c2ecf20Sopenharmony_ci */ 8598c2ecf20Sopenharmony_ci __event__synthesize_thread(comm_event, mmap_event, fork_event, 8608c2ecf20Sopenharmony_ci namespaces_event, pid, 1, process, 8618c2ecf20Sopenharmony_ci tool, machine, mmap_data); 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci err = 0; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci free(namespaces_event); 8668c2ecf20Sopenharmony_ciout_free_fork: 8678c2ecf20Sopenharmony_ci free(fork_event); 8688c2ecf20Sopenharmony_ciout_free_mmap: 8698c2ecf20Sopenharmony_ci free(mmap_event); 8708c2ecf20Sopenharmony_ciout_free_comm: 8718c2ecf20Sopenharmony_ci free(comm_event); 8728c2ecf20Sopenharmony_ciout: 8738c2ecf20Sopenharmony_ci return err; 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistruct synthesize_threads_arg { 8778c2ecf20Sopenharmony_ci struct perf_tool *tool; 8788c2ecf20Sopenharmony_ci perf_event__handler_t process; 8798c2ecf20Sopenharmony_ci struct machine *machine; 8808c2ecf20Sopenharmony_ci bool mmap_data; 8818c2ecf20Sopenharmony_ci struct dirent **dirent; 8828c2ecf20Sopenharmony_ci int num; 8838c2ecf20Sopenharmony_ci int start; 8848c2ecf20Sopenharmony_ci}; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic void *synthesize_threads_worker(void *arg) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci struct synthesize_threads_arg *args = arg; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci __perf_event__synthesize_threads(args->tool, args->process, 8918c2ecf20Sopenharmony_ci args->machine, args->mmap_data, 8928c2ecf20Sopenharmony_ci args->dirent, 8938c2ecf20Sopenharmony_ci args->start, args->num); 8948c2ecf20Sopenharmony_ci return NULL; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ciint perf_event__synthesize_threads(struct perf_tool *tool, 8988c2ecf20Sopenharmony_ci perf_event__handler_t process, 8998c2ecf20Sopenharmony_ci struct machine *machine, 9008c2ecf20Sopenharmony_ci bool mmap_data, 9018c2ecf20Sopenharmony_ci unsigned int nr_threads_synthesize) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci struct synthesize_threads_arg *args = NULL; 9048c2ecf20Sopenharmony_ci pthread_t *synthesize_threads = NULL; 9058c2ecf20Sopenharmony_ci char proc_path[PATH_MAX]; 9068c2ecf20Sopenharmony_ci struct dirent **dirent; 9078c2ecf20Sopenharmony_ci int num_per_thread; 9088c2ecf20Sopenharmony_ci int m, n, i, j; 9098c2ecf20Sopenharmony_ci int thread_nr; 9108c2ecf20Sopenharmony_ci int base = 0; 9118c2ecf20Sopenharmony_ci int err = -1; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if (machine__is_default_guest(machine)) 9158c2ecf20Sopenharmony_ci return 0; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); 9188c2ecf20Sopenharmony_ci n = scandir(proc_path, &dirent, 0, alphasort); 9198c2ecf20Sopenharmony_ci if (n < 0) 9208c2ecf20Sopenharmony_ci return err; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (nr_threads_synthesize == UINT_MAX) 9238c2ecf20Sopenharmony_ci thread_nr = sysconf(_SC_NPROCESSORS_ONLN); 9248c2ecf20Sopenharmony_ci else 9258c2ecf20Sopenharmony_ci thread_nr = nr_threads_synthesize; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci if (thread_nr <= 1) { 9288c2ecf20Sopenharmony_ci err = __perf_event__synthesize_threads(tool, process, 9298c2ecf20Sopenharmony_ci machine, mmap_data, 9308c2ecf20Sopenharmony_ci dirent, base, n); 9318c2ecf20Sopenharmony_ci goto free_dirent; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci if (thread_nr > n) 9348c2ecf20Sopenharmony_ci thread_nr = n; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci synthesize_threads = calloc(sizeof(pthread_t), thread_nr); 9378c2ecf20Sopenharmony_ci if (synthesize_threads == NULL) 9388c2ecf20Sopenharmony_ci goto free_dirent; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci args = calloc(sizeof(*args), thread_nr); 9418c2ecf20Sopenharmony_ci if (args == NULL) 9428c2ecf20Sopenharmony_ci goto free_threads; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci num_per_thread = n / thread_nr; 9458c2ecf20Sopenharmony_ci m = n % thread_nr; 9468c2ecf20Sopenharmony_ci for (i = 0; i < thread_nr; i++) { 9478c2ecf20Sopenharmony_ci args[i].tool = tool; 9488c2ecf20Sopenharmony_ci args[i].process = process; 9498c2ecf20Sopenharmony_ci args[i].machine = machine; 9508c2ecf20Sopenharmony_ci args[i].mmap_data = mmap_data; 9518c2ecf20Sopenharmony_ci args[i].dirent = dirent; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci for (i = 0; i < m; i++) { 9548c2ecf20Sopenharmony_ci args[i].num = num_per_thread + 1; 9558c2ecf20Sopenharmony_ci args[i].start = i * args[i].num; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci if (i != 0) 9588c2ecf20Sopenharmony_ci base = args[i-1].start + args[i-1].num; 9598c2ecf20Sopenharmony_ci for (j = i; j < thread_nr; j++) { 9608c2ecf20Sopenharmony_ci args[j].num = num_per_thread; 9618c2ecf20Sopenharmony_ci args[j].start = base + (j - i) * args[i].num; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci for (i = 0; i < thread_nr; i++) { 9658c2ecf20Sopenharmony_ci if (pthread_create(&synthesize_threads[i], NULL, 9668c2ecf20Sopenharmony_ci synthesize_threads_worker, &args[i])) 9678c2ecf20Sopenharmony_ci goto out_join; 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci err = 0; 9708c2ecf20Sopenharmony_ciout_join: 9718c2ecf20Sopenharmony_ci for (i = 0; i < thread_nr; i++) 9728c2ecf20Sopenharmony_ci pthread_join(synthesize_threads[i], NULL); 9738c2ecf20Sopenharmony_ci free(args); 9748c2ecf20Sopenharmony_cifree_threads: 9758c2ecf20Sopenharmony_ci free(synthesize_threads); 9768c2ecf20Sopenharmony_cifree_dirent: 9778c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) 9788c2ecf20Sopenharmony_ci zfree(&dirent[i]); 9798c2ecf20Sopenharmony_ci free(dirent); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci return err; 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ciint __weak perf_event__synthesize_extra_kmaps(struct perf_tool *tool __maybe_unused, 9858c2ecf20Sopenharmony_ci perf_event__handler_t process __maybe_unused, 9868c2ecf20Sopenharmony_ci struct machine *machine __maybe_unused) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci return 0; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 9928c2ecf20Sopenharmony_ci perf_event__handler_t process, 9938c2ecf20Sopenharmony_ci struct machine *machine) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci size_t size; 9968c2ecf20Sopenharmony_ci struct map *map = machine__kernel_map(machine); 9978c2ecf20Sopenharmony_ci struct kmap *kmap; 9988c2ecf20Sopenharmony_ci int err; 9998c2ecf20Sopenharmony_ci union perf_event *event; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (map == NULL) 10028c2ecf20Sopenharmony_ci return -1; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci kmap = map__kmap(map); 10058c2ecf20Sopenharmony_ci if (!kmap->ref_reloc_sym) 10068c2ecf20Sopenharmony_ci return -1; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci /* 10098c2ecf20Sopenharmony_ci * We should get this from /sys/kernel/sections/.text, but till that is 10108c2ecf20Sopenharmony_ci * available use this, and after it is use this as a fallback for older 10118c2ecf20Sopenharmony_ci * kernels. 10128c2ecf20Sopenharmony_ci */ 10138c2ecf20Sopenharmony_ci event = zalloc((sizeof(event->mmap) + machine->id_hdr_size)); 10148c2ecf20Sopenharmony_ci if (event == NULL) { 10158c2ecf20Sopenharmony_ci pr_debug("Not enough memory synthesizing mmap event " 10168c2ecf20Sopenharmony_ci "for kernel modules\n"); 10178c2ecf20Sopenharmony_ci return -1; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci if (machine__is_host(machine)) { 10218c2ecf20Sopenharmony_ci /* 10228c2ecf20Sopenharmony_ci * kernel uses PERF_RECORD_MISC_USER for user space maps, 10238c2ecf20Sopenharmony_ci * see kernel/perf_event.c __perf_event_mmap 10248c2ecf20Sopenharmony_ci */ 10258c2ecf20Sopenharmony_ci event->header.misc = PERF_RECORD_MISC_KERNEL; 10268c2ecf20Sopenharmony_ci } else { 10278c2ecf20Sopenharmony_ci event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 10318c2ecf20Sopenharmony_ci "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1; 10328c2ecf20Sopenharmony_ci size = PERF_ALIGN(size, sizeof(u64)); 10338c2ecf20Sopenharmony_ci event->mmap.header.type = PERF_RECORD_MMAP; 10348c2ecf20Sopenharmony_ci event->mmap.header.size = (sizeof(event->mmap) - 10358c2ecf20Sopenharmony_ci (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); 10368c2ecf20Sopenharmony_ci event->mmap.pgoff = kmap->ref_reloc_sym->addr; 10378c2ecf20Sopenharmony_ci event->mmap.start = map->start; 10388c2ecf20Sopenharmony_ci event->mmap.len = map->end - event->mmap.start; 10398c2ecf20Sopenharmony_ci event->mmap.pid = machine->pid; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci err = perf_tool__process_synth_event(tool, event, machine, process); 10428c2ecf20Sopenharmony_ci free(event); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci return err; 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ciint perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 10488c2ecf20Sopenharmony_ci perf_event__handler_t process, 10498c2ecf20Sopenharmony_ci struct machine *machine) 10508c2ecf20Sopenharmony_ci{ 10518c2ecf20Sopenharmony_ci int err; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci err = __perf_event__synthesize_kernel_mmap(tool, process, machine); 10548c2ecf20Sopenharmony_ci if (err < 0) 10558c2ecf20Sopenharmony_ci return err; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci return perf_event__synthesize_extra_kmaps(tool, process, machine); 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ciint perf_event__synthesize_thread_map2(struct perf_tool *tool, 10618c2ecf20Sopenharmony_ci struct perf_thread_map *threads, 10628c2ecf20Sopenharmony_ci perf_event__handler_t process, 10638c2ecf20Sopenharmony_ci struct machine *machine) 10648c2ecf20Sopenharmony_ci{ 10658c2ecf20Sopenharmony_ci union perf_event *event; 10668c2ecf20Sopenharmony_ci int i, err, size; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci size = sizeof(event->thread_map); 10698c2ecf20Sopenharmony_ci size += threads->nr * sizeof(event->thread_map.entries[0]); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci event = zalloc(size); 10728c2ecf20Sopenharmony_ci if (!event) 10738c2ecf20Sopenharmony_ci return -ENOMEM; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci event->header.type = PERF_RECORD_THREAD_MAP; 10768c2ecf20Sopenharmony_ci event->header.size = size; 10778c2ecf20Sopenharmony_ci event->thread_map.nr = threads->nr; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci for (i = 0; i < threads->nr; i++) { 10808c2ecf20Sopenharmony_ci struct perf_record_thread_map_entry *entry = &event->thread_map.entries[i]; 10818c2ecf20Sopenharmony_ci char *comm = perf_thread_map__comm(threads, i); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci if (!comm) 10848c2ecf20Sopenharmony_ci comm = (char *) ""; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci entry->pid = perf_thread_map__pid(threads, i); 10878c2ecf20Sopenharmony_ci strncpy((char *) &entry->comm, comm, sizeof(entry->comm)); 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci err = process(tool, event, NULL, machine); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci free(event); 10938c2ecf20Sopenharmony_ci return err; 10948c2ecf20Sopenharmony_ci} 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_cistatic void synthesize_cpus(struct cpu_map_entries *cpus, 10978c2ecf20Sopenharmony_ci struct perf_cpu_map *map) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci int i; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci cpus->nr = map->nr; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci for (i = 0; i < map->nr; i++) 11048c2ecf20Sopenharmony_ci cpus->cpu[i] = map->map[i]; 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cistatic void synthesize_mask(struct perf_record_record_cpu_map *mask, 11088c2ecf20Sopenharmony_ci struct perf_cpu_map *map, int max) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci int i; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci mask->nr = BITS_TO_LONGS(max); 11138c2ecf20Sopenharmony_ci mask->long_size = sizeof(long); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci for (i = 0; i < map->nr; i++) 11168c2ecf20Sopenharmony_ci set_bit(map->map[i], mask->mask); 11178c2ecf20Sopenharmony_ci} 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_cistatic size_t cpus_size(struct perf_cpu_map *map) 11208c2ecf20Sopenharmony_ci{ 11218c2ecf20Sopenharmony_ci return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16); 11228c2ecf20Sopenharmony_ci} 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_cistatic size_t mask_size(struct perf_cpu_map *map, int *max) 11258c2ecf20Sopenharmony_ci{ 11268c2ecf20Sopenharmony_ci int i; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci *max = 0; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci for (i = 0; i < map->nr; i++) { 11318c2ecf20Sopenharmony_ci /* bit possition of the cpu is + 1 */ 11328c2ecf20Sopenharmony_ci int bit = map->map[i] + 1; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci if (bit > *max) 11358c2ecf20Sopenharmony_ci *max = bit; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci return sizeof(struct perf_record_record_cpu_map) + BITS_TO_LONGS(*max) * sizeof(long); 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_civoid *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci size_t size_cpus, size_mask; 11448c2ecf20Sopenharmony_ci bool is_dummy = perf_cpu_map__empty(map); 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci /* 11478c2ecf20Sopenharmony_ci * Both array and mask data have variable size based 11488c2ecf20Sopenharmony_ci * on the number of cpus and their actual values. 11498c2ecf20Sopenharmony_ci * The size of the 'struct perf_record_cpu_map_data' is: 11508c2ecf20Sopenharmony_ci * 11518c2ecf20Sopenharmony_ci * array = size of 'struct cpu_map_entries' + 11528c2ecf20Sopenharmony_ci * number of cpus * sizeof(u64) 11538c2ecf20Sopenharmony_ci * 11548c2ecf20Sopenharmony_ci * mask = size of 'struct perf_record_record_cpu_map' + 11558c2ecf20Sopenharmony_ci * maximum cpu bit converted to size of longs 11568c2ecf20Sopenharmony_ci * 11578c2ecf20Sopenharmony_ci * and finaly + the size of 'struct perf_record_cpu_map_data'. 11588c2ecf20Sopenharmony_ci */ 11598c2ecf20Sopenharmony_ci size_cpus = cpus_size(map); 11608c2ecf20Sopenharmony_ci size_mask = mask_size(map, max); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (is_dummy || (size_cpus < size_mask)) { 11638c2ecf20Sopenharmony_ci *size += size_cpus; 11648c2ecf20Sopenharmony_ci *type = PERF_CPU_MAP__CPUS; 11658c2ecf20Sopenharmony_ci } else { 11668c2ecf20Sopenharmony_ci *size += size_mask; 11678c2ecf20Sopenharmony_ci *type = PERF_CPU_MAP__MASK; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci *size += sizeof(struct perf_record_cpu_map_data); 11718c2ecf20Sopenharmony_ci *size = PERF_ALIGN(*size, sizeof(u64)); 11728c2ecf20Sopenharmony_ci return zalloc(*size); 11738c2ecf20Sopenharmony_ci} 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_civoid cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map, 11768c2ecf20Sopenharmony_ci u16 type, int max) 11778c2ecf20Sopenharmony_ci{ 11788c2ecf20Sopenharmony_ci data->type = type; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci switch (type) { 11818c2ecf20Sopenharmony_ci case PERF_CPU_MAP__CPUS: 11828c2ecf20Sopenharmony_ci synthesize_cpus((struct cpu_map_entries *) data->data, map); 11838c2ecf20Sopenharmony_ci break; 11848c2ecf20Sopenharmony_ci case PERF_CPU_MAP__MASK: 11858c2ecf20Sopenharmony_ci synthesize_mask((struct perf_record_record_cpu_map *)data->data, map, max); 11868c2ecf20Sopenharmony_ci default: 11878c2ecf20Sopenharmony_ci break; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci} 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_cistatic struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map) 11928c2ecf20Sopenharmony_ci{ 11938c2ecf20Sopenharmony_ci size_t size = sizeof(struct perf_record_cpu_map); 11948c2ecf20Sopenharmony_ci struct perf_record_cpu_map *event; 11958c2ecf20Sopenharmony_ci int max; 11968c2ecf20Sopenharmony_ci u16 type; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci event = cpu_map_data__alloc(map, &size, &type, &max); 11998c2ecf20Sopenharmony_ci if (!event) 12008c2ecf20Sopenharmony_ci return NULL; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci event->header.type = PERF_RECORD_CPU_MAP; 12038c2ecf20Sopenharmony_ci event->header.size = size; 12048c2ecf20Sopenharmony_ci event->data.type = type; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci cpu_map_data__synthesize(&event->data, map, type, max); 12078c2ecf20Sopenharmony_ci return event; 12088c2ecf20Sopenharmony_ci} 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ciint perf_event__synthesize_cpu_map(struct perf_tool *tool, 12118c2ecf20Sopenharmony_ci struct perf_cpu_map *map, 12128c2ecf20Sopenharmony_ci perf_event__handler_t process, 12138c2ecf20Sopenharmony_ci struct machine *machine) 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci struct perf_record_cpu_map *event; 12168c2ecf20Sopenharmony_ci int err; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci event = cpu_map_event__new(map); 12198c2ecf20Sopenharmony_ci if (!event) 12208c2ecf20Sopenharmony_ci return -ENOMEM; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci err = process(tool, (union perf_event *) event, NULL, machine); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci free(event); 12258c2ecf20Sopenharmony_ci return err; 12268c2ecf20Sopenharmony_ci} 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ciint perf_event__synthesize_stat_config(struct perf_tool *tool, 12298c2ecf20Sopenharmony_ci struct perf_stat_config *config, 12308c2ecf20Sopenharmony_ci perf_event__handler_t process, 12318c2ecf20Sopenharmony_ci struct machine *machine) 12328c2ecf20Sopenharmony_ci{ 12338c2ecf20Sopenharmony_ci struct perf_record_stat_config *event; 12348c2ecf20Sopenharmony_ci int size, i = 0, err; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci size = sizeof(*event); 12378c2ecf20Sopenharmony_ci size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0])); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci event = zalloc(size); 12408c2ecf20Sopenharmony_ci if (!event) 12418c2ecf20Sopenharmony_ci return -ENOMEM; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci event->header.type = PERF_RECORD_STAT_CONFIG; 12448c2ecf20Sopenharmony_ci event->header.size = size; 12458c2ecf20Sopenharmony_ci event->nr = PERF_STAT_CONFIG_TERM__MAX; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci#define ADD(__term, __val) \ 12488c2ecf20Sopenharmony_ci event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term; \ 12498c2ecf20Sopenharmony_ci event->data[i].val = __val; \ 12508c2ecf20Sopenharmony_ci i++; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci ADD(AGGR_MODE, config->aggr_mode) 12538c2ecf20Sopenharmony_ci ADD(INTERVAL, config->interval) 12548c2ecf20Sopenharmony_ci ADD(SCALE, config->scale) 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX, 12578c2ecf20Sopenharmony_ci "stat config terms unbalanced\n"); 12588c2ecf20Sopenharmony_ci#undef ADD 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci err = process(tool, (union perf_event *) event, NULL, machine); 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci free(event); 12638c2ecf20Sopenharmony_ci return err; 12648c2ecf20Sopenharmony_ci} 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ciint perf_event__synthesize_stat(struct perf_tool *tool, 12678c2ecf20Sopenharmony_ci u32 cpu, u32 thread, u64 id, 12688c2ecf20Sopenharmony_ci struct perf_counts_values *count, 12698c2ecf20Sopenharmony_ci perf_event__handler_t process, 12708c2ecf20Sopenharmony_ci struct machine *machine) 12718c2ecf20Sopenharmony_ci{ 12728c2ecf20Sopenharmony_ci struct perf_record_stat event; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci event.header.type = PERF_RECORD_STAT; 12758c2ecf20Sopenharmony_ci event.header.size = sizeof(event); 12768c2ecf20Sopenharmony_ci event.header.misc = 0; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci event.id = id; 12798c2ecf20Sopenharmony_ci event.cpu = cpu; 12808c2ecf20Sopenharmony_ci event.thread = thread; 12818c2ecf20Sopenharmony_ci event.val = count->val; 12828c2ecf20Sopenharmony_ci event.ena = count->ena; 12838c2ecf20Sopenharmony_ci event.run = count->run; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci return process(tool, (union perf_event *) &event, NULL, machine); 12868c2ecf20Sopenharmony_ci} 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ciint perf_event__synthesize_stat_round(struct perf_tool *tool, 12898c2ecf20Sopenharmony_ci u64 evtime, u64 type, 12908c2ecf20Sopenharmony_ci perf_event__handler_t process, 12918c2ecf20Sopenharmony_ci struct machine *machine) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci struct perf_record_stat_round event; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci event.header.type = PERF_RECORD_STAT_ROUND; 12968c2ecf20Sopenharmony_ci event.header.size = sizeof(event); 12978c2ecf20Sopenharmony_ci event.header.misc = 0; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci event.time = evtime; 13008c2ecf20Sopenharmony_ci event.type = type; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci return process(tool, (union perf_event *) &event, NULL, machine); 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_cisize_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format) 13068c2ecf20Sopenharmony_ci{ 13078c2ecf20Sopenharmony_ci size_t sz, result = sizeof(struct perf_record_sample); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_IDENTIFIER) 13108c2ecf20Sopenharmony_ci result += sizeof(u64); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_IP) 13138c2ecf20Sopenharmony_ci result += sizeof(u64); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_TID) 13168c2ecf20Sopenharmony_ci result += sizeof(u64); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_TIME) 13198c2ecf20Sopenharmony_ci result += sizeof(u64); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_ADDR) 13228c2ecf20Sopenharmony_ci result += sizeof(u64); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_ID) 13258c2ecf20Sopenharmony_ci result += sizeof(u64); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_STREAM_ID) 13288c2ecf20Sopenharmony_ci result += sizeof(u64); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_CPU) 13318c2ecf20Sopenharmony_ci result += sizeof(u64); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_PERIOD) 13348c2ecf20Sopenharmony_ci result += sizeof(u64); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_READ) { 13378c2ecf20Sopenharmony_ci result += sizeof(u64); 13388c2ecf20Sopenharmony_ci if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 13398c2ecf20Sopenharmony_ci result += sizeof(u64); 13408c2ecf20Sopenharmony_ci if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 13418c2ecf20Sopenharmony_ci result += sizeof(u64); 13428c2ecf20Sopenharmony_ci /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 13438c2ecf20Sopenharmony_ci if (read_format & PERF_FORMAT_GROUP) { 13448c2ecf20Sopenharmony_ci sz = sample->read.group.nr * 13458c2ecf20Sopenharmony_ci sizeof(struct sample_read_value); 13468c2ecf20Sopenharmony_ci result += sz; 13478c2ecf20Sopenharmony_ci } else { 13488c2ecf20Sopenharmony_ci result += sizeof(u64); 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_CALLCHAIN) { 13538c2ecf20Sopenharmony_ci sz = (sample->callchain->nr + 1) * sizeof(u64); 13548c2ecf20Sopenharmony_ci result += sz; 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_RAW) { 13588c2ecf20Sopenharmony_ci result += sizeof(u32); 13598c2ecf20Sopenharmony_ci result += sample->raw_size; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_BRANCH_STACK) { 13638c2ecf20Sopenharmony_ci sz = sample->branch_stack->nr * sizeof(struct branch_entry); 13648c2ecf20Sopenharmony_ci /* nr, hw_idx */ 13658c2ecf20Sopenharmony_ci sz += 2 * sizeof(u64); 13668c2ecf20Sopenharmony_ci result += sz; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_REGS_USER) { 13708c2ecf20Sopenharmony_ci if (sample->user_regs.abi) { 13718c2ecf20Sopenharmony_ci result += sizeof(u64); 13728c2ecf20Sopenharmony_ci sz = hweight64(sample->user_regs.mask) * sizeof(u64); 13738c2ecf20Sopenharmony_ci result += sz; 13748c2ecf20Sopenharmony_ci } else { 13758c2ecf20Sopenharmony_ci result += sizeof(u64); 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_STACK_USER) { 13808c2ecf20Sopenharmony_ci sz = sample->user_stack.size; 13818c2ecf20Sopenharmony_ci result += sizeof(u64); 13828c2ecf20Sopenharmony_ci if (sz) { 13838c2ecf20Sopenharmony_ci result += sz; 13848c2ecf20Sopenharmony_ci result += sizeof(u64); 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_WEIGHT) 13898c2ecf20Sopenharmony_ci result += sizeof(u64); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_DATA_SRC) 13928c2ecf20Sopenharmony_ci result += sizeof(u64); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_TRANSACTION) 13958c2ecf20Sopenharmony_ci result += sizeof(u64); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_REGS_INTR) { 13988c2ecf20Sopenharmony_ci if (sample->intr_regs.abi) { 13998c2ecf20Sopenharmony_ci result += sizeof(u64); 14008c2ecf20Sopenharmony_ci sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 14018c2ecf20Sopenharmony_ci result += sz; 14028c2ecf20Sopenharmony_ci } else { 14038c2ecf20Sopenharmony_ci result += sizeof(u64); 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_PHYS_ADDR) 14088c2ecf20Sopenharmony_ci result += sizeof(u64); 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_CGROUP) 14118c2ecf20Sopenharmony_ci result += sizeof(u64); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_AUX) { 14148c2ecf20Sopenharmony_ci result += sizeof(u64); 14158c2ecf20Sopenharmony_ci result += sample->aux_sample.size; 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci return result; 14198c2ecf20Sopenharmony_ci} 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ciint perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format, 14228c2ecf20Sopenharmony_ci const struct perf_sample *sample) 14238c2ecf20Sopenharmony_ci{ 14248c2ecf20Sopenharmony_ci __u64 *array; 14258c2ecf20Sopenharmony_ci size_t sz; 14268c2ecf20Sopenharmony_ci /* 14278c2ecf20Sopenharmony_ci * used for cross-endian analysis. See git commit 65014ab3 14288c2ecf20Sopenharmony_ci * for why this goofiness is needed. 14298c2ecf20Sopenharmony_ci */ 14308c2ecf20Sopenharmony_ci union u64_swap u; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci array = event->sample.array; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_IDENTIFIER) { 14358c2ecf20Sopenharmony_ci *array = sample->id; 14368c2ecf20Sopenharmony_ci array++; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_IP) { 14408c2ecf20Sopenharmony_ci *array = sample->ip; 14418c2ecf20Sopenharmony_ci array++; 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_TID) { 14458c2ecf20Sopenharmony_ci u.val32[0] = sample->pid; 14468c2ecf20Sopenharmony_ci u.val32[1] = sample->tid; 14478c2ecf20Sopenharmony_ci *array = u.val64; 14488c2ecf20Sopenharmony_ci array++; 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_TIME) { 14528c2ecf20Sopenharmony_ci *array = sample->time; 14538c2ecf20Sopenharmony_ci array++; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_ADDR) { 14578c2ecf20Sopenharmony_ci *array = sample->addr; 14588c2ecf20Sopenharmony_ci array++; 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_ID) { 14628c2ecf20Sopenharmony_ci *array = sample->id; 14638c2ecf20Sopenharmony_ci array++; 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_STREAM_ID) { 14678c2ecf20Sopenharmony_ci *array = sample->stream_id; 14688c2ecf20Sopenharmony_ci array++; 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_CPU) { 14728c2ecf20Sopenharmony_ci u.val32[0] = sample->cpu; 14738c2ecf20Sopenharmony_ci u.val32[1] = 0; 14748c2ecf20Sopenharmony_ci *array = u.val64; 14758c2ecf20Sopenharmony_ci array++; 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_PERIOD) { 14798c2ecf20Sopenharmony_ci *array = sample->period; 14808c2ecf20Sopenharmony_ci array++; 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_READ) { 14848c2ecf20Sopenharmony_ci if (read_format & PERF_FORMAT_GROUP) 14858c2ecf20Sopenharmony_ci *array = sample->read.group.nr; 14868c2ecf20Sopenharmony_ci else 14878c2ecf20Sopenharmony_ci *array = sample->read.one.value; 14888c2ecf20Sopenharmony_ci array++; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { 14918c2ecf20Sopenharmony_ci *array = sample->read.time_enabled; 14928c2ecf20Sopenharmony_ci array++; 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { 14968c2ecf20Sopenharmony_ci *array = sample->read.time_running; 14978c2ecf20Sopenharmony_ci array++; 14988c2ecf20Sopenharmony_ci } 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 15018c2ecf20Sopenharmony_ci if (read_format & PERF_FORMAT_GROUP) { 15028c2ecf20Sopenharmony_ci sz = sample->read.group.nr * 15038c2ecf20Sopenharmony_ci sizeof(struct sample_read_value); 15048c2ecf20Sopenharmony_ci memcpy(array, sample->read.group.values, sz); 15058c2ecf20Sopenharmony_ci array = (void *)array + sz; 15068c2ecf20Sopenharmony_ci } else { 15078c2ecf20Sopenharmony_ci *array = sample->read.one.id; 15088c2ecf20Sopenharmony_ci array++; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_CALLCHAIN) { 15138c2ecf20Sopenharmony_ci sz = (sample->callchain->nr + 1) * sizeof(u64); 15148c2ecf20Sopenharmony_ci memcpy(array, sample->callchain, sz); 15158c2ecf20Sopenharmony_ci array = (void *)array + sz; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_RAW) { 15198c2ecf20Sopenharmony_ci u.val32[0] = sample->raw_size; 15208c2ecf20Sopenharmony_ci *array = u.val64; 15218c2ecf20Sopenharmony_ci array = (void *)array + sizeof(u32); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci memcpy(array, sample->raw_data, sample->raw_size); 15248c2ecf20Sopenharmony_ci array = (void *)array + sample->raw_size; 15258c2ecf20Sopenharmony_ci } 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_BRANCH_STACK) { 15288c2ecf20Sopenharmony_ci sz = sample->branch_stack->nr * sizeof(struct branch_entry); 15298c2ecf20Sopenharmony_ci /* nr, hw_idx */ 15308c2ecf20Sopenharmony_ci sz += 2 * sizeof(u64); 15318c2ecf20Sopenharmony_ci memcpy(array, sample->branch_stack, sz); 15328c2ecf20Sopenharmony_ci array = (void *)array + sz; 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_REGS_USER) { 15368c2ecf20Sopenharmony_ci if (sample->user_regs.abi) { 15378c2ecf20Sopenharmony_ci *array++ = sample->user_regs.abi; 15388c2ecf20Sopenharmony_ci sz = hweight64(sample->user_regs.mask) * sizeof(u64); 15398c2ecf20Sopenharmony_ci memcpy(array, sample->user_regs.regs, sz); 15408c2ecf20Sopenharmony_ci array = (void *)array + sz; 15418c2ecf20Sopenharmony_ci } else { 15428c2ecf20Sopenharmony_ci *array++ = 0; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_STACK_USER) { 15478c2ecf20Sopenharmony_ci sz = sample->user_stack.size; 15488c2ecf20Sopenharmony_ci *array++ = sz; 15498c2ecf20Sopenharmony_ci if (sz) { 15508c2ecf20Sopenharmony_ci memcpy(array, sample->user_stack.data, sz); 15518c2ecf20Sopenharmony_ci array = (void *)array + sz; 15528c2ecf20Sopenharmony_ci *array++ = sz; 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_WEIGHT) { 15578c2ecf20Sopenharmony_ci *array = sample->weight; 15588c2ecf20Sopenharmony_ci array++; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_DATA_SRC) { 15628c2ecf20Sopenharmony_ci *array = sample->data_src; 15638c2ecf20Sopenharmony_ci array++; 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_TRANSACTION) { 15678c2ecf20Sopenharmony_ci *array = sample->transaction; 15688c2ecf20Sopenharmony_ci array++; 15698c2ecf20Sopenharmony_ci } 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_REGS_INTR) { 15728c2ecf20Sopenharmony_ci if (sample->intr_regs.abi) { 15738c2ecf20Sopenharmony_ci *array++ = sample->intr_regs.abi; 15748c2ecf20Sopenharmony_ci sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 15758c2ecf20Sopenharmony_ci memcpy(array, sample->intr_regs.regs, sz); 15768c2ecf20Sopenharmony_ci array = (void *)array + sz; 15778c2ecf20Sopenharmony_ci } else { 15788c2ecf20Sopenharmony_ci *array++ = 0; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_PHYS_ADDR) { 15838c2ecf20Sopenharmony_ci *array = sample->phys_addr; 15848c2ecf20Sopenharmony_ci array++; 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_CGROUP) { 15888c2ecf20Sopenharmony_ci *array = sample->cgroup; 15898c2ecf20Sopenharmony_ci array++; 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci if (type & PERF_SAMPLE_AUX) { 15938c2ecf20Sopenharmony_ci sz = sample->aux_sample.size; 15948c2ecf20Sopenharmony_ci *array++ = sz; 15958c2ecf20Sopenharmony_ci memcpy(array, sample->aux_sample.data, sz); 15968c2ecf20Sopenharmony_ci array = (void *)array + sz; 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci return 0; 16008c2ecf20Sopenharmony_ci} 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ciint perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, 16038c2ecf20Sopenharmony_ci struct evlist *evlist, struct machine *machine) 16048c2ecf20Sopenharmony_ci{ 16058c2ecf20Sopenharmony_ci union perf_event *ev; 16068c2ecf20Sopenharmony_ci struct evsel *evsel; 16078c2ecf20Sopenharmony_ci size_t nr = 0, i = 0, sz, max_nr, n; 16088c2ecf20Sopenharmony_ci int err; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci pr_debug2("Synthesizing id index\n"); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / 16138c2ecf20Sopenharmony_ci sizeof(struct id_index_entry); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, evsel) 16168c2ecf20Sopenharmony_ci nr += evsel->core.ids; 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci n = nr > max_nr ? max_nr : nr; 16198c2ecf20Sopenharmony_ci sz = sizeof(struct perf_record_id_index) + n * sizeof(struct id_index_entry); 16208c2ecf20Sopenharmony_ci ev = zalloc(sz); 16218c2ecf20Sopenharmony_ci if (!ev) 16228c2ecf20Sopenharmony_ci return -ENOMEM; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci ev->id_index.header.type = PERF_RECORD_ID_INDEX; 16258c2ecf20Sopenharmony_ci ev->id_index.header.size = sz; 16268c2ecf20Sopenharmony_ci ev->id_index.nr = n; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 16298c2ecf20Sopenharmony_ci u32 j; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci for (j = 0; j < evsel->core.ids; j++) { 16328c2ecf20Sopenharmony_ci struct id_index_entry *e; 16338c2ecf20Sopenharmony_ci struct perf_sample_id *sid; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci if (i >= n) { 16368c2ecf20Sopenharmony_ci err = process(tool, ev, NULL, machine); 16378c2ecf20Sopenharmony_ci if (err) 16388c2ecf20Sopenharmony_ci goto out_err; 16398c2ecf20Sopenharmony_ci nr -= n; 16408c2ecf20Sopenharmony_ci i = 0; 16418c2ecf20Sopenharmony_ci } 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci e = &ev->id_index.entries[i++]; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci e->id = evsel->core.id[j]; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci sid = perf_evlist__id2sid(evlist, e->id); 16488c2ecf20Sopenharmony_ci if (!sid) { 16498c2ecf20Sopenharmony_ci free(ev); 16508c2ecf20Sopenharmony_ci return -ENOENT; 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci e->idx = sid->idx; 16548c2ecf20Sopenharmony_ci e->cpu = sid->cpu; 16558c2ecf20Sopenharmony_ci e->tid = sid->tid; 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci sz = sizeof(struct perf_record_id_index) + nr * sizeof(struct id_index_entry); 16608c2ecf20Sopenharmony_ci ev->id_index.header.size = sz; 16618c2ecf20Sopenharmony_ci ev->id_index.nr = nr; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci err = process(tool, ev, NULL, machine); 16648c2ecf20Sopenharmony_ciout_err: 16658c2ecf20Sopenharmony_ci free(ev); 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci return err; 16688c2ecf20Sopenharmony_ci} 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ciint __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, 16718c2ecf20Sopenharmony_ci struct target *target, struct perf_thread_map *threads, 16728c2ecf20Sopenharmony_ci perf_event__handler_t process, bool data_mmap, 16738c2ecf20Sopenharmony_ci unsigned int nr_threads_synthesize) 16748c2ecf20Sopenharmony_ci{ 16758c2ecf20Sopenharmony_ci if (target__has_task(target)) 16768c2ecf20Sopenharmony_ci return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap); 16778c2ecf20Sopenharmony_ci else if (target__has_cpu(target)) 16788c2ecf20Sopenharmony_ci return perf_event__synthesize_threads(tool, process, 16798c2ecf20Sopenharmony_ci machine, data_mmap, 16808c2ecf20Sopenharmony_ci nr_threads_synthesize); 16818c2ecf20Sopenharmony_ci /* command specified */ 16828c2ecf20Sopenharmony_ci return 0; 16838c2ecf20Sopenharmony_ci} 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ciint machine__synthesize_threads(struct machine *machine, struct target *target, 16868c2ecf20Sopenharmony_ci struct perf_thread_map *threads, bool data_mmap, 16878c2ecf20Sopenharmony_ci unsigned int nr_threads_synthesize) 16888c2ecf20Sopenharmony_ci{ 16898c2ecf20Sopenharmony_ci return __machine__synthesize_threads(machine, NULL, target, threads, 16908c2ecf20Sopenharmony_ci perf_event__process, data_mmap, 16918c2ecf20Sopenharmony_ci nr_threads_synthesize); 16928c2ecf20Sopenharmony_ci} 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_cistatic struct perf_record_event_update *event_update_event__new(size_t size, u64 type, u64 id) 16958c2ecf20Sopenharmony_ci{ 16968c2ecf20Sopenharmony_ci struct perf_record_event_update *ev; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci size += sizeof(*ev); 16998c2ecf20Sopenharmony_ci size = PERF_ALIGN(size, sizeof(u64)); 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci ev = zalloc(size); 17028c2ecf20Sopenharmony_ci if (ev) { 17038c2ecf20Sopenharmony_ci ev->header.type = PERF_RECORD_EVENT_UPDATE; 17048c2ecf20Sopenharmony_ci ev->header.size = (u16)size; 17058c2ecf20Sopenharmony_ci ev->type = type; 17068c2ecf20Sopenharmony_ci ev->id = id; 17078c2ecf20Sopenharmony_ci } 17088c2ecf20Sopenharmony_ci return ev; 17098c2ecf20Sopenharmony_ci} 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ciint perf_event__synthesize_event_update_unit(struct perf_tool *tool, struct evsel *evsel, 17128c2ecf20Sopenharmony_ci perf_event__handler_t process) 17138c2ecf20Sopenharmony_ci{ 17148c2ecf20Sopenharmony_ci size_t size = strlen(evsel->unit); 17158c2ecf20Sopenharmony_ci struct perf_record_event_update *ev; 17168c2ecf20Sopenharmony_ci int err; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->core.id[0]); 17198c2ecf20Sopenharmony_ci if (ev == NULL) 17208c2ecf20Sopenharmony_ci return -ENOMEM; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci strlcpy(ev->data, evsel->unit, size + 1); 17238c2ecf20Sopenharmony_ci err = process(tool, (union perf_event *)ev, NULL, NULL); 17248c2ecf20Sopenharmony_ci free(ev); 17258c2ecf20Sopenharmony_ci return err; 17268c2ecf20Sopenharmony_ci} 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ciint perf_event__synthesize_event_update_scale(struct perf_tool *tool, struct evsel *evsel, 17298c2ecf20Sopenharmony_ci perf_event__handler_t process) 17308c2ecf20Sopenharmony_ci{ 17318c2ecf20Sopenharmony_ci struct perf_record_event_update *ev; 17328c2ecf20Sopenharmony_ci struct perf_record_event_update_scale *ev_data; 17338c2ecf20Sopenharmony_ci int err; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->core.id[0]); 17368c2ecf20Sopenharmony_ci if (ev == NULL) 17378c2ecf20Sopenharmony_ci return -ENOMEM; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci ev_data = (struct perf_record_event_update_scale *)ev->data; 17408c2ecf20Sopenharmony_ci ev_data->scale = evsel->scale; 17418c2ecf20Sopenharmony_ci err = process(tool, (union perf_event *)ev, NULL, NULL); 17428c2ecf20Sopenharmony_ci free(ev); 17438c2ecf20Sopenharmony_ci return err; 17448c2ecf20Sopenharmony_ci} 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ciint perf_event__synthesize_event_update_name(struct perf_tool *tool, struct evsel *evsel, 17478c2ecf20Sopenharmony_ci perf_event__handler_t process) 17488c2ecf20Sopenharmony_ci{ 17498c2ecf20Sopenharmony_ci struct perf_record_event_update *ev; 17508c2ecf20Sopenharmony_ci size_t len = strlen(evsel->name); 17518c2ecf20Sopenharmony_ci int err; 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->core.id[0]); 17548c2ecf20Sopenharmony_ci if (ev == NULL) 17558c2ecf20Sopenharmony_ci return -ENOMEM; 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci strlcpy(ev->data, evsel->name, len + 1); 17588c2ecf20Sopenharmony_ci err = process(tool, (union perf_event *)ev, NULL, NULL); 17598c2ecf20Sopenharmony_ci free(ev); 17608c2ecf20Sopenharmony_ci return err; 17618c2ecf20Sopenharmony_ci} 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ciint perf_event__synthesize_event_update_cpus(struct perf_tool *tool, struct evsel *evsel, 17648c2ecf20Sopenharmony_ci perf_event__handler_t process) 17658c2ecf20Sopenharmony_ci{ 17668c2ecf20Sopenharmony_ci size_t size = sizeof(struct perf_record_event_update); 17678c2ecf20Sopenharmony_ci struct perf_record_event_update *ev; 17688c2ecf20Sopenharmony_ci int max, err; 17698c2ecf20Sopenharmony_ci u16 type; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci if (!evsel->core.own_cpus) 17728c2ecf20Sopenharmony_ci return 0; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci ev = cpu_map_data__alloc(evsel->core.own_cpus, &size, &type, &max); 17758c2ecf20Sopenharmony_ci if (!ev) 17768c2ecf20Sopenharmony_ci return -ENOMEM; 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci ev->header.type = PERF_RECORD_EVENT_UPDATE; 17798c2ecf20Sopenharmony_ci ev->header.size = (u16)size; 17808c2ecf20Sopenharmony_ci ev->type = PERF_EVENT_UPDATE__CPUS; 17818c2ecf20Sopenharmony_ci ev->id = evsel->core.id[0]; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci cpu_map_data__synthesize((struct perf_record_cpu_map_data *)ev->data, 17848c2ecf20Sopenharmony_ci evsel->core.own_cpus, type, max); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci err = process(tool, (union perf_event *)ev, NULL, NULL); 17878c2ecf20Sopenharmony_ci free(ev); 17888c2ecf20Sopenharmony_ci return err; 17898c2ecf20Sopenharmony_ci} 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ciint perf_event__synthesize_attrs(struct perf_tool *tool, struct evlist *evlist, 17928c2ecf20Sopenharmony_ci perf_event__handler_t process) 17938c2ecf20Sopenharmony_ci{ 17948c2ecf20Sopenharmony_ci struct evsel *evsel; 17958c2ecf20Sopenharmony_ci int err = 0; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 17988c2ecf20Sopenharmony_ci err = perf_event__synthesize_attr(tool, &evsel->core.attr, evsel->core.ids, 17998c2ecf20Sopenharmony_ci evsel->core.id, process); 18008c2ecf20Sopenharmony_ci if (err) { 18018c2ecf20Sopenharmony_ci pr_debug("failed to create perf header attribute\n"); 18028c2ecf20Sopenharmony_ci return err; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci return err; 18078c2ecf20Sopenharmony_ci} 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_cistatic bool has_unit(struct evsel *evsel) 18108c2ecf20Sopenharmony_ci{ 18118c2ecf20Sopenharmony_ci return evsel->unit && *evsel->unit; 18128c2ecf20Sopenharmony_ci} 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_cistatic bool has_scale(struct evsel *evsel) 18158c2ecf20Sopenharmony_ci{ 18168c2ecf20Sopenharmony_ci return evsel->scale != 1; 18178c2ecf20Sopenharmony_ci} 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ciint perf_event__synthesize_extra_attr(struct perf_tool *tool, struct evlist *evsel_list, 18208c2ecf20Sopenharmony_ci perf_event__handler_t process, bool is_pipe) 18218c2ecf20Sopenharmony_ci{ 18228c2ecf20Sopenharmony_ci struct evsel *evsel; 18238c2ecf20Sopenharmony_ci int err; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci /* 18268c2ecf20Sopenharmony_ci * Synthesize other events stuff not carried within 18278c2ecf20Sopenharmony_ci * attr event - unit, scale, name 18288c2ecf20Sopenharmony_ci */ 18298c2ecf20Sopenharmony_ci evlist__for_each_entry(evsel_list, evsel) { 18308c2ecf20Sopenharmony_ci if (!evsel->supported) 18318c2ecf20Sopenharmony_ci continue; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci /* 18348c2ecf20Sopenharmony_ci * Synthesize unit and scale only if it's defined. 18358c2ecf20Sopenharmony_ci */ 18368c2ecf20Sopenharmony_ci if (has_unit(evsel)) { 18378c2ecf20Sopenharmony_ci err = perf_event__synthesize_event_update_unit(tool, evsel, process); 18388c2ecf20Sopenharmony_ci if (err < 0) { 18398c2ecf20Sopenharmony_ci pr_err("Couldn't synthesize evsel unit.\n"); 18408c2ecf20Sopenharmony_ci return err; 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci } 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci if (has_scale(evsel)) { 18458c2ecf20Sopenharmony_ci err = perf_event__synthesize_event_update_scale(tool, evsel, process); 18468c2ecf20Sopenharmony_ci if (err < 0) { 18478c2ecf20Sopenharmony_ci pr_err("Couldn't synthesize evsel evsel.\n"); 18488c2ecf20Sopenharmony_ci return err; 18498c2ecf20Sopenharmony_ci } 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci if (evsel->core.own_cpus) { 18538c2ecf20Sopenharmony_ci err = perf_event__synthesize_event_update_cpus(tool, evsel, process); 18548c2ecf20Sopenharmony_ci if (err < 0) { 18558c2ecf20Sopenharmony_ci pr_err("Couldn't synthesize evsel cpus.\n"); 18568c2ecf20Sopenharmony_ci return err; 18578c2ecf20Sopenharmony_ci } 18588c2ecf20Sopenharmony_ci } 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci /* 18618c2ecf20Sopenharmony_ci * Name is needed only for pipe output, 18628c2ecf20Sopenharmony_ci * perf.data carries event names. 18638c2ecf20Sopenharmony_ci */ 18648c2ecf20Sopenharmony_ci if (is_pipe) { 18658c2ecf20Sopenharmony_ci err = perf_event__synthesize_event_update_name(tool, evsel, process); 18668c2ecf20Sopenharmony_ci if (err < 0) { 18678c2ecf20Sopenharmony_ci pr_err("Couldn't synthesize evsel name.\n"); 18688c2ecf20Sopenharmony_ci return err; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci } 18718c2ecf20Sopenharmony_ci } 18728c2ecf20Sopenharmony_ci return 0; 18738c2ecf20Sopenharmony_ci} 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ciint perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, 18768c2ecf20Sopenharmony_ci u32 ids, u64 *id, perf_event__handler_t process) 18778c2ecf20Sopenharmony_ci{ 18788c2ecf20Sopenharmony_ci union perf_event *ev; 18798c2ecf20Sopenharmony_ci size_t size; 18808c2ecf20Sopenharmony_ci int err; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci size = sizeof(struct perf_event_attr); 18838c2ecf20Sopenharmony_ci size = PERF_ALIGN(size, sizeof(u64)); 18848c2ecf20Sopenharmony_ci size += sizeof(struct perf_event_header); 18858c2ecf20Sopenharmony_ci size += ids * sizeof(u64); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci ev = zalloc(size); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci if (ev == NULL) 18908c2ecf20Sopenharmony_ci return -ENOMEM; 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci ev->attr.attr = *attr; 18938c2ecf20Sopenharmony_ci memcpy(ev->attr.id, id, ids * sizeof(u64)); 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci ev->attr.header.type = PERF_RECORD_HEADER_ATTR; 18968c2ecf20Sopenharmony_ci ev->attr.header.size = (u16)size; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci if (ev->attr.header.size == size) 18998c2ecf20Sopenharmony_ci err = process(tool, ev, NULL, NULL); 19008c2ecf20Sopenharmony_ci else 19018c2ecf20Sopenharmony_ci err = -E2BIG; 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci free(ev); 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci return err; 19068c2ecf20Sopenharmony_ci} 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ciint perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct evlist *evlist, 19098c2ecf20Sopenharmony_ci perf_event__handler_t process) 19108c2ecf20Sopenharmony_ci{ 19118c2ecf20Sopenharmony_ci union perf_event ev; 19128c2ecf20Sopenharmony_ci struct tracing_data *tdata; 19138c2ecf20Sopenharmony_ci ssize_t size = 0, aligned_size = 0, padding; 19148c2ecf20Sopenharmony_ci struct feat_fd ff; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci /* 19178c2ecf20Sopenharmony_ci * We are going to store the size of the data followed 19188c2ecf20Sopenharmony_ci * by the data contents. Since the fd descriptor is a pipe, 19198c2ecf20Sopenharmony_ci * we cannot seek back to store the size of the data once 19208c2ecf20Sopenharmony_ci * we know it. Instead we: 19218c2ecf20Sopenharmony_ci * 19228c2ecf20Sopenharmony_ci * - write the tracing data to the temp file 19238c2ecf20Sopenharmony_ci * - get/write the data size to pipe 19248c2ecf20Sopenharmony_ci * - write the tracing data from the temp file 19258c2ecf20Sopenharmony_ci * to the pipe 19268c2ecf20Sopenharmony_ci */ 19278c2ecf20Sopenharmony_ci tdata = tracing_data_get(&evlist->core.entries, fd, true); 19288c2ecf20Sopenharmony_ci if (!tdata) 19298c2ecf20Sopenharmony_ci return -1; 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci memset(&ev, 0, sizeof(ev)); 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 19348c2ecf20Sopenharmony_ci size = tdata->size; 19358c2ecf20Sopenharmony_ci aligned_size = PERF_ALIGN(size, sizeof(u64)); 19368c2ecf20Sopenharmony_ci padding = aligned_size - size; 19378c2ecf20Sopenharmony_ci ev.tracing_data.header.size = sizeof(ev.tracing_data); 19388c2ecf20Sopenharmony_ci ev.tracing_data.size = aligned_size; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci process(tool, &ev, NULL, NULL); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci /* 19438c2ecf20Sopenharmony_ci * The put function will copy all the tracing data 19448c2ecf20Sopenharmony_ci * stored in temp file to the pipe. 19458c2ecf20Sopenharmony_ci */ 19468c2ecf20Sopenharmony_ci tracing_data_put(tdata); 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci ff = (struct feat_fd){ .fd = fd }; 19498c2ecf20Sopenharmony_ci if (write_padded(&ff, NULL, 0, padding)) 19508c2ecf20Sopenharmony_ci return -1; 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci return aligned_size; 19538c2ecf20Sopenharmony_ci} 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ciint perf_event__synthesize_build_id(struct perf_tool *tool, struct dso *pos, u16 misc, 19568c2ecf20Sopenharmony_ci perf_event__handler_t process, struct machine *machine) 19578c2ecf20Sopenharmony_ci{ 19588c2ecf20Sopenharmony_ci union perf_event ev; 19598c2ecf20Sopenharmony_ci size_t len; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci if (!pos->hit) 19628c2ecf20Sopenharmony_ci return 0; 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci memset(&ev, 0, sizeof(ev)); 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci len = pos->long_name_len + 1; 19678c2ecf20Sopenharmony_ci len = PERF_ALIGN(len, NAME_ALIGN); 19688c2ecf20Sopenharmony_ci memcpy(&ev.build_id.build_id, pos->bid.data, sizeof(pos->bid.data)); 19698c2ecf20Sopenharmony_ci ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; 19708c2ecf20Sopenharmony_ci ev.build_id.header.misc = misc; 19718c2ecf20Sopenharmony_ci ev.build_id.pid = machine->pid; 19728c2ecf20Sopenharmony_ci ev.build_id.header.size = sizeof(ev.build_id) + len; 19738c2ecf20Sopenharmony_ci memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci return process(tool, &ev, NULL, machine); 19768c2ecf20Sopenharmony_ci} 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ciint perf_event__synthesize_stat_events(struct perf_stat_config *config, struct perf_tool *tool, 19798c2ecf20Sopenharmony_ci struct evlist *evlist, perf_event__handler_t process, bool attrs) 19808c2ecf20Sopenharmony_ci{ 19818c2ecf20Sopenharmony_ci int err; 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci if (attrs) { 19848c2ecf20Sopenharmony_ci err = perf_event__synthesize_attrs(tool, evlist, process); 19858c2ecf20Sopenharmony_ci if (err < 0) { 19868c2ecf20Sopenharmony_ci pr_err("Couldn't synthesize attrs.\n"); 19878c2ecf20Sopenharmony_ci return err; 19888c2ecf20Sopenharmony_ci } 19898c2ecf20Sopenharmony_ci } 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci err = perf_event__synthesize_extra_attr(tool, evlist, process, attrs); 19928c2ecf20Sopenharmony_ci err = perf_event__synthesize_thread_map2(tool, evlist->core.threads, process, NULL); 19938c2ecf20Sopenharmony_ci if (err < 0) { 19948c2ecf20Sopenharmony_ci pr_err("Couldn't synthesize thread map.\n"); 19958c2ecf20Sopenharmony_ci return err; 19968c2ecf20Sopenharmony_ci } 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci err = perf_event__synthesize_cpu_map(tool, evlist->core.cpus, process, NULL); 19998c2ecf20Sopenharmony_ci if (err < 0) { 20008c2ecf20Sopenharmony_ci pr_err("Couldn't synthesize thread map.\n"); 20018c2ecf20Sopenharmony_ci return err; 20028c2ecf20Sopenharmony_ci } 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci err = perf_event__synthesize_stat_config(tool, config, process, NULL); 20058c2ecf20Sopenharmony_ci if (err < 0) { 20068c2ecf20Sopenharmony_ci pr_err("Couldn't synthesize config.\n"); 20078c2ecf20Sopenharmony_ci return err; 20088c2ecf20Sopenharmony_ci } 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci return 0; 20118c2ecf20Sopenharmony_ci} 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ciextern const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE]; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ciint perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, 20168c2ecf20Sopenharmony_ci struct evlist *evlist, perf_event__handler_t process) 20178c2ecf20Sopenharmony_ci{ 20188c2ecf20Sopenharmony_ci struct perf_header *header = &session->header; 20198c2ecf20Sopenharmony_ci struct perf_record_header_feature *fe; 20208c2ecf20Sopenharmony_ci struct feat_fd ff; 20218c2ecf20Sopenharmony_ci size_t sz, sz_hdr; 20228c2ecf20Sopenharmony_ci int feat, ret; 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci sz_hdr = sizeof(fe->header); 20258c2ecf20Sopenharmony_ci sz = sizeof(union perf_event); 20268c2ecf20Sopenharmony_ci /* get a nice alignment */ 20278c2ecf20Sopenharmony_ci sz = PERF_ALIGN(sz, page_size); 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci memset(&ff, 0, sizeof(ff)); 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci ff.buf = malloc(sz); 20328c2ecf20Sopenharmony_ci if (!ff.buf) 20338c2ecf20Sopenharmony_ci return -ENOMEM; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci ff.size = sz - sz_hdr; 20368c2ecf20Sopenharmony_ci ff.ph = &session->header; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { 20398c2ecf20Sopenharmony_ci if (!feat_ops[feat].synthesize) { 20408c2ecf20Sopenharmony_ci pr_debug("No record header feature for header :%d\n", feat); 20418c2ecf20Sopenharmony_ci continue; 20428c2ecf20Sopenharmony_ci } 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci ff.offset = sizeof(*fe); 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci ret = feat_ops[feat].write(&ff, evlist); 20478c2ecf20Sopenharmony_ci if (ret || ff.offset <= (ssize_t)sizeof(*fe)) { 20488c2ecf20Sopenharmony_ci pr_debug("Error writing feature\n"); 20498c2ecf20Sopenharmony_ci continue; 20508c2ecf20Sopenharmony_ci } 20518c2ecf20Sopenharmony_ci /* ff.buf may have changed due to realloc in do_write() */ 20528c2ecf20Sopenharmony_ci fe = ff.buf; 20538c2ecf20Sopenharmony_ci memset(fe, 0, sizeof(*fe)); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci fe->feat_id = feat; 20568c2ecf20Sopenharmony_ci fe->header.type = PERF_RECORD_HEADER_FEATURE; 20578c2ecf20Sopenharmony_ci fe->header.size = ff.offset; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci ret = process(tool, ff.buf, NULL, NULL); 20608c2ecf20Sopenharmony_ci if (ret) { 20618c2ecf20Sopenharmony_ci free(ff.buf); 20628c2ecf20Sopenharmony_ci return ret; 20638c2ecf20Sopenharmony_ci } 20648c2ecf20Sopenharmony_ci } 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci /* Send HEADER_LAST_FEATURE mark. */ 20678c2ecf20Sopenharmony_ci fe = ff.buf; 20688c2ecf20Sopenharmony_ci fe->feat_id = HEADER_LAST_FEATURE; 20698c2ecf20Sopenharmony_ci fe->header.type = PERF_RECORD_HEADER_FEATURE; 20708c2ecf20Sopenharmony_ci fe->header.size = sizeof(*fe); 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci ret = process(tool, ff.buf, NULL, NULL); 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci free(ff.buf); 20758c2ecf20Sopenharmony_ci return ret; 20768c2ecf20Sopenharmony_ci} 2077