1055c67edSArnaldo Carvalho de Melo // SPDX-License-Identifier: GPL-2.0-only 2055c67edSArnaldo Carvalho de Melo 3c3a057dcSNamhyung Kim #include "util/cgroup.h" 4c3a057dcSNamhyung Kim #include "util/data.h" 5055c67edSArnaldo Carvalho de Melo #include "util/debug.h" 6055c67edSArnaldo Carvalho de Melo #include "util/dso.h" 7055c67edSArnaldo Carvalho de Melo #include "util/event.h" 8055c67edSArnaldo Carvalho de Melo #include "util/evlist.h" 9055c67edSArnaldo Carvalho de Melo #include "util/machine.h" 10055c67edSArnaldo Carvalho de Melo #include "util/map.h" 11055c67edSArnaldo Carvalho de Melo #include "util/map_symbol.h" 12055c67edSArnaldo Carvalho de Melo #include "util/branch.h" 13055c67edSArnaldo Carvalho de Melo #include "util/memswap.h" 14055c67edSArnaldo Carvalho de Melo #include "util/namespaces.h" 15055c67edSArnaldo Carvalho de Melo #include "util/session.h" 16055c67edSArnaldo Carvalho de Melo #include "util/stat.h" 17055c67edSArnaldo Carvalho de Melo #include "util/symbol.h" 18055c67edSArnaldo Carvalho de Melo #include "util/synthetic-events.h" 19055c67edSArnaldo Carvalho de Melo #include "util/target.h" 20055c67edSArnaldo Carvalho de Melo #include "util/time-utils.h" 21055c67edSArnaldo Carvalho de Melo #include <linux/bitops.h> 22055c67edSArnaldo Carvalho de Melo #include <linux/kernel.h> 23055c67edSArnaldo Carvalho de Melo #include <linux/string.h> 24055c67edSArnaldo Carvalho de Melo #include <linux/zalloc.h> 25055c67edSArnaldo Carvalho de Melo #include <linux/perf_event.h> 26055c67edSArnaldo Carvalho de Melo #include <asm/bug.h> 27055c67edSArnaldo Carvalho de Melo #include <perf/evsel.h> 28055c67edSArnaldo Carvalho de Melo #include <perf/cpumap.h> 2920f2be1dSJiri Olsa #include <internal/lib.h> // page_size 30055c67edSArnaldo Carvalho de Melo #include <internal/threadmap.h> 31055c67edSArnaldo Carvalho de Melo #include <perf/threadmap.h> 32055c67edSArnaldo Carvalho de Melo #include <symbol/kallsyms.h> 33055c67edSArnaldo Carvalho de Melo #include <dirent.h> 34055c67edSArnaldo Carvalho de Melo #include <errno.h> 35055c67edSArnaldo Carvalho de Melo #include <inttypes.h> 36055c67edSArnaldo Carvalho de Melo #include <stdio.h> 37055c67edSArnaldo Carvalho de Melo #include <string.h> 38055c67edSArnaldo Carvalho de Melo #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ 39055c67edSArnaldo Carvalho de Melo #include <api/fs/fs.h> 402069425eSIan Rogers #include <api/io.h> 41055c67edSArnaldo Carvalho de Melo #include <sys/types.h> 42055c67edSArnaldo Carvalho de Melo #include <sys/stat.h> 43055c67edSArnaldo Carvalho de Melo #include <fcntl.h> 44055c67edSArnaldo Carvalho de Melo #include <unistd.h> 45055c67edSArnaldo Carvalho de Melo 46055c67edSArnaldo Carvalho de Melo #define DEFAULT_PROC_MAP_PARSE_TIMEOUT 500 47055c67edSArnaldo Carvalho de Melo 48055c67edSArnaldo Carvalho de Melo unsigned int proc_map_timeout = DEFAULT_PROC_MAP_PARSE_TIMEOUT; 49055c67edSArnaldo Carvalho de Melo 50055c67edSArnaldo Carvalho de Melo int perf_tool__process_synth_event(struct perf_tool *tool, 51055c67edSArnaldo Carvalho de Melo union perf_event *event, 52055c67edSArnaldo Carvalho de Melo struct machine *machine, 53055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 54055c67edSArnaldo Carvalho de Melo { 55055c67edSArnaldo Carvalho de Melo struct perf_sample synth_sample = { 56055c67edSArnaldo Carvalho de Melo .pid = -1, 57055c67edSArnaldo Carvalho de Melo .tid = -1, 58055c67edSArnaldo Carvalho de Melo .time = -1, 59055c67edSArnaldo Carvalho de Melo .stream_id = -1, 60055c67edSArnaldo Carvalho de Melo .cpu = -1, 61055c67edSArnaldo Carvalho de Melo .period = 1, 62055c67edSArnaldo Carvalho de Melo .cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK, 63055c67edSArnaldo Carvalho de Melo }; 64055c67edSArnaldo Carvalho de Melo 65055c67edSArnaldo Carvalho de Melo return process(tool, event, &synth_sample, machine); 66055c67edSArnaldo Carvalho de Melo }; 67055c67edSArnaldo Carvalho de Melo 68055c67edSArnaldo Carvalho de Melo /* 69055c67edSArnaldo Carvalho de Melo * Assumes that the first 4095 bytes of /proc/pid/stat contains 70055c67edSArnaldo Carvalho de Melo * the comm, tgid and ppid. 71055c67edSArnaldo Carvalho de Melo */ 7230626e08SNamhyung Kim static int perf_event__get_comm_ids(pid_t pid, pid_t tid, char *comm, size_t len, 73c1b90795SNamhyung Kim pid_t *tgid, pid_t *ppid, bool *kernel) 74055c67edSArnaldo Carvalho de Melo { 75055c67edSArnaldo Carvalho de Melo char bf[4096]; 76055c67edSArnaldo Carvalho de Melo int fd; 77055c67edSArnaldo Carvalho de Melo size_t size = 0; 78055c67edSArnaldo Carvalho de Melo ssize_t n; 79c1b90795SNamhyung Kim char *name, *tgids, *ppids, *vmpeak, *threads; 80055c67edSArnaldo Carvalho de Melo 81055c67edSArnaldo Carvalho de Melo *tgid = -1; 82055c67edSArnaldo Carvalho de Melo *ppid = -1; 83055c67edSArnaldo Carvalho de Melo 8430626e08SNamhyung Kim if (pid) 8530626e08SNamhyung Kim snprintf(bf, sizeof(bf), "/proc/%d/task/%d/status", pid, tid); 8630626e08SNamhyung Kim else 8730626e08SNamhyung Kim snprintf(bf, sizeof(bf), "/proc/%d/status", tid); 88055c67edSArnaldo Carvalho de Melo 8904ed4ccbSIan Rogers fd = open(bf, O_RDONLY); 90055c67edSArnaldo Carvalho de Melo if (fd < 0) { 9104ed4ccbSIan Rogers pr_debug("couldn't open %s\n", bf); 92055c67edSArnaldo Carvalho de Melo return -1; 93055c67edSArnaldo Carvalho de Melo } 94055c67edSArnaldo Carvalho de Melo 95055c67edSArnaldo Carvalho de Melo n = read(fd, bf, sizeof(bf) - 1); 96055c67edSArnaldo Carvalho de Melo close(fd); 97055c67edSArnaldo Carvalho de Melo if (n <= 0) { 98055c67edSArnaldo Carvalho de Melo pr_warning("Couldn't get COMM, tigd and ppid for pid %d\n", 9930626e08SNamhyung Kim tid); 100055c67edSArnaldo Carvalho de Melo return -1; 101055c67edSArnaldo Carvalho de Melo } 102055c67edSArnaldo Carvalho de Melo bf[n] = '\0'; 103055c67edSArnaldo Carvalho de Melo 104055c67edSArnaldo Carvalho de Melo name = strstr(bf, "Name:"); 105c1b90795SNamhyung Kim tgids = strstr(name ?: bf, "Tgid:"); 106c1b90795SNamhyung Kim ppids = strstr(tgids ?: bf, "PPid:"); 107c1b90795SNamhyung Kim vmpeak = strstr(ppids ?: bf, "VmPeak:"); 108c1b90795SNamhyung Kim 109c1b90795SNamhyung Kim if (vmpeak) 110c1b90795SNamhyung Kim threads = NULL; 111c1b90795SNamhyung Kim else 112c1b90795SNamhyung Kim threads = strstr(ppids ?: bf, "Threads:"); 113055c67edSArnaldo Carvalho de Melo 114055c67edSArnaldo Carvalho de Melo if (name) { 115055c67edSArnaldo Carvalho de Melo char *nl; 116055c67edSArnaldo Carvalho de Melo 117055c67edSArnaldo Carvalho de Melo name = skip_spaces(name + 5); /* strlen("Name:") */ 118055c67edSArnaldo Carvalho de Melo nl = strchr(name, '\n'); 119055c67edSArnaldo Carvalho de Melo if (nl) 120055c67edSArnaldo Carvalho de Melo *nl = '\0'; 121055c67edSArnaldo Carvalho de Melo 122055c67edSArnaldo Carvalho de Melo size = strlen(name); 123055c67edSArnaldo Carvalho de Melo if (size >= len) 124055c67edSArnaldo Carvalho de Melo size = len - 1; 125055c67edSArnaldo Carvalho de Melo memcpy(comm, name, size); 126055c67edSArnaldo Carvalho de Melo comm[size] = '\0'; 127055c67edSArnaldo Carvalho de Melo } else { 12830626e08SNamhyung Kim pr_debug("Name: string not found for pid %d\n", tid); 129055c67edSArnaldo Carvalho de Melo } 130055c67edSArnaldo Carvalho de Melo 131055c67edSArnaldo Carvalho de Melo if (tgids) { 132055c67edSArnaldo Carvalho de Melo tgids += 5; /* strlen("Tgid:") */ 133055c67edSArnaldo Carvalho de Melo *tgid = atoi(tgids); 134055c67edSArnaldo Carvalho de Melo } else { 13530626e08SNamhyung Kim pr_debug("Tgid: string not found for pid %d\n", tid); 136055c67edSArnaldo Carvalho de Melo } 137055c67edSArnaldo Carvalho de Melo 138055c67edSArnaldo Carvalho de Melo if (ppids) { 139055c67edSArnaldo Carvalho de Melo ppids += 5; /* strlen("PPid:") */ 140055c67edSArnaldo Carvalho de Melo *ppid = atoi(ppids); 141055c67edSArnaldo Carvalho de Melo } else { 14230626e08SNamhyung Kim pr_debug("PPid: string not found for pid %d\n", tid); 143055c67edSArnaldo Carvalho de Melo } 144055c67edSArnaldo Carvalho de Melo 145c1b90795SNamhyung Kim if (!vmpeak && threads) 146c1b90795SNamhyung Kim *kernel = true; 147c1b90795SNamhyung Kim else 148c1b90795SNamhyung Kim *kernel = false; 149c1b90795SNamhyung Kim 150055c67edSArnaldo Carvalho de Melo return 0; 151055c67edSArnaldo Carvalho de Melo } 152055c67edSArnaldo Carvalho de Melo 15330626e08SNamhyung Kim static int perf_event__prepare_comm(union perf_event *event, pid_t pid, pid_t tid, 154055c67edSArnaldo Carvalho de Melo struct machine *machine, 155c1b90795SNamhyung Kim pid_t *tgid, pid_t *ppid, bool *kernel) 156055c67edSArnaldo Carvalho de Melo { 157055c67edSArnaldo Carvalho de Melo size_t size; 158055c67edSArnaldo Carvalho de Melo 159055c67edSArnaldo Carvalho de Melo *ppid = -1; 160055c67edSArnaldo Carvalho de Melo 161055c67edSArnaldo Carvalho de Melo memset(&event->comm, 0, sizeof(event->comm)); 162055c67edSArnaldo Carvalho de Melo 163055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) { 16430626e08SNamhyung Kim if (perf_event__get_comm_ids(pid, tid, event->comm.comm, 165055c67edSArnaldo Carvalho de Melo sizeof(event->comm.comm), 166c1b90795SNamhyung Kim tgid, ppid, kernel) != 0) { 167055c67edSArnaldo Carvalho de Melo return -1; 168055c67edSArnaldo Carvalho de Melo } 169055c67edSArnaldo Carvalho de Melo } else { 170055c67edSArnaldo Carvalho de Melo *tgid = machine->pid; 171055c67edSArnaldo Carvalho de Melo } 172055c67edSArnaldo Carvalho de Melo 173055c67edSArnaldo Carvalho de Melo if (*tgid < 0) 174055c67edSArnaldo Carvalho de Melo return -1; 175055c67edSArnaldo Carvalho de Melo 176055c67edSArnaldo Carvalho de Melo event->comm.pid = *tgid; 177055c67edSArnaldo Carvalho de Melo event->comm.header.type = PERF_RECORD_COMM; 178055c67edSArnaldo Carvalho de Melo 179055c67edSArnaldo Carvalho de Melo size = strlen(event->comm.comm) + 1; 180055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 181055c67edSArnaldo Carvalho de Melo memset(event->comm.comm + size, 0, machine->id_hdr_size); 182055c67edSArnaldo Carvalho de Melo event->comm.header.size = (sizeof(event->comm) - 183055c67edSArnaldo Carvalho de Melo (sizeof(event->comm.comm) - size) + 184055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 18530626e08SNamhyung Kim event->comm.tid = tid; 186055c67edSArnaldo Carvalho de Melo 187055c67edSArnaldo Carvalho de Melo return 0; 188055c67edSArnaldo Carvalho de Melo } 189055c67edSArnaldo Carvalho de Melo 190055c67edSArnaldo Carvalho de Melo pid_t perf_event__synthesize_comm(struct perf_tool *tool, 191055c67edSArnaldo Carvalho de Melo union perf_event *event, pid_t pid, 192055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 193055c67edSArnaldo Carvalho de Melo struct machine *machine) 194055c67edSArnaldo Carvalho de Melo { 195055c67edSArnaldo Carvalho de Melo pid_t tgid, ppid; 196c1b90795SNamhyung Kim bool kernel_thread; 197055c67edSArnaldo Carvalho de Melo 198c1b90795SNamhyung Kim if (perf_event__prepare_comm(event, 0, pid, machine, &tgid, &ppid, 199c1b90795SNamhyung Kim &kernel_thread) != 0) 200055c67edSArnaldo Carvalho de Melo return -1; 201055c67edSArnaldo Carvalho de Melo 202055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) 203055c67edSArnaldo Carvalho de Melo return -1; 204055c67edSArnaldo Carvalho de Melo 205055c67edSArnaldo Carvalho de Melo return tgid; 206055c67edSArnaldo Carvalho de Melo } 207055c67edSArnaldo Carvalho de Melo 208055c67edSArnaldo Carvalho de Melo static void perf_event__get_ns_link_info(pid_t pid, const char *ns, 209055c67edSArnaldo Carvalho de Melo struct perf_ns_link_info *ns_link_info) 210055c67edSArnaldo Carvalho de Melo { 211055c67edSArnaldo Carvalho de Melo struct stat64 st; 212055c67edSArnaldo Carvalho de Melo char proc_ns[128]; 213055c67edSArnaldo Carvalho de Melo 214055c67edSArnaldo Carvalho de Melo sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns); 215055c67edSArnaldo Carvalho de Melo if (stat64(proc_ns, &st) == 0) { 216055c67edSArnaldo Carvalho de Melo ns_link_info->dev = st.st_dev; 217055c67edSArnaldo Carvalho de Melo ns_link_info->ino = st.st_ino; 218055c67edSArnaldo Carvalho de Melo } 219055c67edSArnaldo Carvalho de Melo } 220055c67edSArnaldo Carvalho de Melo 221055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_namespaces(struct perf_tool *tool, 222055c67edSArnaldo Carvalho de Melo union perf_event *event, 223055c67edSArnaldo Carvalho de Melo pid_t pid, pid_t tgid, 224055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 225055c67edSArnaldo Carvalho de Melo struct machine *machine) 226055c67edSArnaldo Carvalho de Melo { 227055c67edSArnaldo Carvalho de Melo u32 idx; 228055c67edSArnaldo Carvalho de Melo struct perf_ns_link_info *ns_link_info; 229055c67edSArnaldo Carvalho de Melo 230055c67edSArnaldo Carvalho de Melo if (!tool || !tool->namespace_events) 231055c67edSArnaldo Carvalho de Melo return 0; 232055c67edSArnaldo Carvalho de Melo 233055c67edSArnaldo Carvalho de Melo memset(&event->namespaces, 0, (sizeof(event->namespaces) + 234055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 235055c67edSArnaldo Carvalho de Melo machine->id_hdr_size)); 236055c67edSArnaldo Carvalho de Melo 237055c67edSArnaldo Carvalho de Melo event->namespaces.pid = tgid; 238055c67edSArnaldo Carvalho de Melo event->namespaces.tid = pid; 239055c67edSArnaldo Carvalho de Melo 240055c67edSArnaldo Carvalho de Melo event->namespaces.nr_namespaces = NR_NAMESPACES; 241055c67edSArnaldo Carvalho de Melo 242055c67edSArnaldo Carvalho de Melo ns_link_info = event->namespaces.link_info; 243055c67edSArnaldo Carvalho de Melo 244055c67edSArnaldo Carvalho de Melo for (idx = 0; idx < event->namespaces.nr_namespaces; idx++) 245055c67edSArnaldo Carvalho de Melo perf_event__get_ns_link_info(pid, perf_ns__name(idx), 246055c67edSArnaldo Carvalho de Melo &ns_link_info[idx]); 247055c67edSArnaldo Carvalho de Melo 248055c67edSArnaldo Carvalho de Melo event->namespaces.header.type = PERF_RECORD_NAMESPACES; 249055c67edSArnaldo Carvalho de Melo 250055c67edSArnaldo Carvalho de Melo event->namespaces.header.size = (sizeof(event->namespaces) + 251055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 252055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 253055c67edSArnaldo Carvalho de Melo 254055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) 255055c67edSArnaldo Carvalho de Melo return -1; 256055c67edSArnaldo Carvalho de Melo 257055c67edSArnaldo Carvalho de Melo return 0; 258055c67edSArnaldo Carvalho de Melo } 259055c67edSArnaldo Carvalho de Melo 260055c67edSArnaldo Carvalho de Melo static int perf_event__synthesize_fork(struct perf_tool *tool, 261055c67edSArnaldo Carvalho de Melo union perf_event *event, 262055c67edSArnaldo Carvalho de Melo pid_t pid, pid_t tgid, pid_t ppid, 263055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 264055c67edSArnaldo Carvalho de Melo struct machine *machine) 265055c67edSArnaldo Carvalho de Melo { 266055c67edSArnaldo Carvalho de Melo memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size); 267055c67edSArnaldo Carvalho de Melo 268055c67edSArnaldo Carvalho de Melo /* 269055c67edSArnaldo Carvalho de Melo * for main thread set parent to ppid from status file. For other 270055c67edSArnaldo Carvalho de Melo * threads set parent pid to main thread. ie., assume main thread 271055c67edSArnaldo Carvalho de Melo * spawns all threads in a process 272055c67edSArnaldo Carvalho de Melo */ 273055c67edSArnaldo Carvalho de Melo if (tgid == pid) { 274055c67edSArnaldo Carvalho de Melo event->fork.ppid = ppid; 275055c67edSArnaldo Carvalho de Melo event->fork.ptid = ppid; 276055c67edSArnaldo Carvalho de Melo } else { 277055c67edSArnaldo Carvalho de Melo event->fork.ppid = tgid; 278055c67edSArnaldo Carvalho de Melo event->fork.ptid = tgid; 279055c67edSArnaldo Carvalho de Melo } 280055c67edSArnaldo Carvalho de Melo event->fork.pid = tgid; 281055c67edSArnaldo Carvalho de Melo event->fork.tid = pid; 282055c67edSArnaldo Carvalho de Melo event->fork.header.type = PERF_RECORD_FORK; 283055c67edSArnaldo Carvalho de Melo event->fork.header.misc = PERF_RECORD_MISC_FORK_EXEC; 284055c67edSArnaldo Carvalho de Melo 285055c67edSArnaldo Carvalho de Melo event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); 286055c67edSArnaldo Carvalho de Melo 287055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) 288055c67edSArnaldo Carvalho de Melo return -1; 289055c67edSArnaldo Carvalho de Melo 290055c67edSArnaldo Carvalho de Melo return 0; 291055c67edSArnaldo Carvalho de Melo } 292055c67edSArnaldo Carvalho de Melo 2932069425eSIan Rogers static bool read_proc_maps_line(struct io *io, __u64 *start, __u64 *end, 2942069425eSIan Rogers u32 *prot, u32 *flags, __u64 *offset, 2952069425eSIan Rogers u32 *maj, u32 *min, 2962069425eSIan Rogers __u64 *inode, 2972069425eSIan Rogers ssize_t pathname_size, char *pathname) 2982069425eSIan Rogers { 2992069425eSIan Rogers __u64 temp; 3002069425eSIan Rogers int ch; 3012069425eSIan Rogers char *start_pathname = pathname; 3022069425eSIan Rogers 3032069425eSIan Rogers if (io__get_hex(io, start) != '-') 3042069425eSIan Rogers return false; 3052069425eSIan Rogers if (io__get_hex(io, end) != ' ') 3062069425eSIan Rogers return false; 3072069425eSIan Rogers 3082069425eSIan Rogers /* map protection and flags bits */ 3092069425eSIan Rogers *prot = 0; 3102069425eSIan Rogers ch = io__get_char(io); 3112069425eSIan Rogers if (ch == 'r') 3122069425eSIan Rogers *prot |= PROT_READ; 3132069425eSIan Rogers else if (ch != '-') 3142069425eSIan Rogers return false; 3152069425eSIan Rogers ch = io__get_char(io); 3162069425eSIan Rogers if (ch == 'w') 3172069425eSIan Rogers *prot |= PROT_WRITE; 3182069425eSIan Rogers else if (ch != '-') 3192069425eSIan Rogers return false; 3202069425eSIan Rogers ch = io__get_char(io); 3212069425eSIan Rogers if (ch == 'x') 3222069425eSIan Rogers *prot |= PROT_EXEC; 3232069425eSIan Rogers else if (ch != '-') 3242069425eSIan Rogers return false; 3252069425eSIan Rogers ch = io__get_char(io); 3262069425eSIan Rogers if (ch == 's') 3272069425eSIan Rogers *flags = MAP_SHARED; 3282069425eSIan Rogers else if (ch == 'p') 3292069425eSIan Rogers *flags = MAP_PRIVATE; 3302069425eSIan Rogers else 3312069425eSIan Rogers return false; 3322069425eSIan Rogers if (io__get_char(io) != ' ') 3332069425eSIan Rogers return false; 3342069425eSIan Rogers 3352069425eSIan Rogers if (io__get_hex(io, offset) != ' ') 3362069425eSIan Rogers return false; 3372069425eSIan Rogers 3382069425eSIan Rogers if (io__get_hex(io, &temp) != ':') 3392069425eSIan Rogers return false; 3402069425eSIan Rogers *maj = temp; 3412069425eSIan Rogers if (io__get_hex(io, &temp) != ' ') 3422069425eSIan Rogers return false; 3432069425eSIan Rogers *min = temp; 3442069425eSIan Rogers 3452069425eSIan Rogers ch = io__get_dec(io, inode); 3462069425eSIan Rogers if (ch != ' ') { 3472069425eSIan Rogers *pathname = '\0'; 3482069425eSIan Rogers return ch == '\n'; 3492069425eSIan Rogers } 3502069425eSIan Rogers do { 3512069425eSIan Rogers ch = io__get_char(io); 3522069425eSIan Rogers } while (ch == ' '); 3532069425eSIan Rogers while (true) { 3542069425eSIan Rogers if (ch < 0) 3552069425eSIan Rogers return false; 3562069425eSIan Rogers if (ch == '\0' || ch == '\n' || 3572069425eSIan Rogers (pathname + 1 - start_pathname) >= pathname_size) { 3582069425eSIan Rogers *pathname = '\0'; 3592069425eSIan Rogers return true; 3602069425eSIan Rogers } 3612069425eSIan Rogers *pathname++ = ch; 3622069425eSIan Rogers ch = io__get_char(io); 3632069425eSIan Rogers } 3642069425eSIan Rogers } 3652069425eSIan Rogers 3664183a8d7SJiri Olsa static void perf_record_mmap2__read_build_id(struct perf_record_mmap2 *event, 3674183a8d7SJiri Olsa bool is_kernel) 3684183a8d7SJiri Olsa { 3694183a8d7SJiri Olsa struct build_id bid; 3704183a8d7SJiri Olsa int rc; 3714183a8d7SJiri Olsa 3724183a8d7SJiri Olsa if (is_kernel) 3734183a8d7SJiri Olsa rc = sysfs__read_build_id("/sys/kernel/notes", &bid); 3744183a8d7SJiri Olsa else 3754183a8d7SJiri Olsa rc = filename__read_build_id(event->filename, &bid) > 0 ? 0 : -1; 3764183a8d7SJiri Olsa 3774183a8d7SJiri Olsa if (rc == 0) { 3784183a8d7SJiri Olsa memcpy(event->build_id, bid.data, sizeof(bid.data)); 3794183a8d7SJiri Olsa event->build_id_size = (u8) bid.size; 3804183a8d7SJiri Olsa event->header.misc |= PERF_RECORD_MISC_MMAP_BUILD_ID; 3814183a8d7SJiri Olsa event->__reserved_1 = 0; 3824183a8d7SJiri Olsa event->__reserved_2 = 0; 3834183a8d7SJiri Olsa } else { 3844183a8d7SJiri Olsa if (event->filename[0] == '/') { 3854183a8d7SJiri Olsa pr_debug2("Failed to read build ID for %s\n", 3864183a8d7SJiri Olsa event->filename); 3874183a8d7SJiri Olsa } 3884183a8d7SJiri Olsa } 3894183a8d7SJiri Olsa } 3904183a8d7SJiri Olsa 391055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_mmap_events(struct perf_tool *tool, 392055c67edSArnaldo Carvalho de Melo union perf_event *event, 393055c67edSArnaldo Carvalho de Melo pid_t pid, pid_t tgid, 394055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 395055c67edSArnaldo Carvalho de Melo struct machine *machine, 396055c67edSArnaldo Carvalho de Melo bool mmap_data) 397055c67edSArnaldo Carvalho de Melo { 398055c67edSArnaldo Carvalho de Melo unsigned long long t; 39904ed4ccbSIan Rogers char bf[BUFSIZ]; 4002069425eSIan Rogers struct io io; 401055c67edSArnaldo Carvalho de Melo bool truncation = false; 402055c67edSArnaldo Carvalho de Melo unsigned long long timeout = proc_map_timeout * 1000000ULL; 403055c67edSArnaldo Carvalho de Melo int rc = 0; 404055c67edSArnaldo Carvalho de Melo const char *hugetlbfs_mnt = hugetlbfs__mountpoint(); 405055c67edSArnaldo Carvalho de Melo int hugetlbfs_mnt_len = hugetlbfs_mnt ? strlen(hugetlbfs_mnt) : 0; 406055c67edSArnaldo Carvalho de Melo 407055c67edSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 408055c67edSArnaldo Carvalho de Melo return 0; 409055c67edSArnaldo Carvalho de Melo 41004ed4ccbSIan Rogers snprintf(bf, sizeof(bf), "%s/proc/%d/task/%d/maps", 411055c67edSArnaldo Carvalho de Melo machine->root_dir, pid, pid); 412055c67edSArnaldo Carvalho de Melo 4132069425eSIan Rogers io.fd = open(bf, O_RDONLY, 0); 4142069425eSIan Rogers if (io.fd < 0) { 415055c67edSArnaldo Carvalho de Melo /* 416055c67edSArnaldo Carvalho de Melo * We raced with a task exiting - just return: 417055c67edSArnaldo Carvalho de Melo */ 41804ed4ccbSIan Rogers pr_debug("couldn't open %s\n", bf); 419055c67edSArnaldo Carvalho de Melo return -1; 420055c67edSArnaldo Carvalho de Melo } 4212069425eSIan Rogers io__init(&io, io.fd, bf, sizeof(bf)); 422055c67edSArnaldo Carvalho de Melo 423055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_MMAP2; 424055c67edSArnaldo Carvalho de Melo t = rdclock(); 425055c67edSArnaldo Carvalho de Melo 4262069425eSIan Rogers while (!io.eof) { 4272069425eSIan Rogers static const char anonstr[] = "//anon"; 4282a76f6deSIan Rogers size_t size, aligned_size; 429055c67edSArnaldo Carvalho de Melo 4302069425eSIan Rogers /* ensure null termination since stack will be reused. */ 4312069425eSIan Rogers event->mmap2.filename[0] = '\0'; 4322069425eSIan Rogers 4332069425eSIan Rogers /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 4342069425eSIan Rogers if (!read_proc_maps_line(&io, 4352069425eSIan Rogers &event->mmap2.start, 4362069425eSIan Rogers &event->mmap2.len, 4372069425eSIan Rogers &event->mmap2.prot, 4382069425eSIan Rogers &event->mmap2.flags, 4392069425eSIan Rogers &event->mmap2.pgoff, 4402069425eSIan Rogers &event->mmap2.maj, 4412069425eSIan Rogers &event->mmap2.min, 4422069425eSIan Rogers &event->mmap2.ino, 4432069425eSIan Rogers sizeof(event->mmap2.filename), 4442069425eSIan Rogers event->mmap2.filename)) 4452069425eSIan Rogers continue; 446055c67edSArnaldo Carvalho de Melo 447055c67edSArnaldo Carvalho de Melo if ((rdclock() - t) > timeout) { 44804ed4ccbSIan Rogers pr_warning("Reading %s/proc/%d/task/%d/maps time out. " 449055c67edSArnaldo Carvalho de Melo "You may want to increase " 450055c67edSArnaldo Carvalho de Melo "the time limit by --proc-map-timeout\n", 45104ed4ccbSIan Rogers machine->root_dir, pid, pid); 452055c67edSArnaldo Carvalho de Melo truncation = true; 453055c67edSArnaldo Carvalho de Melo goto out; 454055c67edSArnaldo Carvalho de Melo } 455055c67edSArnaldo Carvalho de Melo 4563b7a15b0SIan Rogers event->mmap2.ino_generation = 0; 457055c67edSArnaldo Carvalho de Melo 458055c67edSArnaldo Carvalho de Melo /* 459055c67edSArnaldo Carvalho de Melo * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 460055c67edSArnaldo Carvalho de Melo */ 461055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) 462055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_USER; 463055c67edSArnaldo Carvalho de Melo else 464055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_GUEST_USER; 465055c67edSArnaldo Carvalho de Melo 4662069425eSIan Rogers if ((event->mmap2.prot & PROT_EXEC) == 0) { 4672069425eSIan Rogers if (!mmap_data || (event->mmap2.prot & PROT_READ) == 0) 468055c67edSArnaldo Carvalho de Melo continue; 469055c67edSArnaldo Carvalho de Melo 470055c67edSArnaldo Carvalho de Melo event->header.misc |= PERF_RECORD_MISC_MMAP_DATA; 471055c67edSArnaldo Carvalho de Melo } 472055c67edSArnaldo Carvalho de Melo 473055c67edSArnaldo Carvalho de Melo out: 474055c67edSArnaldo Carvalho de Melo if (truncation) 475055c67edSArnaldo Carvalho de Melo event->header.misc |= PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT; 476055c67edSArnaldo Carvalho de Melo 4772069425eSIan Rogers if (!strcmp(event->mmap2.filename, "")) 4782069425eSIan Rogers strcpy(event->mmap2.filename, anonstr); 479055c67edSArnaldo Carvalho de Melo 480055c67edSArnaldo Carvalho de Melo if (hugetlbfs_mnt_len && 4812069425eSIan Rogers !strncmp(event->mmap2.filename, hugetlbfs_mnt, 4822069425eSIan Rogers hugetlbfs_mnt_len)) { 4832069425eSIan Rogers strcpy(event->mmap2.filename, anonstr); 484055c67edSArnaldo Carvalho de Melo event->mmap2.flags |= MAP_HUGETLB; 485055c67edSArnaldo Carvalho de Melo } 486055c67edSArnaldo Carvalho de Melo 4872069425eSIan Rogers size = strlen(event->mmap2.filename) + 1; 4882a76f6deSIan Rogers aligned_size = PERF_ALIGN(size, sizeof(u64)); 489055c67edSArnaldo Carvalho de Melo event->mmap2.len -= event->mmap.start; 490055c67edSArnaldo Carvalho de Melo event->mmap2.header.size = (sizeof(event->mmap2) - 4912a76f6deSIan Rogers (sizeof(event->mmap2.filename) - aligned_size)); 4922a76f6deSIan Rogers memset(event->mmap2.filename + size, 0, machine->id_hdr_size + 4932a76f6deSIan Rogers (aligned_size - size)); 494055c67edSArnaldo Carvalho de Melo event->mmap2.header.size += machine->id_hdr_size; 495055c67edSArnaldo Carvalho de Melo event->mmap2.pid = tgid; 496055c67edSArnaldo Carvalho de Melo event->mmap2.tid = pid; 497055c67edSArnaldo Carvalho de Melo 4984183a8d7SJiri Olsa if (symbol_conf.buildid_mmap2) 4994183a8d7SJiri Olsa perf_record_mmap2__read_build_id(&event->mmap2, false); 5004183a8d7SJiri Olsa 501055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { 502055c67edSArnaldo Carvalho de Melo rc = -1; 503055c67edSArnaldo Carvalho de Melo break; 504055c67edSArnaldo Carvalho de Melo } 505055c67edSArnaldo Carvalho de Melo 506055c67edSArnaldo Carvalho de Melo if (truncation) 507055c67edSArnaldo Carvalho de Melo break; 508055c67edSArnaldo Carvalho de Melo } 509055c67edSArnaldo Carvalho de Melo 5102069425eSIan Rogers close(io.fd); 511055c67edSArnaldo Carvalho de Melo return rc; 512055c67edSArnaldo Carvalho de Melo } 513055c67edSArnaldo Carvalho de Melo 514ab64069fSNamhyung Kim #ifdef HAVE_FILE_HANDLE 515ab64069fSNamhyung Kim static int perf_event__synthesize_cgroup(struct perf_tool *tool, 516ab64069fSNamhyung Kim union perf_event *event, 517ab64069fSNamhyung Kim char *path, size_t mount_len, 518ab64069fSNamhyung Kim perf_event__handler_t process, 519ab64069fSNamhyung Kim struct machine *machine) 520ab64069fSNamhyung Kim { 521ab64069fSNamhyung Kim size_t event_size = sizeof(event->cgroup) - sizeof(event->cgroup.path); 522ab64069fSNamhyung Kim size_t path_len = strlen(path) - mount_len + 1; 523ab64069fSNamhyung Kim struct { 524ab64069fSNamhyung Kim struct file_handle fh; 525ab64069fSNamhyung Kim uint64_t cgroup_id; 526ab64069fSNamhyung Kim } handle; 527ab64069fSNamhyung Kim int mount_id; 528ab64069fSNamhyung Kim 529ab64069fSNamhyung Kim while (path_len % sizeof(u64)) 530ab64069fSNamhyung Kim path[mount_len + path_len++] = '\0'; 531ab64069fSNamhyung Kim 532ab64069fSNamhyung Kim memset(&event->cgroup, 0, event_size); 533ab64069fSNamhyung Kim 534ab64069fSNamhyung Kim event->cgroup.header.type = PERF_RECORD_CGROUP; 535ab64069fSNamhyung Kim event->cgroup.header.size = event_size + path_len + machine->id_hdr_size; 536ab64069fSNamhyung Kim 537ab64069fSNamhyung Kim handle.fh.handle_bytes = sizeof(handle.cgroup_id); 538ab64069fSNamhyung Kim if (name_to_handle_at(AT_FDCWD, path, &handle.fh, &mount_id, 0) < 0) { 539ab64069fSNamhyung Kim pr_debug("stat failed: %s\n", path); 540ab64069fSNamhyung Kim return -1; 541ab64069fSNamhyung Kim } 542ab64069fSNamhyung Kim 543ab64069fSNamhyung Kim event->cgroup.id = handle.cgroup_id; 544ab64069fSNamhyung Kim strncpy(event->cgroup.path, path + mount_len, path_len); 545ab64069fSNamhyung Kim memset(event->cgroup.path + path_len, 0, machine->id_hdr_size); 546ab64069fSNamhyung Kim 547ab64069fSNamhyung Kim if (perf_tool__process_synth_event(tool, event, machine, process) < 0) { 548ab64069fSNamhyung Kim pr_debug("process synth event failed\n"); 549ab64069fSNamhyung Kim return -1; 550ab64069fSNamhyung Kim } 551ab64069fSNamhyung Kim 552ab64069fSNamhyung Kim return 0; 553ab64069fSNamhyung Kim } 554ab64069fSNamhyung Kim 555ab64069fSNamhyung Kim static int perf_event__walk_cgroup_tree(struct perf_tool *tool, 556ab64069fSNamhyung Kim union perf_event *event, 557ab64069fSNamhyung Kim char *path, size_t mount_len, 558ab64069fSNamhyung Kim perf_event__handler_t process, 559ab64069fSNamhyung Kim struct machine *machine) 560ab64069fSNamhyung Kim { 561ab64069fSNamhyung Kim size_t pos = strlen(path); 562ab64069fSNamhyung Kim DIR *d; 563ab64069fSNamhyung Kim struct dirent *dent; 564ab64069fSNamhyung Kim int ret = 0; 565ab64069fSNamhyung Kim 566ab64069fSNamhyung Kim if (perf_event__synthesize_cgroup(tool, event, path, mount_len, 567ab64069fSNamhyung Kim process, machine) < 0) 568ab64069fSNamhyung Kim return -1; 569ab64069fSNamhyung Kim 570ab64069fSNamhyung Kim d = opendir(path); 571ab64069fSNamhyung Kim if (d == NULL) { 572ab64069fSNamhyung Kim pr_debug("failed to open directory: %s\n", path); 573ab64069fSNamhyung Kim return -1; 574ab64069fSNamhyung Kim } 575ab64069fSNamhyung Kim 576ab64069fSNamhyung Kim while ((dent = readdir(d)) != NULL) { 577ab64069fSNamhyung Kim if (dent->d_type != DT_DIR) 578ab64069fSNamhyung Kim continue; 579ab64069fSNamhyung Kim if (!strcmp(dent->d_name, ".") || 580ab64069fSNamhyung Kim !strcmp(dent->d_name, "..")) 581ab64069fSNamhyung Kim continue; 582ab64069fSNamhyung Kim 583ab64069fSNamhyung Kim /* any sane path should be less than PATH_MAX */ 584ab64069fSNamhyung Kim if (strlen(path) + strlen(dent->d_name) + 1 >= PATH_MAX) 585ab64069fSNamhyung Kim continue; 586ab64069fSNamhyung Kim 587ab64069fSNamhyung Kim if (path[pos - 1] != '/') 588ab64069fSNamhyung Kim strcat(path, "/"); 589ab64069fSNamhyung Kim strcat(path, dent->d_name); 590ab64069fSNamhyung Kim 591ab64069fSNamhyung Kim ret = perf_event__walk_cgroup_tree(tool, event, path, 592ab64069fSNamhyung Kim mount_len, process, machine); 593ab64069fSNamhyung Kim if (ret < 0) 594ab64069fSNamhyung Kim break; 595ab64069fSNamhyung Kim 596ab64069fSNamhyung Kim path[pos] = '\0'; 597ab64069fSNamhyung Kim } 598ab64069fSNamhyung Kim 599ab64069fSNamhyung Kim closedir(d); 600ab64069fSNamhyung Kim return ret; 601ab64069fSNamhyung Kim } 602ab64069fSNamhyung Kim 603ab64069fSNamhyung Kim int perf_event__synthesize_cgroups(struct perf_tool *tool, 604ab64069fSNamhyung Kim perf_event__handler_t process, 605ab64069fSNamhyung Kim struct machine *machine) 606ab64069fSNamhyung Kim { 607ab64069fSNamhyung Kim union perf_event event; 608ab64069fSNamhyung Kim char cgrp_root[PATH_MAX]; 609ab64069fSNamhyung Kim size_t mount_len; /* length of mount point in the path */ 610ab64069fSNamhyung Kim 611aa50d953SNamhyung Kim if (!tool || !tool->cgroup_events) 612aa50d953SNamhyung Kim return 0; 613aa50d953SNamhyung Kim 614ab64069fSNamhyung Kim if (cgroupfs_find_mountpoint(cgrp_root, PATH_MAX, "perf_event") < 0) { 615ab64069fSNamhyung Kim pr_debug("cannot find cgroup mount point\n"); 616ab64069fSNamhyung Kim return -1; 617ab64069fSNamhyung Kim } 618ab64069fSNamhyung Kim 619ab64069fSNamhyung Kim mount_len = strlen(cgrp_root); 620ab64069fSNamhyung Kim /* make sure the path starts with a slash (after mount point) */ 621ab64069fSNamhyung Kim strcat(cgrp_root, "/"); 622ab64069fSNamhyung Kim 623ab64069fSNamhyung Kim if (perf_event__walk_cgroup_tree(tool, &event, cgrp_root, mount_len, 624ab64069fSNamhyung Kim process, machine) < 0) 625ab64069fSNamhyung Kim return -1; 626ab64069fSNamhyung Kim 627ab64069fSNamhyung Kim return 0; 628ab64069fSNamhyung Kim } 629ab64069fSNamhyung Kim #else 630ab64069fSNamhyung Kim int perf_event__synthesize_cgroups(struct perf_tool *tool __maybe_unused, 631ab64069fSNamhyung Kim perf_event__handler_t process __maybe_unused, 632ab64069fSNamhyung Kim struct machine *machine __maybe_unused) 633ab64069fSNamhyung Kim { 634ab64069fSNamhyung Kim return -1; 635ab64069fSNamhyung Kim } 636ab64069fSNamhyung Kim #endif 637ab64069fSNamhyung Kim 638055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process, 639055c67edSArnaldo Carvalho de Melo struct machine *machine) 640055c67edSArnaldo Carvalho de Melo { 641055c67edSArnaldo Carvalho de Melo int rc = 0; 642055c67edSArnaldo Carvalho de Melo struct map *pos; 643055c67edSArnaldo Carvalho de Melo struct maps *maps = machine__kernel_maps(machine); 644e0dbf18fSJiri Olsa union perf_event *event; 645e0dbf18fSJiri Olsa size_t size = symbol_conf.buildid_mmap2 ? 646e0dbf18fSJiri Olsa sizeof(event->mmap2) : sizeof(event->mmap); 647e0dbf18fSJiri Olsa 648e0dbf18fSJiri Olsa event = zalloc(size + machine->id_hdr_size); 649055c67edSArnaldo Carvalho de Melo if (event == NULL) { 650055c67edSArnaldo Carvalho de Melo pr_debug("Not enough memory synthesizing mmap event " 651055c67edSArnaldo Carvalho de Melo "for kernel modules\n"); 652055c67edSArnaldo Carvalho de Melo return -1; 653055c67edSArnaldo Carvalho de Melo } 654055c67edSArnaldo Carvalho de Melo 655055c67edSArnaldo Carvalho de Melo /* 656055c67edSArnaldo Carvalho de Melo * kernel uses 0 for user space maps, see kernel/perf_event.c 657055c67edSArnaldo Carvalho de Melo * __perf_event_mmap 658055c67edSArnaldo Carvalho de Melo */ 659055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) 660055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_KERNEL; 661055c67edSArnaldo Carvalho de Melo else 662055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 663055c67edSArnaldo Carvalho de Melo 6648efc4f05SArnaldo Carvalho de Melo maps__for_each_entry(maps, pos) { 665055c67edSArnaldo Carvalho de Melo if (!__map__is_kmodule(pos)) 666055c67edSArnaldo Carvalho de Melo continue; 667055c67edSArnaldo Carvalho de Melo 668e0dbf18fSJiri Olsa if (symbol_conf.buildid_mmap2) { 669e0dbf18fSJiri Olsa size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); 670e0dbf18fSJiri Olsa event->mmap2.header.type = PERF_RECORD_MMAP2; 671e0dbf18fSJiri Olsa event->mmap2.header.size = (sizeof(event->mmap2) - 672e0dbf18fSJiri Olsa (sizeof(event->mmap2.filename) - size)); 673e0dbf18fSJiri Olsa memset(event->mmap2.filename + size, 0, machine->id_hdr_size); 674e0dbf18fSJiri Olsa event->mmap2.header.size += machine->id_hdr_size; 675e0dbf18fSJiri Olsa event->mmap2.start = pos->start; 676e0dbf18fSJiri Olsa event->mmap2.len = pos->end - pos->start; 677e0dbf18fSJiri Olsa event->mmap2.pid = machine->pid; 678e0dbf18fSJiri Olsa 679e0dbf18fSJiri Olsa memcpy(event->mmap2.filename, pos->dso->long_name, 680e0dbf18fSJiri Olsa pos->dso->long_name_len + 1); 6814183a8d7SJiri Olsa 6824183a8d7SJiri Olsa perf_record_mmap2__read_build_id(&event->mmap2, false); 683e0dbf18fSJiri Olsa } else { 684055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); 685055c67edSArnaldo Carvalho de Melo event->mmap.header.type = PERF_RECORD_MMAP; 686055c67edSArnaldo Carvalho de Melo event->mmap.header.size = (sizeof(event->mmap) - 687055c67edSArnaldo Carvalho de Melo (sizeof(event->mmap.filename) - size)); 688055c67edSArnaldo Carvalho de Melo memset(event->mmap.filename + size, 0, machine->id_hdr_size); 689055c67edSArnaldo Carvalho de Melo event->mmap.header.size += machine->id_hdr_size; 690055c67edSArnaldo Carvalho de Melo event->mmap.start = pos->start; 691055c67edSArnaldo Carvalho de Melo event->mmap.len = pos->end - pos->start; 692055c67edSArnaldo Carvalho de Melo event->mmap.pid = machine->pid; 693055c67edSArnaldo Carvalho de Melo 694055c67edSArnaldo Carvalho de Melo memcpy(event->mmap.filename, pos->dso->long_name, 695055c67edSArnaldo Carvalho de Melo pos->dso->long_name_len + 1); 696e0dbf18fSJiri Olsa } 697e0dbf18fSJiri Olsa 698055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { 699055c67edSArnaldo Carvalho de Melo rc = -1; 700055c67edSArnaldo Carvalho de Melo break; 701055c67edSArnaldo Carvalho de Melo } 702055c67edSArnaldo Carvalho de Melo } 703055c67edSArnaldo Carvalho de Melo 704055c67edSArnaldo Carvalho de Melo free(event); 705055c67edSArnaldo Carvalho de Melo return rc; 706055c67edSArnaldo Carvalho de Melo } 707055c67edSArnaldo Carvalho de Melo 708473f742eSNamhyung Kim static int filter_task(const struct dirent *dirent) 709473f742eSNamhyung Kim { 710473f742eSNamhyung Kim return isdigit(dirent->d_name[0]); 711473f742eSNamhyung Kim } 712473f742eSNamhyung Kim 713055c67edSArnaldo Carvalho de Melo static int __event__synthesize_thread(union perf_event *comm_event, 714055c67edSArnaldo Carvalho de Melo union perf_event *mmap_event, 715055c67edSArnaldo Carvalho de Melo union perf_event *fork_event, 716055c67edSArnaldo Carvalho de Melo union perf_event *namespaces_event, 717055c67edSArnaldo Carvalho de Melo pid_t pid, int full, perf_event__handler_t process, 71884111b9cSNamhyung Kim struct perf_tool *tool, struct machine *machine, 71984111b9cSNamhyung Kim bool needs_mmap, bool mmap_data) 720055c67edSArnaldo Carvalho de Melo { 721055c67edSArnaldo Carvalho de Melo char filename[PATH_MAX]; 722473f742eSNamhyung Kim struct dirent **dirent; 723055c67edSArnaldo Carvalho de Melo pid_t tgid, ppid; 724055c67edSArnaldo Carvalho de Melo int rc = 0; 725473f742eSNamhyung Kim int i, n; 726055c67edSArnaldo Carvalho de Melo 727055c67edSArnaldo Carvalho de Melo /* special case: only send one comm event using passed in pid */ 728055c67edSArnaldo Carvalho de Melo if (!full) { 729055c67edSArnaldo Carvalho de Melo tgid = perf_event__synthesize_comm(tool, comm_event, pid, 730055c67edSArnaldo Carvalho de Melo process, machine); 731055c67edSArnaldo Carvalho de Melo 732055c67edSArnaldo Carvalho de Melo if (tgid == -1) 733055c67edSArnaldo Carvalho de Melo return -1; 734055c67edSArnaldo Carvalho de Melo 735055c67edSArnaldo Carvalho de Melo if (perf_event__synthesize_namespaces(tool, namespaces_event, pid, 736055c67edSArnaldo Carvalho de Melo tgid, process, machine) < 0) 737055c67edSArnaldo Carvalho de Melo return -1; 738055c67edSArnaldo Carvalho de Melo 739055c67edSArnaldo Carvalho de Melo /* 740055c67edSArnaldo Carvalho de Melo * send mmap only for thread group leader 74179b6bb73SArnaldo Carvalho de Melo * see thread__init_maps() 742055c67edSArnaldo Carvalho de Melo */ 74384111b9cSNamhyung Kim if (pid == tgid && needs_mmap && 744055c67edSArnaldo Carvalho de Melo perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 745055c67edSArnaldo Carvalho de Melo process, machine, mmap_data)) 746055c67edSArnaldo Carvalho de Melo return -1; 747055c67edSArnaldo Carvalho de Melo 748055c67edSArnaldo Carvalho de Melo return 0; 749055c67edSArnaldo Carvalho de Melo } 750055c67edSArnaldo Carvalho de Melo 751055c67edSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 752055c67edSArnaldo Carvalho de Melo return 0; 753055c67edSArnaldo Carvalho de Melo 754055c67edSArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), "%s/proc/%d/task", 755055c67edSArnaldo Carvalho de Melo machine->root_dir, pid); 756055c67edSArnaldo Carvalho de Melo 757363afa3aSNamhyung Kim n = scandir(filename, &dirent, filter_task, NULL); 758473f742eSNamhyung Kim if (n < 0) 759473f742eSNamhyung Kim return n; 760055c67edSArnaldo Carvalho de Melo 761473f742eSNamhyung Kim for (i = 0; i < n; i++) { 762055c67edSArnaldo Carvalho de Melo char *end; 763055c67edSArnaldo Carvalho de Melo pid_t _pid; 764c3d59cfdSThomas Richter bool kernel_thread = false; 765055c67edSArnaldo Carvalho de Melo 766473f742eSNamhyung Kim _pid = strtol(dirent[i]->d_name, &end, 10); 767055c67edSArnaldo Carvalho de Melo if (*end) 768055c67edSArnaldo Carvalho de Melo continue; 769055c67edSArnaldo Carvalho de Melo 770ff898552SNamhyung Kim /* some threads may exit just after scan, ignore it */ 77130626e08SNamhyung Kim if (perf_event__prepare_comm(comm_event, pid, _pid, machine, 772c1b90795SNamhyung Kim &tgid, &ppid, &kernel_thread) != 0) 773ff898552SNamhyung Kim continue; 774055c67edSArnaldo Carvalho de Melo 775ff898552SNamhyung Kim rc = -1; 776055c67edSArnaldo Carvalho de Melo if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid, 777055c67edSArnaldo Carvalho de Melo ppid, process, machine) < 0) 778055c67edSArnaldo Carvalho de Melo break; 779055c67edSArnaldo Carvalho de Melo 780055c67edSArnaldo Carvalho de Melo if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid, 781055c67edSArnaldo Carvalho de Melo tgid, process, machine) < 0) 782055c67edSArnaldo Carvalho de Melo break; 783055c67edSArnaldo Carvalho de Melo 784055c67edSArnaldo Carvalho de Melo /* 785055c67edSArnaldo Carvalho de Melo * Send the prepared comm event 786055c67edSArnaldo Carvalho de Melo */ 787055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, comm_event, machine, process) != 0) 788055c67edSArnaldo Carvalho de Melo break; 789055c67edSArnaldo Carvalho de Melo 790055c67edSArnaldo Carvalho de Melo rc = 0; 79184111b9cSNamhyung Kim if (_pid == pid && !kernel_thread && needs_mmap) { 792055c67edSArnaldo Carvalho de Melo /* process the parent's maps too */ 793055c67edSArnaldo Carvalho de Melo rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 794055c67edSArnaldo Carvalho de Melo process, machine, mmap_data); 795055c67edSArnaldo Carvalho de Melo if (rc) 796055c67edSArnaldo Carvalho de Melo break; 797055c67edSArnaldo Carvalho de Melo } 798055c67edSArnaldo Carvalho de Melo } 799055c67edSArnaldo Carvalho de Melo 800473f742eSNamhyung Kim for (i = 0; i < n; i++) 801473f742eSNamhyung Kim zfree(&dirent[i]); 802473f742eSNamhyung Kim free(dirent); 803473f742eSNamhyung Kim 804055c67edSArnaldo Carvalho de Melo return rc; 805055c67edSArnaldo Carvalho de Melo } 806055c67edSArnaldo Carvalho de Melo 807055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_thread_map(struct perf_tool *tool, 808055c67edSArnaldo Carvalho de Melo struct perf_thread_map *threads, 809055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 810055c67edSArnaldo Carvalho de Melo struct machine *machine, 81184111b9cSNamhyung Kim bool needs_mmap, bool mmap_data) 812055c67edSArnaldo Carvalho de Melo { 813055c67edSArnaldo Carvalho de Melo union perf_event *comm_event, *mmap_event, *fork_event; 814055c67edSArnaldo Carvalho de Melo union perf_event *namespaces_event; 815055c67edSArnaldo Carvalho de Melo int err = -1, thread, j; 816055c67edSArnaldo Carvalho de Melo 817055c67edSArnaldo Carvalho de Melo comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 818055c67edSArnaldo Carvalho de Melo if (comm_event == NULL) 819055c67edSArnaldo Carvalho de Melo goto out; 820055c67edSArnaldo Carvalho de Melo 821055c67edSArnaldo Carvalho de Melo mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); 822055c67edSArnaldo Carvalho de Melo if (mmap_event == NULL) 823055c67edSArnaldo Carvalho de Melo goto out_free_comm; 824055c67edSArnaldo Carvalho de Melo 825055c67edSArnaldo Carvalho de Melo fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); 826055c67edSArnaldo Carvalho de Melo if (fork_event == NULL) 827055c67edSArnaldo Carvalho de Melo goto out_free_mmap; 828055c67edSArnaldo Carvalho de Melo 829055c67edSArnaldo Carvalho de Melo namespaces_event = malloc(sizeof(namespaces_event->namespaces) + 830055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 831055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 832055c67edSArnaldo Carvalho de Melo if (namespaces_event == NULL) 833055c67edSArnaldo Carvalho de Melo goto out_free_fork; 834055c67edSArnaldo Carvalho de Melo 835055c67edSArnaldo Carvalho de Melo err = 0; 836055c67edSArnaldo Carvalho de Melo for (thread = 0; thread < threads->nr; ++thread) { 837055c67edSArnaldo Carvalho de Melo if (__event__synthesize_thread(comm_event, mmap_event, 838055c67edSArnaldo Carvalho de Melo fork_event, namespaces_event, 839055c67edSArnaldo Carvalho de Melo perf_thread_map__pid(threads, thread), 0, 840055c67edSArnaldo Carvalho de Melo process, tool, machine, 84184111b9cSNamhyung Kim needs_mmap, mmap_data)) { 842055c67edSArnaldo Carvalho de Melo err = -1; 843055c67edSArnaldo Carvalho de Melo break; 844055c67edSArnaldo Carvalho de Melo } 845055c67edSArnaldo Carvalho de Melo 846055c67edSArnaldo Carvalho de Melo /* 847055c67edSArnaldo Carvalho de Melo * comm.pid is set to thread group id by 848055c67edSArnaldo Carvalho de Melo * perf_event__synthesize_comm 849055c67edSArnaldo Carvalho de Melo */ 850055c67edSArnaldo Carvalho de Melo if ((int) comm_event->comm.pid != perf_thread_map__pid(threads, thread)) { 851055c67edSArnaldo Carvalho de Melo bool need_leader = true; 852055c67edSArnaldo Carvalho de Melo 853055c67edSArnaldo Carvalho de Melo /* is thread group leader in thread_map? */ 854055c67edSArnaldo Carvalho de Melo for (j = 0; j < threads->nr; ++j) { 855055c67edSArnaldo Carvalho de Melo if ((int) comm_event->comm.pid == perf_thread_map__pid(threads, j)) { 856055c67edSArnaldo Carvalho de Melo need_leader = false; 857055c67edSArnaldo Carvalho de Melo break; 858055c67edSArnaldo Carvalho de Melo } 859055c67edSArnaldo Carvalho de Melo } 860055c67edSArnaldo Carvalho de Melo 861055c67edSArnaldo Carvalho de Melo /* if not, generate events for it */ 862055c67edSArnaldo Carvalho de Melo if (need_leader && 863055c67edSArnaldo Carvalho de Melo __event__synthesize_thread(comm_event, mmap_event, 864055c67edSArnaldo Carvalho de Melo fork_event, namespaces_event, 865055c67edSArnaldo Carvalho de Melo comm_event->comm.pid, 0, 866055c67edSArnaldo Carvalho de Melo process, tool, machine, 86784111b9cSNamhyung Kim needs_mmap, mmap_data)) { 868055c67edSArnaldo Carvalho de Melo err = -1; 869055c67edSArnaldo Carvalho de Melo break; 870055c67edSArnaldo Carvalho de Melo } 871055c67edSArnaldo Carvalho de Melo } 872055c67edSArnaldo Carvalho de Melo } 873055c67edSArnaldo Carvalho de Melo free(namespaces_event); 874055c67edSArnaldo Carvalho de Melo out_free_fork: 875055c67edSArnaldo Carvalho de Melo free(fork_event); 876055c67edSArnaldo Carvalho de Melo out_free_mmap: 877055c67edSArnaldo Carvalho de Melo free(mmap_event); 878055c67edSArnaldo Carvalho de Melo out_free_comm: 879055c67edSArnaldo Carvalho de Melo free(comm_event); 880055c67edSArnaldo Carvalho de Melo out: 881055c67edSArnaldo Carvalho de Melo return err; 882055c67edSArnaldo Carvalho de Melo } 883055c67edSArnaldo Carvalho de Melo 884055c67edSArnaldo Carvalho de Melo static int __perf_event__synthesize_threads(struct perf_tool *tool, 885055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 886055c67edSArnaldo Carvalho de Melo struct machine *machine, 88784111b9cSNamhyung Kim bool needs_mmap, 888055c67edSArnaldo Carvalho de Melo bool mmap_data, 889055c67edSArnaldo Carvalho de Melo struct dirent **dirent, 890055c67edSArnaldo Carvalho de Melo int start, 891055c67edSArnaldo Carvalho de Melo int num) 892055c67edSArnaldo Carvalho de Melo { 893055c67edSArnaldo Carvalho de Melo union perf_event *comm_event, *mmap_event, *fork_event; 894055c67edSArnaldo Carvalho de Melo union perf_event *namespaces_event; 895055c67edSArnaldo Carvalho de Melo int err = -1; 896055c67edSArnaldo Carvalho de Melo char *end; 897055c67edSArnaldo Carvalho de Melo pid_t pid; 898055c67edSArnaldo Carvalho de Melo int i; 899055c67edSArnaldo Carvalho de Melo 900055c67edSArnaldo Carvalho de Melo comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 901055c67edSArnaldo Carvalho de Melo if (comm_event == NULL) 902055c67edSArnaldo Carvalho de Melo goto out; 903055c67edSArnaldo Carvalho de Melo 904055c67edSArnaldo Carvalho de Melo mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); 905055c67edSArnaldo Carvalho de Melo if (mmap_event == NULL) 906055c67edSArnaldo Carvalho de Melo goto out_free_comm; 907055c67edSArnaldo Carvalho de Melo 908055c67edSArnaldo Carvalho de Melo fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); 909055c67edSArnaldo Carvalho de Melo if (fork_event == NULL) 910055c67edSArnaldo Carvalho de Melo goto out_free_mmap; 911055c67edSArnaldo Carvalho de Melo 912055c67edSArnaldo Carvalho de Melo namespaces_event = malloc(sizeof(namespaces_event->namespaces) + 913055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 914055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 915055c67edSArnaldo Carvalho de Melo if (namespaces_event == NULL) 916055c67edSArnaldo Carvalho de Melo goto out_free_fork; 917055c67edSArnaldo Carvalho de Melo 918055c67edSArnaldo Carvalho de Melo for (i = start; i < start + num; i++) { 919055c67edSArnaldo Carvalho de Melo if (!isdigit(dirent[i]->d_name[0])) 920055c67edSArnaldo Carvalho de Melo continue; 921055c67edSArnaldo Carvalho de Melo 922055c67edSArnaldo Carvalho de Melo pid = (pid_t)strtol(dirent[i]->d_name, &end, 10); 923055c67edSArnaldo Carvalho de Melo /* only interested in proper numerical dirents */ 924055c67edSArnaldo Carvalho de Melo if (*end) 925055c67edSArnaldo Carvalho de Melo continue; 926055c67edSArnaldo Carvalho de Melo /* 927055c67edSArnaldo Carvalho de Melo * We may race with exiting thread, so don't stop just because 928055c67edSArnaldo Carvalho de Melo * one thread couldn't be synthesized. 929055c67edSArnaldo Carvalho de Melo */ 930055c67edSArnaldo Carvalho de Melo __event__synthesize_thread(comm_event, mmap_event, fork_event, 931055c67edSArnaldo Carvalho de Melo namespaces_event, pid, 1, process, 93284111b9cSNamhyung Kim tool, machine, needs_mmap, mmap_data); 933055c67edSArnaldo Carvalho de Melo } 934055c67edSArnaldo Carvalho de Melo err = 0; 935055c67edSArnaldo Carvalho de Melo 936055c67edSArnaldo Carvalho de Melo free(namespaces_event); 937055c67edSArnaldo Carvalho de Melo out_free_fork: 938055c67edSArnaldo Carvalho de Melo free(fork_event); 939055c67edSArnaldo Carvalho de Melo out_free_mmap: 940055c67edSArnaldo Carvalho de Melo free(mmap_event); 941055c67edSArnaldo Carvalho de Melo out_free_comm: 942055c67edSArnaldo Carvalho de Melo free(comm_event); 943055c67edSArnaldo Carvalho de Melo out: 944055c67edSArnaldo Carvalho de Melo return err; 945055c67edSArnaldo Carvalho de Melo } 946055c67edSArnaldo Carvalho de Melo 947055c67edSArnaldo Carvalho de Melo struct synthesize_threads_arg { 948055c67edSArnaldo Carvalho de Melo struct perf_tool *tool; 949055c67edSArnaldo Carvalho de Melo perf_event__handler_t process; 950055c67edSArnaldo Carvalho de Melo struct machine *machine; 95184111b9cSNamhyung Kim bool needs_mmap; 952055c67edSArnaldo Carvalho de Melo bool mmap_data; 953055c67edSArnaldo Carvalho de Melo struct dirent **dirent; 954055c67edSArnaldo Carvalho de Melo int num; 955055c67edSArnaldo Carvalho de Melo int start; 956055c67edSArnaldo Carvalho de Melo }; 957055c67edSArnaldo Carvalho de Melo 958055c67edSArnaldo Carvalho de Melo static void *synthesize_threads_worker(void *arg) 959055c67edSArnaldo Carvalho de Melo { 960055c67edSArnaldo Carvalho de Melo struct synthesize_threads_arg *args = arg; 961055c67edSArnaldo Carvalho de Melo 962055c67edSArnaldo Carvalho de Melo __perf_event__synthesize_threads(args->tool, args->process, 96384111b9cSNamhyung Kim args->machine, 96484111b9cSNamhyung Kim args->needs_mmap, args->mmap_data, 965055c67edSArnaldo Carvalho de Melo args->dirent, 966055c67edSArnaldo Carvalho de Melo args->start, args->num); 967055c67edSArnaldo Carvalho de Melo return NULL; 968055c67edSArnaldo Carvalho de Melo } 969055c67edSArnaldo Carvalho de Melo 970055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_threads(struct perf_tool *tool, 971055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 972055c67edSArnaldo Carvalho de Melo struct machine *machine, 97384111b9cSNamhyung Kim bool needs_mmap, bool mmap_data, 974055c67edSArnaldo Carvalho de Melo unsigned int nr_threads_synthesize) 975055c67edSArnaldo Carvalho de Melo { 976055c67edSArnaldo Carvalho de Melo struct synthesize_threads_arg *args = NULL; 977055c67edSArnaldo Carvalho de Melo pthread_t *synthesize_threads = NULL; 978055c67edSArnaldo Carvalho de Melo char proc_path[PATH_MAX]; 979055c67edSArnaldo Carvalho de Melo struct dirent **dirent; 980055c67edSArnaldo Carvalho de Melo int num_per_thread; 981055c67edSArnaldo Carvalho de Melo int m, n, i, j; 982055c67edSArnaldo Carvalho de Melo int thread_nr; 983055c67edSArnaldo Carvalho de Melo int base = 0; 984055c67edSArnaldo Carvalho de Melo int err = -1; 985055c67edSArnaldo Carvalho de Melo 986055c67edSArnaldo Carvalho de Melo 987055c67edSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 988055c67edSArnaldo Carvalho de Melo return 0; 989055c67edSArnaldo Carvalho de Melo 990055c67edSArnaldo Carvalho de Melo snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); 991363afa3aSNamhyung Kim n = scandir(proc_path, &dirent, filter_task, NULL); 992055c67edSArnaldo Carvalho de Melo if (n < 0) 993055c67edSArnaldo Carvalho de Melo return err; 994055c67edSArnaldo Carvalho de Melo 995055c67edSArnaldo Carvalho de Melo if (nr_threads_synthesize == UINT_MAX) 996055c67edSArnaldo Carvalho de Melo thread_nr = sysconf(_SC_NPROCESSORS_ONLN); 997055c67edSArnaldo Carvalho de Melo else 998055c67edSArnaldo Carvalho de Melo thread_nr = nr_threads_synthesize; 999055c67edSArnaldo Carvalho de Melo 1000055c67edSArnaldo Carvalho de Melo if (thread_nr <= 1) { 1001055c67edSArnaldo Carvalho de Melo err = __perf_event__synthesize_threads(tool, process, 100284111b9cSNamhyung Kim machine, 100384111b9cSNamhyung Kim needs_mmap, mmap_data, 1004055c67edSArnaldo Carvalho de Melo dirent, base, n); 1005055c67edSArnaldo Carvalho de Melo goto free_dirent; 1006055c67edSArnaldo Carvalho de Melo } 1007055c67edSArnaldo Carvalho de Melo if (thread_nr > n) 1008055c67edSArnaldo Carvalho de Melo thread_nr = n; 1009055c67edSArnaldo Carvalho de Melo 1010055c67edSArnaldo Carvalho de Melo synthesize_threads = calloc(sizeof(pthread_t), thread_nr); 1011055c67edSArnaldo Carvalho de Melo if (synthesize_threads == NULL) 1012055c67edSArnaldo Carvalho de Melo goto free_dirent; 1013055c67edSArnaldo Carvalho de Melo 1014055c67edSArnaldo Carvalho de Melo args = calloc(sizeof(*args), thread_nr); 1015055c67edSArnaldo Carvalho de Melo if (args == NULL) 1016055c67edSArnaldo Carvalho de Melo goto free_threads; 1017055c67edSArnaldo Carvalho de Melo 1018055c67edSArnaldo Carvalho de Melo num_per_thread = n / thread_nr; 1019055c67edSArnaldo Carvalho de Melo m = n % thread_nr; 1020055c67edSArnaldo Carvalho de Melo for (i = 0; i < thread_nr; i++) { 1021055c67edSArnaldo Carvalho de Melo args[i].tool = tool; 1022055c67edSArnaldo Carvalho de Melo args[i].process = process; 1023055c67edSArnaldo Carvalho de Melo args[i].machine = machine; 102484111b9cSNamhyung Kim args[i].needs_mmap = needs_mmap; 1025055c67edSArnaldo Carvalho de Melo args[i].mmap_data = mmap_data; 1026055c67edSArnaldo Carvalho de Melo args[i].dirent = dirent; 1027055c67edSArnaldo Carvalho de Melo } 1028055c67edSArnaldo Carvalho de Melo for (i = 0; i < m; i++) { 1029055c67edSArnaldo Carvalho de Melo args[i].num = num_per_thread + 1; 1030055c67edSArnaldo Carvalho de Melo args[i].start = i * args[i].num; 1031055c67edSArnaldo Carvalho de Melo } 1032055c67edSArnaldo Carvalho de Melo if (i != 0) 1033055c67edSArnaldo Carvalho de Melo base = args[i-1].start + args[i-1].num; 1034055c67edSArnaldo Carvalho de Melo for (j = i; j < thread_nr; j++) { 1035055c67edSArnaldo Carvalho de Melo args[j].num = num_per_thread; 1036055c67edSArnaldo Carvalho de Melo args[j].start = base + (j - i) * args[i].num; 1037055c67edSArnaldo Carvalho de Melo } 1038055c67edSArnaldo Carvalho de Melo 1039055c67edSArnaldo Carvalho de Melo for (i = 0; i < thread_nr; i++) { 1040055c67edSArnaldo Carvalho de Melo if (pthread_create(&synthesize_threads[i], NULL, 1041055c67edSArnaldo Carvalho de Melo synthesize_threads_worker, &args[i])) 1042055c67edSArnaldo Carvalho de Melo goto out_join; 1043055c67edSArnaldo Carvalho de Melo } 1044055c67edSArnaldo Carvalho de Melo err = 0; 1045055c67edSArnaldo Carvalho de Melo out_join: 1046055c67edSArnaldo Carvalho de Melo for (i = 0; i < thread_nr; i++) 1047055c67edSArnaldo Carvalho de Melo pthread_join(synthesize_threads[i], NULL); 1048055c67edSArnaldo Carvalho de Melo free(args); 1049055c67edSArnaldo Carvalho de Melo free_threads: 1050055c67edSArnaldo Carvalho de Melo free(synthesize_threads); 1051055c67edSArnaldo Carvalho de Melo free_dirent: 1052055c67edSArnaldo Carvalho de Melo for (i = 0; i < n; i++) 1053055c67edSArnaldo Carvalho de Melo zfree(&dirent[i]); 1054055c67edSArnaldo Carvalho de Melo free(dirent); 1055055c67edSArnaldo Carvalho de Melo 1056055c67edSArnaldo Carvalho de Melo return err; 1057055c67edSArnaldo Carvalho de Melo } 1058055c67edSArnaldo Carvalho de Melo 1059055c67edSArnaldo Carvalho de Melo int __weak perf_event__synthesize_extra_kmaps(struct perf_tool *tool __maybe_unused, 1060055c67edSArnaldo Carvalho de Melo perf_event__handler_t process __maybe_unused, 1061055c67edSArnaldo Carvalho de Melo struct machine *machine __maybe_unused) 1062055c67edSArnaldo Carvalho de Melo { 1063055c67edSArnaldo Carvalho de Melo return 0; 1064055c67edSArnaldo Carvalho de Melo } 1065055c67edSArnaldo Carvalho de Melo 1066055c67edSArnaldo Carvalho de Melo static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 1067055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1068055c67edSArnaldo Carvalho de Melo struct machine *machine) 1069055c67edSArnaldo Carvalho de Melo { 1070978410ffSJiri Olsa union perf_event *event; 1071978410ffSJiri Olsa size_t size = symbol_conf.buildid_mmap2 ? 1072978410ffSJiri Olsa sizeof(event->mmap2) : sizeof(event->mmap); 1073055c67edSArnaldo Carvalho de Melo struct map *map = machine__kernel_map(machine); 1074055c67edSArnaldo Carvalho de Melo struct kmap *kmap; 1075055c67edSArnaldo Carvalho de Melo int err; 1076055c67edSArnaldo Carvalho de Melo 1077055c67edSArnaldo Carvalho de Melo if (map == NULL) 1078055c67edSArnaldo Carvalho de Melo return -1; 1079055c67edSArnaldo Carvalho de Melo 1080055c67edSArnaldo Carvalho de Melo kmap = map__kmap(map); 1081055c67edSArnaldo Carvalho de Melo if (!kmap->ref_reloc_sym) 1082055c67edSArnaldo Carvalho de Melo return -1; 1083055c67edSArnaldo Carvalho de Melo 1084055c67edSArnaldo Carvalho de Melo /* 1085055c67edSArnaldo Carvalho de Melo * We should get this from /sys/kernel/sections/.text, but till that is 1086055c67edSArnaldo Carvalho de Melo * available use this, and after it is use this as a fallback for older 1087055c67edSArnaldo Carvalho de Melo * kernels. 1088055c67edSArnaldo Carvalho de Melo */ 1089978410ffSJiri Olsa event = zalloc(size + machine->id_hdr_size); 1090055c67edSArnaldo Carvalho de Melo if (event == NULL) { 1091055c67edSArnaldo Carvalho de Melo pr_debug("Not enough memory synthesizing mmap event " 1092055c67edSArnaldo Carvalho de Melo "for kernel modules\n"); 1093055c67edSArnaldo Carvalho de Melo return -1; 1094055c67edSArnaldo Carvalho de Melo } 1095055c67edSArnaldo Carvalho de Melo 1096055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) { 1097055c67edSArnaldo Carvalho de Melo /* 1098055c67edSArnaldo Carvalho de Melo * kernel uses PERF_RECORD_MISC_USER for user space maps, 1099055c67edSArnaldo Carvalho de Melo * see kernel/perf_event.c __perf_event_mmap 1100055c67edSArnaldo Carvalho de Melo */ 1101055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_KERNEL; 1102055c67edSArnaldo Carvalho de Melo } else { 1103055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 1104055c67edSArnaldo Carvalho de Melo } 1105055c67edSArnaldo Carvalho de Melo 1106978410ffSJiri Olsa if (symbol_conf.buildid_mmap2) { 1107978410ffSJiri Olsa size = snprintf(event->mmap2.filename, sizeof(event->mmap2.filename), 1108978410ffSJiri Olsa "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1; 1109978410ffSJiri Olsa size = PERF_ALIGN(size, sizeof(u64)); 1110978410ffSJiri Olsa event->mmap2.header.type = PERF_RECORD_MMAP2; 1111978410ffSJiri Olsa event->mmap2.header.size = (sizeof(event->mmap2) - 1112978410ffSJiri Olsa (sizeof(event->mmap2.filename) - size) + machine->id_hdr_size); 1113978410ffSJiri Olsa event->mmap2.pgoff = kmap->ref_reloc_sym->addr; 1114978410ffSJiri Olsa event->mmap2.start = map->start; 1115978410ffSJiri Olsa event->mmap2.len = map->end - event->mmap.start; 1116978410ffSJiri Olsa event->mmap2.pid = machine->pid; 11174183a8d7SJiri Olsa 11184183a8d7SJiri Olsa perf_record_mmap2__read_build_id(&event->mmap2, true); 1119978410ffSJiri Olsa } else { 1120055c67edSArnaldo Carvalho de Melo size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 1121055c67edSArnaldo Carvalho de Melo "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1; 1122055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 1123055c67edSArnaldo Carvalho de Melo event->mmap.header.type = PERF_RECORD_MMAP; 1124055c67edSArnaldo Carvalho de Melo event->mmap.header.size = (sizeof(event->mmap) - 1125055c67edSArnaldo Carvalho de Melo (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); 1126055c67edSArnaldo Carvalho de Melo event->mmap.pgoff = kmap->ref_reloc_sym->addr; 1127055c67edSArnaldo Carvalho de Melo event->mmap.start = map->start; 1128055c67edSArnaldo Carvalho de Melo event->mmap.len = map->end - event->mmap.start; 1129055c67edSArnaldo Carvalho de Melo event->mmap.pid = machine->pid; 1130978410ffSJiri Olsa } 1131055c67edSArnaldo Carvalho de Melo 1132055c67edSArnaldo Carvalho de Melo err = perf_tool__process_synth_event(tool, event, machine, process); 1133055c67edSArnaldo Carvalho de Melo free(event); 1134055c67edSArnaldo Carvalho de Melo 1135055c67edSArnaldo Carvalho de Melo return err; 1136055c67edSArnaldo Carvalho de Melo } 1137055c67edSArnaldo Carvalho de Melo 1138055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 1139055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1140055c67edSArnaldo Carvalho de Melo struct machine *machine) 1141055c67edSArnaldo Carvalho de Melo { 1142055c67edSArnaldo Carvalho de Melo int err; 1143055c67edSArnaldo Carvalho de Melo 1144055c67edSArnaldo Carvalho de Melo err = __perf_event__synthesize_kernel_mmap(tool, process, machine); 1145055c67edSArnaldo Carvalho de Melo if (err < 0) 1146055c67edSArnaldo Carvalho de Melo return err; 1147055c67edSArnaldo Carvalho de Melo 1148055c67edSArnaldo Carvalho de Melo return perf_event__synthesize_extra_kmaps(tool, process, machine); 1149055c67edSArnaldo Carvalho de Melo } 1150055c67edSArnaldo Carvalho de Melo 1151055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_thread_map2(struct perf_tool *tool, 1152055c67edSArnaldo Carvalho de Melo struct perf_thread_map *threads, 1153055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1154055c67edSArnaldo Carvalho de Melo struct machine *machine) 1155055c67edSArnaldo Carvalho de Melo { 1156055c67edSArnaldo Carvalho de Melo union perf_event *event; 1157055c67edSArnaldo Carvalho de Melo int i, err, size; 1158055c67edSArnaldo Carvalho de Melo 1159055c67edSArnaldo Carvalho de Melo size = sizeof(event->thread_map); 1160055c67edSArnaldo Carvalho de Melo size += threads->nr * sizeof(event->thread_map.entries[0]); 1161055c67edSArnaldo Carvalho de Melo 1162055c67edSArnaldo Carvalho de Melo event = zalloc(size); 1163055c67edSArnaldo Carvalho de Melo if (!event) 1164055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1165055c67edSArnaldo Carvalho de Melo 1166055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_THREAD_MAP; 1167055c67edSArnaldo Carvalho de Melo event->header.size = size; 1168055c67edSArnaldo Carvalho de Melo event->thread_map.nr = threads->nr; 1169055c67edSArnaldo Carvalho de Melo 1170055c67edSArnaldo Carvalho de Melo for (i = 0; i < threads->nr; i++) { 1171055c67edSArnaldo Carvalho de Melo struct perf_record_thread_map_entry *entry = &event->thread_map.entries[i]; 1172055c67edSArnaldo Carvalho de Melo char *comm = perf_thread_map__comm(threads, i); 1173055c67edSArnaldo Carvalho de Melo 1174055c67edSArnaldo Carvalho de Melo if (!comm) 1175055c67edSArnaldo Carvalho de Melo comm = (char *) ""; 1176055c67edSArnaldo Carvalho de Melo 1177055c67edSArnaldo Carvalho de Melo entry->pid = perf_thread_map__pid(threads, i); 1178055c67edSArnaldo Carvalho de Melo strncpy((char *) &entry->comm, comm, sizeof(entry->comm)); 1179055c67edSArnaldo Carvalho de Melo } 1180055c67edSArnaldo Carvalho de Melo 1181055c67edSArnaldo Carvalho de Melo err = process(tool, event, NULL, machine); 1182055c67edSArnaldo Carvalho de Melo 1183055c67edSArnaldo Carvalho de Melo free(event); 1184055c67edSArnaldo Carvalho de Melo return err; 1185055c67edSArnaldo Carvalho de Melo } 1186055c67edSArnaldo Carvalho de Melo 1187b2f10cd4SIan Rogers static void synthesize_cpus(struct perf_record_cpu_map_data *data, 118835ae6f09SIan Rogers const struct perf_cpu_map *map) 1189055c67edSArnaldo Carvalho de Melo { 119044028699SIan Rogers int i, map_nr = perf_cpu_map__nr(map); 1191055c67edSArnaldo Carvalho de Melo 1192b2f10cd4SIan Rogers data->cpus_data.nr = map_nr; 1193055c67edSArnaldo Carvalho de Melo 119444028699SIan Rogers for (i = 0; i < map_nr; i++) 1195b2f10cd4SIan Rogers data->cpus_data.cpu[i] = perf_cpu_map__cpu(map, i).cpu; 1196055c67edSArnaldo Carvalho de Melo } 1197055c67edSArnaldo Carvalho de Melo 1198b2f10cd4SIan Rogers static void synthesize_mask(struct perf_record_cpu_map_data *data, 119935ae6f09SIan Rogers const struct perf_cpu_map *map, int max) 1200055c67edSArnaldo Carvalho de Melo { 1201b2f10cd4SIan Rogers int idx; 1202b2f10cd4SIan Rogers struct perf_cpu cpu; 1203055c67edSArnaldo Carvalho de Melo 1204b2f10cd4SIan Rogers /* Due to padding, the 4bytes per entry mask variant is always smaller. */ 1205b2f10cd4SIan Rogers data->mask32_data.nr = BITS_TO_U32(max); 1206b2f10cd4SIan Rogers data->mask32_data.long_size = 4; 1207055c67edSArnaldo Carvalho de Melo 1208b2f10cd4SIan Rogers perf_cpu_map__for_each_cpu(cpu, idx, map) { 1209b2f10cd4SIan Rogers int bit_word = cpu.cpu / 32; 1210b2f10cd4SIan Rogers __u32 bit_mask = 1U << (cpu.cpu & 31); 1211b2f10cd4SIan Rogers 1212b2f10cd4SIan Rogers data->mask32_data.mask[bit_word] |= bit_mask; 1213b2f10cd4SIan Rogers } 1214055c67edSArnaldo Carvalho de Melo } 1215055c67edSArnaldo Carvalho de Melo 121635ae6f09SIan Rogers static size_t cpus_size(const struct perf_cpu_map *map) 1217055c67edSArnaldo Carvalho de Melo { 121844028699SIan Rogers return sizeof(struct cpu_map_entries) + perf_cpu_map__nr(map) * sizeof(u16); 1219055c67edSArnaldo Carvalho de Melo } 1220055c67edSArnaldo Carvalho de Melo 122135ae6f09SIan Rogers static size_t mask_size(const struct perf_cpu_map *map, int *max) 1222055c67edSArnaldo Carvalho de Melo { 122328526478SIan Rogers *max = perf_cpu_map__max(map).cpu; 1224b2f10cd4SIan Rogers return sizeof(struct perf_record_mask_cpu_map32) + BITS_TO_U32(*max) * sizeof(__u32); 1225055c67edSArnaldo Carvalho de Melo } 1226055c67edSArnaldo Carvalho de Melo 122735ae6f09SIan Rogers static void *cpu_map_data__alloc(const struct perf_cpu_map *map, size_t *size, 122835ae6f09SIan Rogers u16 *type, int *max) 1229055c67edSArnaldo Carvalho de Melo { 1230055c67edSArnaldo Carvalho de Melo size_t size_cpus, size_mask; 1231055c67edSArnaldo Carvalho de Melo bool is_dummy = perf_cpu_map__empty(map); 1232055c67edSArnaldo Carvalho de Melo 1233055c67edSArnaldo Carvalho de Melo /* 1234055c67edSArnaldo Carvalho de Melo * Both array and mask data have variable size based 1235055c67edSArnaldo Carvalho de Melo * on the number of cpus and their actual values. 1236055c67edSArnaldo Carvalho de Melo * The size of the 'struct perf_record_cpu_map_data' is: 1237055c67edSArnaldo Carvalho de Melo * 1238055c67edSArnaldo Carvalho de Melo * array = size of 'struct cpu_map_entries' + 1239055c67edSArnaldo Carvalho de Melo * number of cpus * sizeof(u64) 1240055c67edSArnaldo Carvalho de Melo * 1241055c67edSArnaldo Carvalho de Melo * mask = size of 'struct perf_record_record_cpu_map' + 1242055c67edSArnaldo Carvalho de Melo * maximum cpu bit converted to size of longs 1243055c67edSArnaldo Carvalho de Melo * 12444d39c89fSIngo Molnar * and finally + the size of 'struct perf_record_cpu_map_data'. 1245055c67edSArnaldo Carvalho de Melo */ 1246055c67edSArnaldo Carvalho de Melo size_cpus = cpus_size(map); 1247055c67edSArnaldo Carvalho de Melo size_mask = mask_size(map, max); 1248055c67edSArnaldo Carvalho de Melo 1249055c67edSArnaldo Carvalho de Melo if (is_dummy || (size_cpus < size_mask)) { 1250055c67edSArnaldo Carvalho de Melo *size += size_cpus; 1251055c67edSArnaldo Carvalho de Melo *type = PERF_CPU_MAP__CPUS; 1252055c67edSArnaldo Carvalho de Melo } else { 1253055c67edSArnaldo Carvalho de Melo *size += size_mask; 1254055c67edSArnaldo Carvalho de Melo *type = PERF_CPU_MAP__MASK; 1255055c67edSArnaldo Carvalho de Melo } 1256055c67edSArnaldo Carvalho de Melo 1257b2f10cd4SIan Rogers *size += sizeof(__u16); /* For perf_record_cpu_map_data.type. */ 1258055c67edSArnaldo Carvalho de Melo *size = PERF_ALIGN(*size, sizeof(u64)); 1259055c67edSArnaldo Carvalho de Melo return zalloc(*size); 1260055c67edSArnaldo Carvalho de Melo } 1261055c67edSArnaldo Carvalho de Melo 126235ae6f09SIan Rogers static void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, 126335ae6f09SIan Rogers const struct perf_cpu_map *map, 1264055c67edSArnaldo Carvalho de Melo u16 type, int max) 1265055c67edSArnaldo Carvalho de Melo { 1266055c67edSArnaldo Carvalho de Melo data->type = type; 1267055c67edSArnaldo Carvalho de Melo 1268055c67edSArnaldo Carvalho de Melo switch (type) { 1269055c67edSArnaldo Carvalho de Melo case PERF_CPU_MAP__CPUS: 1270b2f10cd4SIan Rogers synthesize_cpus(data, map); 1271055c67edSArnaldo Carvalho de Melo break; 1272055c67edSArnaldo Carvalho de Melo case PERF_CPU_MAP__MASK: 1273b2f10cd4SIan Rogers synthesize_mask(data, map, max); 1274055c67edSArnaldo Carvalho de Melo default: 1275055c67edSArnaldo Carvalho de Melo break; 12768284bbeaSZou Wei } 1277055c67edSArnaldo Carvalho de Melo } 1278055c67edSArnaldo Carvalho de Melo 127935ae6f09SIan Rogers static struct perf_record_cpu_map *cpu_map_event__new(const struct perf_cpu_map *map) 1280055c67edSArnaldo Carvalho de Melo { 1281b2f10cd4SIan Rogers size_t size = sizeof(struct perf_event_header); 1282055c67edSArnaldo Carvalho de Melo struct perf_record_cpu_map *event; 1283055c67edSArnaldo Carvalho de Melo int max; 1284055c67edSArnaldo Carvalho de Melo u16 type; 1285055c67edSArnaldo Carvalho de Melo 1286055c67edSArnaldo Carvalho de Melo event = cpu_map_data__alloc(map, &size, &type, &max); 1287055c67edSArnaldo Carvalho de Melo if (!event) 1288055c67edSArnaldo Carvalho de Melo return NULL; 1289055c67edSArnaldo Carvalho de Melo 1290055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_CPU_MAP; 1291055c67edSArnaldo Carvalho de Melo event->header.size = size; 1292055c67edSArnaldo Carvalho de Melo event->data.type = type; 1293055c67edSArnaldo Carvalho de Melo 1294055c67edSArnaldo Carvalho de Melo cpu_map_data__synthesize(&event->data, map, type, max); 1295055c67edSArnaldo Carvalho de Melo return event; 1296055c67edSArnaldo Carvalho de Melo } 1297055c67edSArnaldo Carvalho de Melo 1298055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_cpu_map(struct perf_tool *tool, 129935ae6f09SIan Rogers const struct perf_cpu_map *map, 1300055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1301055c67edSArnaldo Carvalho de Melo struct machine *machine) 1302055c67edSArnaldo Carvalho de Melo { 1303055c67edSArnaldo Carvalho de Melo struct perf_record_cpu_map *event; 1304055c67edSArnaldo Carvalho de Melo int err; 1305055c67edSArnaldo Carvalho de Melo 1306055c67edSArnaldo Carvalho de Melo event = cpu_map_event__new(map); 1307055c67edSArnaldo Carvalho de Melo if (!event) 1308055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1309055c67edSArnaldo Carvalho de Melo 1310055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *) event, NULL, machine); 1311055c67edSArnaldo Carvalho de Melo 1312055c67edSArnaldo Carvalho de Melo free(event); 1313055c67edSArnaldo Carvalho de Melo return err; 1314055c67edSArnaldo Carvalho de Melo } 1315055c67edSArnaldo Carvalho de Melo 1316055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_config(struct perf_tool *tool, 1317055c67edSArnaldo Carvalho de Melo struct perf_stat_config *config, 1318055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1319055c67edSArnaldo Carvalho de Melo struct machine *machine) 1320055c67edSArnaldo Carvalho de Melo { 1321055c67edSArnaldo Carvalho de Melo struct perf_record_stat_config *event; 1322055c67edSArnaldo Carvalho de Melo int size, i = 0, err; 1323055c67edSArnaldo Carvalho de Melo 1324055c67edSArnaldo Carvalho de Melo size = sizeof(*event); 1325055c67edSArnaldo Carvalho de Melo size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0])); 1326055c67edSArnaldo Carvalho de Melo 1327055c67edSArnaldo Carvalho de Melo event = zalloc(size); 1328055c67edSArnaldo Carvalho de Melo if (!event) 1329055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1330055c67edSArnaldo Carvalho de Melo 1331055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_STAT_CONFIG; 1332055c67edSArnaldo Carvalho de Melo event->header.size = size; 1333055c67edSArnaldo Carvalho de Melo event->nr = PERF_STAT_CONFIG_TERM__MAX; 1334055c67edSArnaldo Carvalho de Melo 1335055c67edSArnaldo Carvalho de Melo #define ADD(__term, __val) \ 1336055c67edSArnaldo Carvalho de Melo event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term; \ 1337055c67edSArnaldo Carvalho de Melo event->data[i].val = __val; \ 1338055c67edSArnaldo Carvalho de Melo i++; 1339055c67edSArnaldo Carvalho de Melo 1340055c67edSArnaldo Carvalho de Melo ADD(AGGR_MODE, config->aggr_mode) 1341055c67edSArnaldo Carvalho de Melo ADD(INTERVAL, config->interval) 1342055c67edSArnaldo Carvalho de Melo ADD(SCALE, config->scale) 1343055c67edSArnaldo Carvalho de Melo 1344055c67edSArnaldo Carvalho de Melo WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX, 1345055c67edSArnaldo Carvalho de Melo "stat config terms unbalanced\n"); 1346055c67edSArnaldo Carvalho de Melo #undef ADD 1347055c67edSArnaldo Carvalho de Melo 1348055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *) event, NULL, machine); 1349055c67edSArnaldo Carvalho de Melo 1350055c67edSArnaldo Carvalho de Melo free(event); 1351055c67edSArnaldo Carvalho de Melo return err; 1352055c67edSArnaldo Carvalho de Melo } 1353055c67edSArnaldo Carvalho de Melo 1354055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat(struct perf_tool *tool, 13556d18804bSIan Rogers struct perf_cpu cpu, u32 thread, u64 id, 1356055c67edSArnaldo Carvalho de Melo struct perf_counts_values *count, 1357055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1358055c67edSArnaldo Carvalho de Melo struct machine *machine) 1359055c67edSArnaldo Carvalho de Melo { 1360055c67edSArnaldo Carvalho de Melo struct perf_record_stat event; 1361055c67edSArnaldo Carvalho de Melo 1362055c67edSArnaldo Carvalho de Melo event.header.type = PERF_RECORD_STAT; 1363055c67edSArnaldo Carvalho de Melo event.header.size = sizeof(event); 1364055c67edSArnaldo Carvalho de Melo event.header.misc = 0; 1365055c67edSArnaldo Carvalho de Melo 1366055c67edSArnaldo Carvalho de Melo event.id = id; 13676d18804bSIan Rogers event.cpu = cpu.cpu; 1368055c67edSArnaldo Carvalho de Melo event.thread = thread; 1369055c67edSArnaldo Carvalho de Melo event.val = count->val; 1370055c67edSArnaldo Carvalho de Melo event.ena = count->ena; 1371055c67edSArnaldo Carvalho de Melo event.run = count->run; 1372055c67edSArnaldo Carvalho de Melo 1373055c67edSArnaldo Carvalho de Melo return process(tool, (union perf_event *) &event, NULL, machine); 1374055c67edSArnaldo Carvalho de Melo } 1375055c67edSArnaldo Carvalho de Melo 1376055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_round(struct perf_tool *tool, 1377055c67edSArnaldo Carvalho de Melo u64 evtime, u64 type, 1378055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1379055c67edSArnaldo Carvalho de Melo struct machine *machine) 1380055c67edSArnaldo Carvalho de Melo { 1381055c67edSArnaldo Carvalho de Melo struct perf_record_stat_round event; 1382055c67edSArnaldo Carvalho de Melo 1383055c67edSArnaldo Carvalho de Melo event.header.type = PERF_RECORD_STAT_ROUND; 1384055c67edSArnaldo Carvalho de Melo event.header.size = sizeof(event); 1385055c67edSArnaldo Carvalho de Melo event.header.misc = 0; 1386055c67edSArnaldo Carvalho de Melo 1387055c67edSArnaldo Carvalho de Melo event.time = evtime; 1388055c67edSArnaldo Carvalho de Melo event.type = type; 1389055c67edSArnaldo Carvalho de Melo 1390055c67edSArnaldo Carvalho de Melo return process(tool, (union perf_event *) &event, NULL, machine); 1391055c67edSArnaldo Carvalho de Melo } 1392055c67edSArnaldo Carvalho de Melo 1393055c67edSArnaldo Carvalho de Melo size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format) 1394055c67edSArnaldo Carvalho de Melo { 1395055c67edSArnaldo Carvalho de Melo size_t sz, result = sizeof(struct perf_record_sample); 1396055c67edSArnaldo Carvalho de Melo 1397055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IDENTIFIER) 1398055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1399055c67edSArnaldo Carvalho de Melo 1400055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IP) 1401055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1402055c67edSArnaldo Carvalho de Melo 1403055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TID) 1404055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1405055c67edSArnaldo Carvalho de Melo 1406055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TIME) 1407055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1408055c67edSArnaldo Carvalho de Melo 1409055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ADDR) 1410055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1411055c67edSArnaldo Carvalho de Melo 1412055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ID) 1413055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1414055c67edSArnaldo Carvalho de Melo 1415055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STREAM_ID) 1416055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1417055c67edSArnaldo Carvalho de Melo 1418055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CPU) 1419055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1420055c67edSArnaldo Carvalho de Melo 1421055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PERIOD) 1422055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1423055c67edSArnaldo Carvalho de Melo 1424055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_READ) { 1425055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1426055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 1427055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1428055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 1429055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1430055c67edSArnaldo Carvalho de Melo /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 1431055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) { 1432*f52679b7SNamhyung Kim sz = sample_read_value_size(read_format); 1433*f52679b7SNamhyung Kim result += sz * sample->read.group.nr; 1434055c67edSArnaldo Carvalho de Melo } else { 1435055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1436*f52679b7SNamhyung Kim if (read_format & PERF_FORMAT_LOST) 1437*f52679b7SNamhyung Kim result += sizeof(u64); 1438055c67edSArnaldo Carvalho de Melo } 1439055c67edSArnaldo Carvalho de Melo } 1440055c67edSArnaldo Carvalho de Melo 1441055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CALLCHAIN) { 1442055c67edSArnaldo Carvalho de Melo sz = (sample->callchain->nr + 1) * sizeof(u64); 1443055c67edSArnaldo Carvalho de Melo result += sz; 1444055c67edSArnaldo Carvalho de Melo } 1445055c67edSArnaldo Carvalho de Melo 1446055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_RAW) { 1447055c67edSArnaldo Carvalho de Melo result += sizeof(u32); 1448055c67edSArnaldo Carvalho de Melo result += sample->raw_size; 1449055c67edSArnaldo Carvalho de Melo } 1450055c67edSArnaldo Carvalho de Melo 1451055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_BRANCH_STACK) { 1452055c67edSArnaldo Carvalho de Melo sz = sample->branch_stack->nr * sizeof(struct branch_entry); 145342bbabedSKan Liang /* nr, hw_idx */ 145442bbabedSKan Liang sz += 2 * sizeof(u64); 1455055c67edSArnaldo Carvalho de Melo result += sz; 1456055c67edSArnaldo Carvalho de Melo } 1457055c67edSArnaldo Carvalho de Melo 1458055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_USER) { 1459055c67edSArnaldo Carvalho de Melo if (sample->user_regs.abi) { 1460055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1461055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->user_regs.mask) * sizeof(u64); 1462055c67edSArnaldo Carvalho de Melo result += sz; 1463055c67edSArnaldo Carvalho de Melo } else { 1464055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1465055c67edSArnaldo Carvalho de Melo } 1466055c67edSArnaldo Carvalho de Melo } 1467055c67edSArnaldo Carvalho de Melo 1468055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STACK_USER) { 1469055c67edSArnaldo Carvalho de Melo sz = sample->user_stack.size; 1470055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1471055c67edSArnaldo Carvalho de Melo if (sz) { 1472055c67edSArnaldo Carvalho de Melo result += sz; 1473055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1474055c67edSArnaldo Carvalho de Melo } 1475055c67edSArnaldo Carvalho de Melo } 1476055c67edSArnaldo Carvalho de Melo 1477ea8d0ed6SKan Liang if (type & PERF_SAMPLE_WEIGHT_TYPE) 1478055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1479055c67edSArnaldo Carvalho de Melo 1480055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_DATA_SRC) 1481055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1482055c67edSArnaldo Carvalho de Melo 1483055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TRANSACTION) 1484055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1485055c67edSArnaldo Carvalho de Melo 1486055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_INTR) { 1487055c67edSArnaldo Carvalho de Melo if (sample->intr_regs.abi) { 1488055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1489055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 1490055c67edSArnaldo Carvalho de Melo result += sz; 1491055c67edSArnaldo Carvalho de Melo } else { 1492055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1493055c67edSArnaldo Carvalho de Melo } 1494055c67edSArnaldo Carvalho de Melo } 1495055c67edSArnaldo Carvalho de Melo 1496055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PHYS_ADDR) 1497055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1498055c67edSArnaldo Carvalho de Melo 1499ba78c1c5SNamhyung Kim if (type & PERF_SAMPLE_CGROUP) 1500ba78c1c5SNamhyung Kim result += sizeof(u64); 1501ba78c1c5SNamhyung Kim 1502542b88fdSKan Liang if (type & PERF_SAMPLE_DATA_PAGE_SIZE) 1503542b88fdSKan Liang result += sizeof(u64); 1504542b88fdSKan Liang 1505c1de7f3dSKan Liang if (type & PERF_SAMPLE_CODE_PAGE_SIZE) 1506c1de7f3dSKan Liang result += sizeof(u64); 1507c1de7f3dSKan Liang 150898dcf14dSAdrian Hunter if (type & PERF_SAMPLE_AUX) { 150998dcf14dSAdrian Hunter result += sizeof(u64); 151098dcf14dSAdrian Hunter result += sample->aux_sample.size; 151198dcf14dSAdrian Hunter } 151298dcf14dSAdrian Hunter 1513055c67edSArnaldo Carvalho de Melo return result; 1514055c67edSArnaldo Carvalho de Melo } 1515055c67edSArnaldo Carvalho de Melo 1516fbefe9c2SKan Liang void __weak arch_perf_synthesize_sample_weight(const struct perf_sample *data, 1517fbefe9c2SKan Liang __u64 *array, u64 type __maybe_unused) 1518fbefe9c2SKan Liang { 1519fbefe9c2SKan Liang *array = data->weight; 1520fbefe9c2SKan Liang } 1521fbefe9c2SKan Liang 1522*f52679b7SNamhyung Kim static __u64 *copy_read_group_values(__u64 *array, __u64 read_format, 1523*f52679b7SNamhyung Kim const struct perf_sample *sample) 1524*f52679b7SNamhyung Kim { 1525*f52679b7SNamhyung Kim size_t sz = sample_read_value_size(read_format); 1526*f52679b7SNamhyung Kim struct sample_read_value *v = sample->read.group.values; 1527*f52679b7SNamhyung Kim 1528*f52679b7SNamhyung Kim sample_read_group__for_each(v, sample->read.group.nr, read_format) { 1529*f52679b7SNamhyung Kim /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 1530*f52679b7SNamhyung Kim memcpy(array, v, sz); 1531*f52679b7SNamhyung Kim array = (void *)array + sz; 1532*f52679b7SNamhyung Kim } 1533*f52679b7SNamhyung Kim return array; 1534*f52679b7SNamhyung Kim } 1535*f52679b7SNamhyung Kim 1536055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format, 1537055c67edSArnaldo Carvalho de Melo const struct perf_sample *sample) 1538055c67edSArnaldo Carvalho de Melo { 1539055c67edSArnaldo Carvalho de Melo __u64 *array; 1540055c67edSArnaldo Carvalho de Melo size_t sz; 1541055c67edSArnaldo Carvalho de Melo /* 1542055c67edSArnaldo Carvalho de Melo * used for cross-endian analysis. See git commit 65014ab3 1543055c67edSArnaldo Carvalho de Melo * for why this goofiness is needed. 1544055c67edSArnaldo Carvalho de Melo */ 1545055c67edSArnaldo Carvalho de Melo union u64_swap u; 1546055c67edSArnaldo Carvalho de Melo 1547055c67edSArnaldo Carvalho de Melo array = event->sample.array; 1548055c67edSArnaldo Carvalho de Melo 1549055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IDENTIFIER) { 1550055c67edSArnaldo Carvalho de Melo *array = sample->id; 1551055c67edSArnaldo Carvalho de Melo array++; 1552055c67edSArnaldo Carvalho de Melo } 1553055c67edSArnaldo Carvalho de Melo 1554055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IP) { 1555055c67edSArnaldo Carvalho de Melo *array = sample->ip; 1556055c67edSArnaldo Carvalho de Melo array++; 1557055c67edSArnaldo Carvalho de Melo } 1558055c67edSArnaldo Carvalho de Melo 1559055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TID) { 1560055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->pid; 1561055c67edSArnaldo Carvalho de Melo u.val32[1] = sample->tid; 1562055c67edSArnaldo Carvalho de Melo *array = u.val64; 1563055c67edSArnaldo Carvalho de Melo array++; 1564055c67edSArnaldo Carvalho de Melo } 1565055c67edSArnaldo Carvalho de Melo 1566055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TIME) { 1567055c67edSArnaldo Carvalho de Melo *array = sample->time; 1568055c67edSArnaldo Carvalho de Melo array++; 1569055c67edSArnaldo Carvalho de Melo } 1570055c67edSArnaldo Carvalho de Melo 1571055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ADDR) { 1572055c67edSArnaldo Carvalho de Melo *array = sample->addr; 1573055c67edSArnaldo Carvalho de Melo array++; 1574055c67edSArnaldo Carvalho de Melo } 1575055c67edSArnaldo Carvalho de Melo 1576055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ID) { 1577055c67edSArnaldo Carvalho de Melo *array = sample->id; 1578055c67edSArnaldo Carvalho de Melo array++; 1579055c67edSArnaldo Carvalho de Melo } 1580055c67edSArnaldo Carvalho de Melo 1581055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STREAM_ID) { 1582055c67edSArnaldo Carvalho de Melo *array = sample->stream_id; 1583055c67edSArnaldo Carvalho de Melo array++; 1584055c67edSArnaldo Carvalho de Melo } 1585055c67edSArnaldo Carvalho de Melo 1586055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CPU) { 1587055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->cpu; 1588055c67edSArnaldo Carvalho de Melo u.val32[1] = 0; 1589055c67edSArnaldo Carvalho de Melo *array = u.val64; 1590055c67edSArnaldo Carvalho de Melo array++; 1591055c67edSArnaldo Carvalho de Melo } 1592055c67edSArnaldo Carvalho de Melo 1593055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PERIOD) { 1594055c67edSArnaldo Carvalho de Melo *array = sample->period; 1595055c67edSArnaldo Carvalho de Melo array++; 1596055c67edSArnaldo Carvalho de Melo } 1597055c67edSArnaldo Carvalho de Melo 1598055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_READ) { 1599055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) 1600055c67edSArnaldo Carvalho de Melo *array = sample->read.group.nr; 1601055c67edSArnaldo Carvalho de Melo else 1602055c67edSArnaldo Carvalho de Melo *array = sample->read.one.value; 1603055c67edSArnaldo Carvalho de Melo array++; 1604055c67edSArnaldo Carvalho de Melo 1605055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { 1606055c67edSArnaldo Carvalho de Melo *array = sample->read.time_enabled; 1607055c67edSArnaldo Carvalho de Melo array++; 1608055c67edSArnaldo Carvalho de Melo } 1609055c67edSArnaldo Carvalho de Melo 1610055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { 1611055c67edSArnaldo Carvalho de Melo *array = sample->read.time_running; 1612055c67edSArnaldo Carvalho de Melo array++; 1613055c67edSArnaldo Carvalho de Melo } 1614055c67edSArnaldo Carvalho de Melo 1615055c67edSArnaldo Carvalho de Melo /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 1616055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) { 1617*f52679b7SNamhyung Kim array = copy_read_group_values(array, read_format, 1618*f52679b7SNamhyung Kim sample); 1619055c67edSArnaldo Carvalho de Melo } else { 1620055c67edSArnaldo Carvalho de Melo *array = sample->read.one.id; 1621055c67edSArnaldo Carvalho de Melo array++; 1622*f52679b7SNamhyung Kim 1623*f52679b7SNamhyung Kim if (read_format & PERF_FORMAT_LOST) { 1624*f52679b7SNamhyung Kim *array = sample->read.one.lost; 1625*f52679b7SNamhyung Kim array++; 1626*f52679b7SNamhyung Kim } 1627055c67edSArnaldo Carvalho de Melo } 1628055c67edSArnaldo Carvalho de Melo } 1629055c67edSArnaldo Carvalho de Melo 1630055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CALLCHAIN) { 1631055c67edSArnaldo Carvalho de Melo sz = (sample->callchain->nr + 1) * sizeof(u64); 1632055c67edSArnaldo Carvalho de Melo memcpy(array, sample->callchain, sz); 1633055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1634055c67edSArnaldo Carvalho de Melo } 1635055c67edSArnaldo Carvalho de Melo 1636055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_RAW) { 1637055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->raw_size; 1638055c67edSArnaldo Carvalho de Melo *array = u.val64; 1639055c67edSArnaldo Carvalho de Melo array = (void *)array + sizeof(u32); 1640055c67edSArnaldo Carvalho de Melo 1641055c67edSArnaldo Carvalho de Melo memcpy(array, sample->raw_data, sample->raw_size); 1642055c67edSArnaldo Carvalho de Melo array = (void *)array + sample->raw_size; 1643055c67edSArnaldo Carvalho de Melo } 1644055c67edSArnaldo Carvalho de Melo 1645055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_BRANCH_STACK) { 1646055c67edSArnaldo Carvalho de Melo sz = sample->branch_stack->nr * sizeof(struct branch_entry); 164742bbabedSKan Liang /* nr, hw_idx */ 164842bbabedSKan Liang sz += 2 * sizeof(u64); 1649055c67edSArnaldo Carvalho de Melo memcpy(array, sample->branch_stack, sz); 1650055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1651055c67edSArnaldo Carvalho de Melo } 1652055c67edSArnaldo Carvalho de Melo 1653055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_USER) { 1654055c67edSArnaldo Carvalho de Melo if (sample->user_regs.abi) { 1655055c67edSArnaldo Carvalho de Melo *array++ = sample->user_regs.abi; 1656055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->user_regs.mask) * sizeof(u64); 1657055c67edSArnaldo Carvalho de Melo memcpy(array, sample->user_regs.regs, sz); 1658055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1659055c67edSArnaldo Carvalho de Melo } else { 1660055c67edSArnaldo Carvalho de Melo *array++ = 0; 1661055c67edSArnaldo Carvalho de Melo } 1662055c67edSArnaldo Carvalho de Melo } 1663055c67edSArnaldo Carvalho de Melo 1664055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STACK_USER) { 1665055c67edSArnaldo Carvalho de Melo sz = sample->user_stack.size; 1666055c67edSArnaldo Carvalho de Melo *array++ = sz; 1667055c67edSArnaldo Carvalho de Melo if (sz) { 1668055c67edSArnaldo Carvalho de Melo memcpy(array, sample->user_stack.data, sz); 1669055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1670055c67edSArnaldo Carvalho de Melo *array++ = sz; 1671055c67edSArnaldo Carvalho de Melo } 1672055c67edSArnaldo Carvalho de Melo } 1673055c67edSArnaldo Carvalho de Melo 1674ea8d0ed6SKan Liang if (type & PERF_SAMPLE_WEIGHT_TYPE) { 1675fbefe9c2SKan Liang arch_perf_synthesize_sample_weight(sample, array, type); 1676055c67edSArnaldo Carvalho de Melo array++; 1677055c67edSArnaldo Carvalho de Melo } 1678055c67edSArnaldo Carvalho de Melo 1679055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_DATA_SRC) { 1680055c67edSArnaldo Carvalho de Melo *array = sample->data_src; 1681055c67edSArnaldo Carvalho de Melo array++; 1682055c67edSArnaldo Carvalho de Melo } 1683055c67edSArnaldo Carvalho de Melo 1684055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TRANSACTION) { 1685055c67edSArnaldo Carvalho de Melo *array = sample->transaction; 1686055c67edSArnaldo Carvalho de Melo array++; 1687055c67edSArnaldo Carvalho de Melo } 1688055c67edSArnaldo Carvalho de Melo 1689055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_INTR) { 1690055c67edSArnaldo Carvalho de Melo if (sample->intr_regs.abi) { 1691055c67edSArnaldo Carvalho de Melo *array++ = sample->intr_regs.abi; 1692055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 1693055c67edSArnaldo Carvalho de Melo memcpy(array, sample->intr_regs.regs, sz); 1694055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1695055c67edSArnaldo Carvalho de Melo } else { 1696055c67edSArnaldo Carvalho de Melo *array++ = 0; 1697055c67edSArnaldo Carvalho de Melo } 1698055c67edSArnaldo Carvalho de Melo } 1699055c67edSArnaldo Carvalho de Melo 1700055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PHYS_ADDR) { 1701055c67edSArnaldo Carvalho de Melo *array = sample->phys_addr; 1702055c67edSArnaldo Carvalho de Melo array++; 1703055c67edSArnaldo Carvalho de Melo } 1704055c67edSArnaldo Carvalho de Melo 1705ba78c1c5SNamhyung Kim if (type & PERF_SAMPLE_CGROUP) { 1706ba78c1c5SNamhyung Kim *array = sample->cgroup; 1707ba78c1c5SNamhyung Kim array++; 1708ba78c1c5SNamhyung Kim } 1709ba78c1c5SNamhyung Kim 1710542b88fdSKan Liang if (type & PERF_SAMPLE_DATA_PAGE_SIZE) { 1711542b88fdSKan Liang *array = sample->data_page_size; 1712542b88fdSKan Liang array++; 1713542b88fdSKan Liang } 1714542b88fdSKan Liang 1715c1de7f3dSKan Liang if (type & PERF_SAMPLE_CODE_PAGE_SIZE) { 1716c1de7f3dSKan Liang *array = sample->code_page_size; 1717c1de7f3dSKan Liang array++; 1718c1de7f3dSKan Liang } 1719c1de7f3dSKan Liang 172098dcf14dSAdrian Hunter if (type & PERF_SAMPLE_AUX) { 172198dcf14dSAdrian Hunter sz = sample->aux_sample.size; 172298dcf14dSAdrian Hunter *array++ = sz; 172398dcf14dSAdrian Hunter memcpy(array, sample->aux_sample.data, sz); 172498dcf14dSAdrian Hunter array = (void *)array + sz; 172598dcf14dSAdrian Hunter } 172698dcf14dSAdrian Hunter 1727055c67edSArnaldo Carvalho de Melo return 0; 1728055c67edSArnaldo Carvalho de Melo } 1729055c67edSArnaldo Carvalho de Melo 17301ee94463SAdrian Hunter int perf_event__synthesize_id_sample(__u64 *array, u64 type, const struct perf_sample *sample) 17311ee94463SAdrian Hunter { 17321ee94463SAdrian Hunter __u64 *start = array; 17331ee94463SAdrian Hunter 17341ee94463SAdrian Hunter /* 17351ee94463SAdrian Hunter * used for cross-endian analysis. See git commit 65014ab3 17361ee94463SAdrian Hunter * for why this goofiness is needed. 17371ee94463SAdrian Hunter */ 17381ee94463SAdrian Hunter union u64_swap u; 17391ee94463SAdrian Hunter 17401ee94463SAdrian Hunter if (type & PERF_SAMPLE_TID) { 17411ee94463SAdrian Hunter u.val32[0] = sample->pid; 17421ee94463SAdrian Hunter u.val32[1] = sample->tid; 17431ee94463SAdrian Hunter *array = u.val64; 17441ee94463SAdrian Hunter array++; 17451ee94463SAdrian Hunter } 17461ee94463SAdrian Hunter 17471ee94463SAdrian Hunter if (type & PERF_SAMPLE_TIME) { 17481ee94463SAdrian Hunter *array = sample->time; 17491ee94463SAdrian Hunter array++; 17501ee94463SAdrian Hunter } 17511ee94463SAdrian Hunter 17521ee94463SAdrian Hunter if (type & PERF_SAMPLE_ID) { 17531ee94463SAdrian Hunter *array = sample->id; 17541ee94463SAdrian Hunter array++; 17551ee94463SAdrian Hunter } 17561ee94463SAdrian Hunter 17571ee94463SAdrian Hunter if (type & PERF_SAMPLE_STREAM_ID) { 17581ee94463SAdrian Hunter *array = sample->stream_id; 17591ee94463SAdrian Hunter array++; 17601ee94463SAdrian Hunter } 17611ee94463SAdrian Hunter 17621ee94463SAdrian Hunter if (type & PERF_SAMPLE_CPU) { 17631ee94463SAdrian Hunter u.val32[0] = sample->cpu; 17641ee94463SAdrian Hunter u.val32[1] = 0; 17651ee94463SAdrian Hunter *array = u.val64; 17661ee94463SAdrian Hunter array++; 17671ee94463SAdrian Hunter } 17681ee94463SAdrian Hunter 17691ee94463SAdrian Hunter if (type & PERF_SAMPLE_IDENTIFIER) { 17701ee94463SAdrian Hunter *array = sample->id; 17711ee94463SAdrian Hunter array++; 17721ee94463SAdrian Hunter } 17731ee94463SAdrian Hunter 17741ee94463SAdrian Hunter return (void *)array - (void *)start; 17751ee94463SAdrian Hunter } 17761ee94463SAdrian Hunter 1777b47bb186SAdrian Hunter int __perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, 1778b47bb186SAdrian Hunter struct evlist *evlist, struct machine *machine, size_t from) 1779055c67edSArnaldo Carvalho de Melo { 1780055c67edSArnaldo Carvalho de Melo union perf_event *ev; 1781055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 1782b47bb186SAdrian Hunter size_t nr = 0, i = 0, sz, max_nr, n, pos; 1783b47bb186SAdrian Hunter size_t e1_sz = sizeof(struct id_index_entry); 1784b47bb186SAdrian Hunter size_t e2_sz = sizeof(struct id_index_entry_2); 1785b47bb186SAdrian Hunter size_t etot_sz = e1_sz + e2_sz; 1786b47bb186SAdrian Hunter bool e2_needed = false; 1787055c67edSArnaldo Carvalho de Melo int err; 1788055c67edSArnaldo Carvalho de Melo 1789b47bb186SAdrian Hunter max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / etot_sz; 1790055c67edSArnaldo Carvalho de Melo 1791b47bb186SAdrian Hunter pos = 0; 1792b47bb186SAdrian Hunter evlist__for_each_entry(evlist, evsel) { 1793b47bb186SAdrian Hunter if (pos++ < from) 1794b47bb186SAdrian Hunter continue; 1795e7eb9002SJiri Olsa nr += evsel->core.ids; 1796b47bb186SAdrian Hunter } 1797055c67edSArnaldo Carvalho de Melo 17986b080312SAdrian Hunter if (!nr) 17996b080312SAdrian Hunter return 0; 18006b080312SAdrian Hunter 18016b080312SAdrian Hunter pr_debug2("Synthesizing id index\n"); 18026b080312SAdrian Hunter 1803055c67edSArnaldo Carvalho de Melo n = nr > max_nr ? max_nr : nr; 1804b47bb186SAdrian Hunter sz = sizeof(struct perf_record_id_index) + n * etot_sz; 1805055c67edSArnaldo Carvalho de Melo ev = zalloc(sz); 1806055c67edSArnaldo Carvalho de Melo if (!ev) 1807055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1808055c67edSArnaldo Carvalho de Melo 1809b47bb186SAdrian Hunter sz = sizeof(struct perf_record_id_index) + n * e1_sz; 1810b47bb186SAdrian Hunter 1811055c67edSArnaldo Carvalho de Melo ev->id_index.header.type = PERF_RECORD_ID_INDEX; 1812055c67edSArnaldo Carvalho de Melo ev->id_index.nr = n; 1813055c67edSArnaldo Carvalho de Melo 1814b47bb186SAdrian Hunter pos = 0; 1815055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) { 1816055c67edSArnaldo Carvalho de Melo u32 j; 1817055c67edSArnaldo Carvalho de Melo 1818b47bb186SAdrian Hunter if (pos++ < from) 1819b47bb186SAdrian Hunter continue; 1820b47bb186SAdrian Hunter for (j = 0; j < evsel->core.ids; j++, i++) { 1821055c67edSArnaldo Carvalho de Melo struct id_index_entry *e; 1822b47bb186SAdrian Hunter struct id_index_entry_2 *e2; 1823055c67edSArnaldo Carvalho de Melo struct perf_sample_id *sid; 1824055c67edSArnaldo Carvalho de Melo 1825055c67edSArnaldo Carvalho de Melo if (i >= n) { 1826b47bb186SAdrian Hunter ev->id_index.header.size = sz + (e2_needed ? n * e2_sz : 0); 1827055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, machine); 1828055c67edSArnaldo Carvalho de Melo if (err) 1829055c67edSArnaldo Carvalho de Melo goto out_err; 1830055c67edSArnaldo Carvalho de Melo nr -= n; 1831055c67edSArnaldo Carvalho de Melo i = 0; 1832b47bb186SAdrian Hunter e2_needed = false; 1833055c67edSArnaldo Carvalho de Melo } 1834055c67edSArnaldo Carvalho de Melo 1835b47bb186SAdrian Hunter e = &ev->id_index.entries[i]; 1836055c67edSArnaldo Carvalho de Melo 1837deaf3219SJiri Olsa e->id = evsel->core.id[j]; 1838055c67edSArnaldo Carvalho de Melo 18393ccf8a7bSArnaldo Carvalho de Melo sid = evlist__id2sid(evlist, e->id); 1840055c67edSArnaldo Carvalho de Melo if (!sid) { 1841055c67edSArnaldo Carvalho de Melo free(ev); 1842055c67edSArnaldo Carvalho de Melo return -ENOENT; 1843055c67edSArnaldo Carvalho de Melo } 1844055c67edSArnaldo Carvalho de Melo 1845055c67edSArnaldo Carvalho de Melo e->idx = sid->idx; 18466d18804bSIan Rogers e->cpu = sid->cpu.cpu; 1847055c67edSArnaldo Carvalho de Melo e->tid = sid->tid; 1848b47bb186SAdrian Hunter 1849b47bb186SAdrian Hunter if (sid->machine_pid) 1850b47bb186SAdrian Hunter e2_needed = true; 1851b47bb186SAdrian Hunter 1852b47bb186SAdrian Hunter e2 = (void *)ev + sz; 1853b47bb186SAdrian Hunter e2[i].machine_pid = sid->machine_pid; 1854b47bb186SAdrian Hunter e2[i].vcpu = sid->vcpu.cpu; 1855055c67edSArnaldo Carvalho de Melo } 1856055c67edSArnaldo Carvalho de Melo } 1857055c67edSArnaldo Carvalho de Melo 1858b47bb186SAdrian Hunter sz = sizeof(struct perf_record_id_index) + nr * e1_sz; 1859b47bb186SAdrian Hunter ev->id_index.header.size = sz + (e2_needed ? nr * e2_sz : 0); 1860055c67edSArnaldo Carvalho de Melo ev->id_index.nr = nr; 1861055c67edSArnaldo Carvalho de Melo 1862055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, machine); 1863055c67edSArnaldo Carvalho de Melo out_err: 1864055c67edSArnaldo Carvalho de Melo free(ev); 1865055c67edSArnaldo Carvalho de Melo 1866055c67edSArnaldo Carvalho de Melo return err; 1867055c67edSArnaldo Carvalho de Melo } 1868055c67edSArnaldo Carvalho de Melo 1869b47bb186SAdrian Hunter int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, 1870b47bb186SAdrian Hunter struct evlist *evlist, struct machine *machine) 1871b47bb186SAdrian Hunter { 1872b47bb186SAdrian Hunter return __perf_event__synthesize_id_index(tool, process, evlist, machine, 0); 1873b47bb186SAdrian Hunter } 1874b47bb186SAdrian Hunter 1875055c67edSArnaldo Carvalho de Melo int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, 1876055c67edSArnaldo Carvalho de Melo struct target *target, struct perf_thread_map *threads, 187784111b9cSNamhyung Kim perf_event__handler_t process, bool needs_mmap, 187884111b9cSNamhyung Kim bool data_mmap, unsigned int nr_threads_synthesize) 1879055c67edSArnaldo Carvalho de Melo { 1880bc9c806eSLeo Yan /* 1881bc9c806eSLeo Yan * When perf runs in non-root PID namespace, and the namespace's proc FS 1882bc9c806eSLeo Yan * is not mounted, nsinfo__is_in_root_namespace() returns false. 1883bc9c806eSLeo Yan * In this case, the proc FS is coming for the parent namespace, thus 1884bc9c806eSLeo Yan * perf tool will wrongly gather process info from its parent PID 1885bc9c806eSLeo Yan * namespace. 1886bc9c806eSLeo Yan * 1887bc9c806eSLeo Yan * To avoid the confusion that the perf tool runs in a child PID 1888bc9c806eSLeo Yan * namespace but it synthesizes thread info from its parent PID 1889bc9c806eSLeo Yan * namespace, returns failure with warning. 1890bc9c806eSLeo Yan */ 1891bc9c806eSLeo Yan if (!nsinfo__is_in_root_namespace()) { 1892bc9c806eSLeo Yan pr_err("Perf runs in non-root PID namespace but it tries to "); 1893bc9c806eSLeo Yan pr_err("gather process info from its parent PID namespace.\n"); 1894bc9c806eSLeo Yan pr_err("Please mount the proc file system properly, e.g. "); 1895bc9c806eSLeo Yan pr_err("add the option '--mount-proc' for unshare command.\n"); 1896bc9c806eSLeo Yan return -EPERM; 1897bc9c806eSLeo Yan } 1898bc9c806eSLeo Yan 1899055c67edSArnaldo Carvalho de Melo if (target__has_task(target)) 190084111b9cSNamhyung Kim return perf_event__synthesize_thread_map(tool, threads, process, machine, 190184111b9cSNamhyung Kim needs_mmap, data_mmap); 1902055c67edSArnaldo Carvalho de Melo else if (target__has_cpu(target)) 190384111b9cSNamhyung Kim return perf_event__synthesize_threads(tool, process, machine, 190484111b9cSNamhyung Kim needs_mmap, data_mmap, 1905055c67edSArnaldo Carvalho de Melo nr_threads_synthesize); 1906055c67edSArnaldo Carvalho de Melo /* command specified */ 1907055c67edSArnaldo Carvalho de Melo return 0; 1908055c67edSArnaldo Carvalho de Melo } 1909055c67edSArnaldo Carvalho de Melo 1910055c67edSArnaldo Carvalho de Melo int machine__synthesize_threads(struct machine *machine, struct target *target, 191184111b9cSNamhyung Kim struct perf_thread_map *threads, bool needs_mmap, 191284111b9cSNamhyung Kim bool data_mmap, unsigned int nr_threads_synthesize) 1913055c67edSArnaldo Carvalho de Melo { 1914055c67edSArnaldo Carvalho de Melo return __machine__synthesize_threads(machine, NULL, target, threads, 191584111b9cSNamhyung Kim perf_event__process, needs_mmap, 191684111b9cSNamhyung Kim data_mmap, nr_threads_synthesize); 1917055c67edSArnaldo Carvalho de Melo } 1918055c67edSArnaldo Carvalho de Melo 1919055c67edSArnaldo Carvalho de Melo static struct perf_record_event_update *event_update_event__new(size_t size, u64 type, u64 id) 1920055c67edSArnaldo Carvalho de Melo { 1921055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1922055c67edSArnaldo Carvalho de Melo 1923055c67edSArnaldo Carvalho de Melo size += sizeof(*ev); 1924055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 1925055c67edSArnaldo Carvalho de Melo 1926055c67edSArnaldo Carvalho de Melo ev = zalloc(size); 1927055c67edSArnaldo Carvalho de Melo if (ev) { 1928055c67edSArnaldo Carvalho de Melo ev->header.type = PERF_RECORD_EVENT_UPDATE; 1929055c67edSArnaldo Carvalho de Melo ev->header.size = (u16)size; 1930055c67edSArnaldo Carvalho de Melo ev->type = type; 1931055c67edSArnaldo Carvalho de Melo ev->id = id; 1932055c67edSArnaldo Carvalho de Melo } 1933055c67edSArnaldo Carvalho de Melo return ev; 1934055c67edSArnaldo Carvalho de Melo } 1935055c67edSArnaldo Carvalho de Melo 1936055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_unit(struct perf_tool *tool, struct evsel *evsel, 1937055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1938055c67edSArnaldo Carvalho de Melo { 1939055c67edSArnaldo Carvalho de Melo size_t size = strlen(evsel->unit); 1940055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1941055c67edSArnaldo Carvalho de Melo int err; 1942055c67edSArnaldo Carvalho de Melo 1943deaf3219SJiri Olsa ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->core.id[0]); 1944055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1945055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1946055c67edSArnaldo Carvalho de Melo 1947055c67edSArnaldo Carvalho de Melo strlcpy(ev->data, evsel->unit, size + 1); 1948055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1949055c67edSArnaldo Carvalho de Melo free(ev); 1950055c67edSArnaldo Carvalho de Melo return err; 1951055c67edSArnaldo Carvalho de Melo } 1952055c67edSArnaldo Carvalho de Melo 1953055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_scale(struct perf_tool *tool, struct evsel *evsel, 1954055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1955055c67edSArnaldo Carvalho de Melo { 1956055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1957055c67edSArnaldo Carvalho de Melo struct perf_record_event_update_scale *ev_data; 1958055c67edSArnaldo Carvalho de Melo int err; 1959055c67edSArnaldo Carvalho de Melo 1960deaf3219SJiri Olsa ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->core.id[0]); 1961055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1962055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1963055c67edSArnaldo Carvalho de Melo 1964055c67edSArnaldo Carvalho de Melo ev_data = (struct perf_record_event_update_scale *)ev->data; 1965055c67edSArnaldo Carvalho de Melo ev_data->scale = evsel->scale; 1966055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1967055c67edSArnaldo Carvalho de Melo free(ev); 1968055c67edSArnaldo Carvalho de Melo return err; 1969055c67edSArnaldo Carvalho de Melo } 1970055c67edSArnaldo Carvalho de Melo 1971055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_name(struct perf_tool *tool, struct evsel *evsel, 1972055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1973055c67edSArnaldo Carvalho de Melo { 1974055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1975055c67edSArnaldo Carvalho de Melo size_t len = strlen(evsel->name); 1976055c67edSArnaldo Carvalho de Melo int err; 1977055c67edSArnaldo Carvalho de Melo 1978deaf3219SJiri Olsa ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->core.id[0]); 1979055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1980055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1981055c67edSArnaldo Carvalho de Melo 1982055c67edSArnaldo Carvalho de Melo strlcpy(ev->data, evsel->name, len + 1); 1983055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1984055c67edSArnaldo Carvalho de Melo free(ev); 1985055c67edSArnaldo Carvalho de Melo return err; 1986055c67edSArnaldo Carvalho de Melo } 1987055c67edSArnaldo Carvalho de Melo 1988055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, struct evsel *evsel, 1989055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1990055c67edSArnaldo Carvalho de Melo { 1991055c67edSArnaldo Carvalho de Melo size_t size = sizeof(struct perf_record_event_update); 1992055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1993055c67edSArnaldo Carvalho de Melo int max, err; 1994055c67edSArnaldo Carvalho de Melo u16 type; 1995055c67edSArnaldo Carvalho de Melo 1996055c67edSArnaldo Carvalho de Melo if (!evsel->core.own_cpus) 1997055c67edSArnaldo Carvalho de Melo return 0; 1998055c67edSArnaldo Carvalho de Melo 1999055c67edSArnaldo Carvalho de Melo ev = cpu_map_data__alloc(evsel->core.own_cpus, &size, &type, &max); 2000055c67edSArnaldo Carvalho de Melo if (!ev) 2001055c67edSArnaldo Carvalho de Melo return -ENOMEM; 2002055c67edSArnaldo Carvalho de Melo 2003055c67edSArnaldo Carvalho de Melo ev->header.type = PERF_RECORD_EVENT_UPDATE; 2004055c67edSArnaldo Carvalho de Melo ev->header.size = (u16)size; 2005055c67edSArnaldo Carvalho de Melo ev->type = PERF_EVENT_UPDATE__CPUS; 2006deaf3219SJiri Olsa ev->id = evsel->core.id[0]; 2007055c67edSArnaldo Carvalho de Melo 2008055c67edSArnaldo Carvalho de Melo cpu_map_data__synthesize((struct perf_record_cpu_map_data *)ev->data, 2009055c67edSArnaldo Carvalho de Melo evsel->core.own_cpus, type, max); 2010055c67edSArnaldo Carvalho de Melo 2011055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 2012055c67edSArnaldo Carvalho de Melo free(ev); 2013055c67edSArnaldo Carvalho de Melo return err; 2014055c67edSArnaldo Carvalho de Melo } 2015055c67edSArnaldo Carvalho de Melo 2016055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_attrs(struct perf_tool *tool, struct evlist *evlist, 2017055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 2018055c67edSArnaldo Carvalho de Melo { 2019055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 2020055c67edSArnaldo Carvalho de Melo int err = 0; 2021055c67edSArnaldo Carvalho de Melo 2022055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) { 2023e7eb9002SJiri Olsa err = perf_event__synthesize_attr(tool, &evsel->core.attr, evsel->core.ids, 2024deaf3219SJiri Olsa evsel->core.id, process); 2025055c67edSArnaldo Carvalho de Melo if (err) { 2026055c67edSArnaldo Carvalho de Melo pr_debug("failed to create perf header attribute\n"); 2027055c67edSArnaldo Carvalho de Melo return err; 2028055c67edSArnaldo Carvalho de Melo } 2029055c67edSArnaldo Carvalho de Melo } 2030055c67edSArnaldo Carvalho de Melo 2031055c67edSArnaldo Carvalho de Melo return err; 2032055c67edSArnaldo Carvalho de Melo } 2033055c67edSArnaldo Carvalho de Melo 2034055c67edSArnaldo Carvalho de Melo static bool has_unit(struct evsel *evsel) 2035055c67edSArnaldo Carvalho de Melo { 2036055c67edSArnaldo Carvalho de Melo return evsel->unit && *evsel->unit; 2037055c67edSArnaldo Carvalho de Melo } 2038055c67edSArnaldo Carvalho de Melo 2039055c67edSArnaldo Carvalho de Melo static bool has_scale(struct evsel *evsel) 2040055c67edSArnaldo Carvalho de Melo { 2041055c67edSArnaldo Carvalho de Melo return evsel->scale != 1; 2042055c67edSArnaldo Carvalho de Melo } 2043055c67edSArnaldo Carvalho de Melo 2044055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_extra_attr(struct perf_tool *tool, struct evlist *evsel_list, 2045055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, bool is_pipe) 2046055c67edSArnaldo Carvalho de Melo { 2047055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 2048055c67edSArnaldo Carvalho de Melo int err; 2049055c67edSArnaldo Carvalho de Melo 2050055c67edSArnaldo Carvalho de Melo /* 2051055c67edSArnaldo Carvalho de Melo * Synthesize other events stuff not carried within 2052055c67edSArnaldo Carvalho de Melo * attr event - unit, scale, name 2053055c67edSArnaldo Carvalho de Melo */ 2054055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evsel_list, evsel) { 2055055c67edSArnaldo Carvalho de Melo if (!evsel->supported) 2056055c67edSArnaldo Carvalho de Melo continue; 2057055c67edSArnaldo Carvalho de Melo 2058055c67edSArnaldo Carvalho de Melo /* 2059055c67edSArnaldo Carvalho de Melo * Synthesize unit and scale only if it's defined. 2060055c67edSArnaldo Carvalho de Melo */ 2061055c67edSArnaldo Carvalho de Melo if (has_unit(evsel)) { 2062055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_unit(tool, evsel, process); 2063055c67edSArnaldo Carvalho de Melo if (err < 0) { 2064055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel unit.\n"); 2065055c67edSArnaldo Carvalho de Melo return err; 2066055c67edSArnaldo Carvalho de Melo } 2067055c67edSArnaldo Carvalho de Melo } 2068055c67edSArnaldo Carvalho de Melo 2069055c67edSArnaldo Carvalho de Melo if (has_scale(evsel)) { 2070055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_scale(tool, evsel, process); 2071055c67edSArnaldo Carvalho de Melo if (err < 0) { 2072055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel evsel.\n"); 2073055c67edSArnaldo Carvalho de Melo return err; 2074055c67edSArnaldo Carvalho de Melo } 2075055c67edSArnaldo Carvalho de Melo } 2076055c67edSArnaldo Carvalho de Melo 2077055c67edSArnaldo Carvalho de Melo if (evsel->core.own_cpus) { 2078055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_cpus(tool, evsel, process); 2079055c67edSArnaldo Carvalho de Melo if (err < 0) { 2080055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel cpus.\n"); 2081055c67edSArnaldo Carvalho de Melo return err; 2082055c67edSArnaldo Carvalho de Melo } 2083055c67edSArnaldo Carvalho de Melo } 2084055c67edSArnaldo Carvalho de Melo 2085055c67edSArnaldo Carvalho de Melo /* 2086055c67edSArnaldo Carvalho de Melo * Name is needed only for pipe output, 2087055c67edSArnaldo Carvalho de Melo * perf.data carries event names. 2088055c67edSArnaldo Carvalho de Melo */ 2089055c67edSArnaldo Carvalho de Melo if (is_pipe) { 2090055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_name(tool, evsel, process); 2091055c67edSArnaldo Carvalho de Melo if (err < 0) { 2092055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel name.\n"); 2093055c67edSArnaldo Carvalho de Melo return err; 2094055c67edSArnaldo Carvalho de Melo } 2095055c67edSArnaldo Carvalho de Melo } 2096055c67edSArnaldo Carvalho de Melo } 2097055c67edSArnaldo Carvalho de Melo return 0; 2098055c67edSArnaldo Carvalho de Melo } 2099055c67edSArnaldo Carvalho de Melo 2100055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, 2101055c67edSArnaldo Carvalho de Melo u32 ids, u64 *id, perf_event__handler_t process) 2102055c67edSArnaldo Carvalho de Melo { 2103055c67edSArnaldo Carvalho de Melo union perf_event *ev; 2104055c67edSArnaldo Carvalho de Melo size_t size; 2105055c67edSArnaldo Carvalho de Melo int err; 2106055c67edSArnaldo Carvalho de Melo 2107055c67edSArnaldo Carvalho de Melo size = sizeof(struct perf_event_attr); 2108055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 2109055c67edSArnaldo Carvalho de Melo size += sizeof(struct perf_event_header); 2110055c67edSArnaldo Carvalho de Melo size += ids * sizeof(u64); 2111055c67edSArnaldo Carvalho de Melo 2112055c67edSArnaldo Carvalho de Melo ev = zalloc(size); 2113055c67edSArnaldo Carvalho de Melo 2114055c67edSArnaldo Carvalho de Melo if (ev == NULL) 2115055c67edSArnaldo Carvalho de Melo return -ENOMEM; 2116055c67edSArnaldo Carvalho de Melo 2117055c67edSArnaldo Carvalho de Melo ev->attr.attr = *attr; 2118055c67edSArnaldo Carvalho de Melo memcpy(ev->attr.id, id, ids * sizeof(u64)); 2119055c67edSArnaldo Carvalho de Melo 2120055c67edSArnaldo Carvalho de Melo ev->attr.header.type = PERF_RECORD_HEADER_ATTR; 2121055c67edSArnaldo Carvalho de Melo ev->attr.header.size = (u16)size; 2122055c67edSArnaldo Carvalho de Melo 2123055c67edSArnaldo Carvalho de Melo if (ev->attr.header.size == size) 2124055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, NULL); 2125055c67edSArnaldo Carvalho de Melo else 2126055c67edSArnaldo Carvalho de Melo err = -E2BIG; 2127055c67edSArnaldo Carvalho de Melo 2128055c67edSArnaldo Carvalho de Melo free(ev); 2129055c67edSArnaldo Carvalho de Melo 2130055c67edSArnaldo Carvalho de Melo return err; 2131055c67edSArnaldo Carvalho de Melo } 2132055c67edSArnaldo Carvalho de Melo 2133055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct evlist *evlist, 2134055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 2135055c67edSArnaldo Carvalho de Melo { 2136055c67edSArnaldo Carvalho de Melo union perf_event ev; 2137055c67edSArnaldo Carvalho de Melo struct tracing_data *tdata; 2138055c67edSArnaldo Carvalho de Melo ssize_t size = 0, aligned_size = 0, padding; 2139055c67edSArnaldo Carvalho de Melo struct feat_fd ff; 2140055c67edSArnaldo Carvalho de Melo 2141055c67edSArnaldo Carvalho de Melo /* 2142055c67edSArnaldo Carvalho de Melo * We are going to store the size of the data followed 2143055c67edSArnaldo Carvalho de Melo * by the data contents. Since the fd descriptor is a pipe, 2144055c67edSArnaldo Carvalho de Melo * we cannot seek back to store the size of the data once 2145055c67edSArnaldo Carvalho de Melo * we know it. Instead we: 2146055c67edSArnaldo Carvalho de Melo * 2147055c67edSArnaldo Carvalho de Melo * - write the tracing data to the temp file 2148055c67edSArnaldo Carvalho de Melo * - get/write the data size to pipe 2149055c67edSArnaldo Carvalho de Melo * - write the tracing data from the temp file 2150055c67edSArnaldo Carvalho de Melo * to the pipe 2151055c67edSArnaldo Carvalho de Melo */ 2152055c67edSArnaldo Carvalho de Melo tdata = tracing_data_get(&evlist->core.entries, fd, true); 2153055c67edSArnaldo Carvalho de Melo if (!tdata) 2154055c67edSArnaldo Carvalho de Melo return -1; 2155055c67edSArnaldo Carvalho de Melo 2156055c67edSArnaldo Carvalho de Melo memset(&ev, 0, sizeof(ev)); 2157055c67edSArnaldo Carvalho de Melo 2158055c67edSArnaldo Carvalho de Melo ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 2159055c67edSArnaldo Carvalho de Melo size = tdata->size; 2160055c67edSArnaldo Carvalho de Melo aligned_size = PERF_ALIGN(size, sizeof(u64)); 2161055c67edSArnaldo Carvalho de Melo padding = aligned_size - size; 2162055c67edSArnaldo Carvalho de Melo ev.tracing_data.header.size = sizeof(ev.tracing_data); 2163055c67edSArnaldo Carvalho de Melo ev.tracing_data.size = aligned_size; 2164055c67edSArnaldo Carvalho de Melo 2165055c67edSArnaldo Carvalho de Melo process(tool, &ev, NULL, NULL); 2166055c67edSArnaldo Carvalho de Melo 2167055c67edSArnaldo Carvalho de Melo /* 2168055c67edSArnaldo Carvalho de Melo * The put function will copy all the tracing data 2169055c67edSArnaldo Carvalho de Melo * stored in temp file to the pipe. 2170055c67edSArnaldo Carvalho de Melo */ 2171055c67edSArnaldo Carvalho de Melo tracing_data_put(tdata); 2172055c67edSArnaldo Carvalho de Melo 2173055c67edSArnaldo Carvalho de Melo ff = (struct feat_fd){ .fd = fd }; 2174055c67edSArnaldo Carvalho de Melo if (write_padded(&ff, NULL, 0, padding)) 2175055c67edSArnaldo Carvalho de Melo return -1; 2176055c67edSArnaldo Carvalho de Melo 2177055c67edSArnaldo Carvalho de Melo return aligned_size; 2178055c67edSArnaldo Carvalho de Melo } 2179055c67edSArnaldo Carvalho de Melo 2180055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_build_id(struct perf_tool *tool, struct dso *pos, u16 misc, 2181055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, struct machine *machine) 2182055c67edSArnaldo Carvalho de Melo { 2183055c67edSArnaldo Carvalho de Melo union perf_event ev; 2184055c67edSArnaldo Carvalho de Melo size_t len; 2185055c67edSArnaldo Carvalho de Melo 2186055c67edSArnaldo Carvalho de Melo if (!pos->hit) 2187055c67edSArnaldo Carvalho de Melo return 0; 2188055c67edSArnaldo Carvalho de Melo 2189055c67edSArnaldo Carvalho de Melo memset(&ev, 0, sizeof(ev)); 2190055c67edSArnaldo Carvalho de Melo 2191055c67edSArnaldo Carvalho de Melo len = pos->long_name_len + 1; 2192055c67edSArnaldo Carvalho de Melo len = PERF_ALIGN(len, NAME_ALIGN); 21930aba7f03SJiri Olsa memcpy(&ev.build_id.build_id, pos->bid.data, sizeof(pos->bid.data)); 2194055c67edSArnaldo Carvalho de Melo ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; 2195055c67edSArnaldo Carvalho de Melo ev.build_id.header.misc = misc; 2196055c67edSArnaldo Carvalho de Melo ev.build_id.pid = machine->pid; 2197055c67edSArnaldo Carvalho de Melo ev.build_id.header.size = sizeof(ev.build_id) + len; 2198055c67edSArnaldo Carvalho de Melo memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); 2199055c67edSArnaldo Carvalho de Melo 2200055c67edSArnaldo Carvalho de Melo return process(tool, &ev, NULL, machine); 2201055c67edSArnaldo Carvalho de Melo } 2202055c67edSArnaldo Carvalho de Melo 2203055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_events(struct perf_stat_config *config, struct perf_tool *tool, 2204055c67edSArnaldo Carvalho de Melo struct evlist *evlist, perf_event__handler_t process, bool attrs) 2205055c67edSArnaldo Carvalho de Melo { 2206055c67edSArnaldo Carvalho de Melo int err; 2207055c67edSArnaldo Carvalho de Melo 2208055c67edSArnaldo Carvalho de Melo if (attrs) { 2209055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_attrs(tool, evlist, process); 2210055c67edSArnaldo Carvalho de Melo if (err < 0) { 2211055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize attrs.\n"); 2212055c67edSArnaldo Carvalho de Melo return err; 2213055c67edSArnaldo Carvalho de Melo } 2214055c67edSArnaldo Carvalho de Melo } 2215055c67edSArnaldo Carvalho de Melo 2216055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_extra_attr(tool, evlist, process, attrs); 2217055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_thread_map2(tool, evlist->core.threads, process, NULL); 2218055c67edSArnaldo Carvalho de Melo if (err < 0) { 2219055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize thread map.\n"); 2220055c67edSArnaldo Carvalho de Melo return err; 2221055c67edSArnaldo Carvalho de Melo } 2222055c67edSArnaldo Carvalho de Melo 22230df6ade7SIan Rogers err = perf_event__synthesize_cpu_map(tool, evlist->core.user_requested_cpus, process, NULL); 2224055c67edSArnaldo Carvalho de Melo if (err < 0) { 2225055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize thread map.\n"); 2226055c67edSArnaldo Carvalho de Melo return err; 2227055c67edSArnaldo Carvalho de Melo } 2228055c67edSArnaldo Carvalho de Melo 2229055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_stat_config(tool, config, process, NULL); 2230055c67edSArnaldo Carvalho de Melo if (err < 0) { 2231055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize config.\n"); 2232055c67edSArnaldo Carvalho de Melo return err; 2233055c67edSArnaldo Carvalho de Melo } 2234055c67edSArnaldo Carvalho de Melo 2235055c67edSArnaldo Carvalho de Melo return 0; 2236055c67edSArnaldo Carvalho de Melo } 2237055c67edSArnaldo Carvalho de Melo 2238055c67edSArnaldo Carvalho de Melo extern const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE]; 2239055c67edSArnaldo Carvalho de Melo 2240055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, 2241055c67edSArnaldo Carvalho de Melo struct evlist *evlist, perf_event__handler_t process) 2242055c67edSArnaldo Carvalho de Melo { 2243055c67edSArnaldo Carvalho de Melo struct perf_header *header = &session->header; 2244055c67edSArnaldo Carvalho de Melo struct perf_record_header_feature *fe; 2245055c67edSArnaldo Carvalho de Melo struct feat_fd ff; 2246055c67edSArnaldo Carvalho de Melo size_t sz, sz_hdr; 2247055c67edSArnaldo Carvalho de Melo int feat, ret; 2248055c67edSArnaldo Carvalho de Melo 2249055c67edSArnaldo Carvalho de Melo sz_hdr = sizeof(fe->header); 2250055c67edSArnaldo Carvalho de Melo sz = sizeof(union perf_event); 2251055c67edSArnaldo Carvalho de Melo /* get a nice alignment */ 2252055c67edSArnaldo Carvalho de Melo sz = PERF_ALIGN(sz, page_size); 2253055c67edSArnaldo Carvalho de Melo 2254055c67edSArnaldo Carvalho de Melo memset(&ff, 0, sizeof(ff)); 2255055c67edSArnaldo Carvalho de Melo 2256055c67edSArnaldo Carvalho de Melo ff.buf = malloc(sz); 2257055c67edSArnaldo Carvalho de Melo if (!ff.buf) 2258055c67edSArnaldo Carvalho de Melo return -ENOMEM; 2259055c67edSArnaldo Carvalho de Melo 2260055c67edSArnaldo Carvalho de Melo ff.size = sz - sz_hdr; 2261055c67edSArnaldo Carvalho de Melo ff.ph = &session->header; 2262055c67edSArnaldo Carvalho de Melo 2263055c67edSArnaldo Carvalho de Melo for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { 2264055c67edSArnaldo Carvalho de Melo if (!feat_ops[feat].synthesize) { 2265055c67edSArnaldo Carvalho de Melo pr_debug("No record header feature for header :%d\n", feat); 2266055c67edSArnaldo Carvalho de Melo continue; 2267055c67edSArnaldo Carvalho de Melo } 2268055c67edSArnaldo Carvalho de Melo 2269055c67edSArnaldo Carvalho de Melo ff.offset = sizeof(*fe); 2270055c67edSArnaldo Carvalho de Melo 2271055c67edSArnaldo Carvalho de Melo ret = feat_ops[feat].write(&ff, evlist); 2272055c67edSArnaldo Carvalho de Melo if (ret || ff.offset <= (ssize_t)sizeof(*fe)) { 2273055c67edSArnaldo Carvalho de Melo pr_debug("Error writing feature\n"); 2274055c67edSArnaldo Carvalho de Melo continue; 2275055c67edSArnaldo Carvalho de Melo } 2276055c67edSArnaldo Carvalho de Melo /* ff.buf may have changed due to realloc in do_write() */ 2277055c67edSArnaldo Carvalho de Melo fe = ff.buf; 2278055c67edSArnaldo Carvalho de Melo memset(fe, 0, sizeof(*fe)); 2279055c67edSArnaldo Carvalho de Melo 2280055c67edSArnaldo Carvalho de Melo fe->feat_id = feat; 2281055c67edSArnaldo Carvalho de Melo fe->header.type = PERF_RECORD_HEADER_FEATURE; 2282055c67edSArnaldo Carvalho de Melo fe->header.size = ff.offset; 2283055c67edSArnaldo Carvalho de Melo 2284055c67edSArnaldo Carvalho de Melo ret = process(tool, ff.buf, NULL, NULL); 2285055c67edSArnaldo Carvalho de Melo if (ret) { 2286055c67edSArnaldo Carvalho de Melo free(ff.buf); 2287055c67edSArnaldo Carvalho de Melo return ret; 2288055c67edSArnaldo Carvalho de Melo } 2289055c67edSArnaldo Carvalho de Melo } 2290055c67edSArnaldo Carvalho de Melo 2291055c67edSArnaldo Carvalho de Melo /* Send HEADER_LAST_FEATURE mark. */ 2292055c67edSArnaldo Carvalho de Melo fe = ff.buf; 2293055c67edSArnaldo Carvalho de Melo fe->feat_id = HEADER_LAST_FEATURE; 2294055c67edSArnaldo Carvalho de Melo fe->header.type = PERF_RECORD_HEADER_FEATURE; 2295055c67edSArnaldo Carvalho de Melo fe->header.size = sizeof(*fe); 2296055c67edSArnaldo Carvalho de Melo 2297055c67edSArnaldo Carvalho de Melo ret = process(tool, ff.buf, NULL, NULL); 2298055c67edSArnaldo Carvalho de Melo 2299055c67edSArnaldo Carvalho de Melo free(ff.buf); 2300055c67edSArnaldo Carvalho de Melo return ret; 2301055c67edSArnaldo Carvalho de Melo } 2302c3a057dcSNamhyung Kim 2303c3a057dcSNamhyung Kim int perf_event__synthesize_for_pipe(struct perf_tool *tool, 2304c3a057dcSNamhyung Kim struct perf_session *session, 2305c3a057dcSNamhyung Kim struct perf_data *data, 2306c3a057dcSNamhyung Kim perf_event__handler_t process) 2307c3a057dcSNamhyung Kim { 2308c3a057dcSNamhyung Kim int err; 2309c3a057dcSNamhyung Kim int ret = 0; 2310c3a057dcSNamhyung Kim struct evlist *evlist = session->evlist; 2311c3a057dcSNamhyung Kim 2312c3a057dcSNamhyung Kim /* 2313c3a057dcSNamhyung Kim * We need to synthesize events first, because some 2314c3a057dcSNamhyung Kim * features works on top of them (on report side). 2315c3a057dcSNamhyung Kim */ 2316c3a057dcSNamhyung Kim err = perf_event__synthesize_attrs(tool, evlist, process); 2317c3a057dcSNamhyung Kim if (err < 0) { 2318c3a057dcSNamhyung Kim pr_err("Couldn't synthesize attrs.\n"); 2319c3a057dcSNamhyung Kim return err; 2320c3a057dcSNamhyung Kim } 2321c3a057dcSNamhyung Kim ret += err; 2322c3a057dcSNamhyung Kim 2323c3a057dcSNamhyung Kim err = perf_event__synthesize_features(tool, session, evlist, process); 2324c3a057dcSNamhyung Kim if (err < 0) { 2325c3a057dcSNamhyung Kim pr_err("Couldn't synthesize features.\n"); 2326c3a057dcSNamhyung Kim return err; 2327c3a057dcSNamhyung Kim } 2328c3a057dcSNamhyung Kim ret += err; 2329c3a057dcSNamhyung Kim 2330c3a057dcSNamhyung Kim if (have_tracepoints(&evlist->core.entries)) { 2331c3a057dcSNamhyung Kim int fd = perf_data__fd(data); 2332c3a057dcSNamhyung Kim 2333c3a057dcSNamhyung Kim /* 2334c3a057dcSNamhyung Kim * FIXME err <= 0 here actually means that 2335c3a057dcSNamhyung Kim * there were no tracepoints so its not really 2336c3a057dcSNamhyung Kim * an error, just that we don't need to 2337c3a057dcSNamhyung Kim * synthesize anything. We really have to 2338c3a057dcSNamhyung Kim * return this more properly and also 2339c3a057dcSNamhyung Kim * propagate errors that now are calling die() 2340c3a057dcSNamhyung Kim */ 2341c3a057dcSNamhyung Kim err = perf_event__synthesize_tracing_data(tool, fd, evlist, 2342c3a057dcSNamhyung Kim process); 2343c3a057dcSNamhyung Kim if (err <= 0) { 2344c3a057dcSNamhyung Kim pr_err("Couldn't record tracing data.\n"); 2345c3a057dcSNamhyung Kim return err; 2346c3a057dcSNamhyung Kim } 2347c3a057dcSNamhyung Kim ret += err; 2348c3a057dcSNamhyung Kim } 2349c3a057dcSNamhyung Kim 2350c3a057dcSNamhyung Kim return ret; 2351c3a057dcSNamhyung Kim } 235241b740b6SNamhyung Kim 235341b740b6SNamhyung Kim int parse_synth_opt(char *synth) 235441b740b6SNamhyung Kim { 235541b740b6SNamhyung Kim char *p, *q; 235641b740b6SNamhyung Kim int ret = 0; 235741b740b6SNamhyung Kim 235841b740b6SNamhyung Kim if (synth == NULL) 235941b740b6SNamhyung Kim return -1; 236041b740b6SNamhyung Kim 236141b740b6SNamhyung Kim for (q = synth; (p = strsep(&q, ",")); p = q) { 236241b740b6SNamhyung Kim if (!strcasecmp(p, "no") || !strcasecmp(p, "none")) 236341b740b6SNamhyung Kim return 0; 236441b740b6SNamhyung Kim 236541b740b6SNamhyung Kim if (!strcasecmp(p, "all")) 236641b740b6SNamhyung Kim return PERF_SYNTH_ALL; 236741b740b6SNamhyung Kim 236841b740b6SNamhyung Kim if (!strcasecmp(p, "task")) 236941b740b6SNamhyung Kim ret |= PERF_SYNTH_TASK; 237041b740b6SNamhyung Kim else if (!strcasecmp(p, "mmap")) 237141b740b6SNamhyung Kim ret |= PERF_SYNTH_TASK | PERF_SYNTH_MMAP; 237241b740b6SNamhyung Kim else if (!strcasecmp(p, "cgroup")) 237341b740b6SNamhyung Kim ret |= PERF_SYNTH_CGROUP; 237441b740b6SNamhyung Kim else 237541b740b6SNamhyung Kim return -1; 237641b740b6SNamhyung Kim } 237741b740b6SNamhyung Kim 237841b740b6SNamhyung Kim return ret; 237941b740b6SNamhyung Kim } 2380