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 757473f742eSNamhyung Kim n = scandir(filename, &dirent, filter_task, alphasort); 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 770055c67edSArnaldo Carvalho de Melo rc = -1; 77130626e08SNamhyung Kim if (perf_event__prepare_comm(comm_event, pid, _pid, machine, 772c1b90795SNamhyung Kim &tgid, &ppid, &kernel_thread) != 0) 773055c67edSArnaldo Carvalho de Melo break; 774055c67edSArnaldo Carvalho de Melo 775055c67edSArnaldo Carvalho de Melo if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid, 776055c67edSArnaldo Carvalho de Melo ppid, process, machine) < 0) 777055c67edSArnaldo Carvalho de Melo break; 778055c67edSArnaldo Carvalho de Melo 779055c67edSArnaldo Carvalho de Melo if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid, 780055c67edSArnaldo Carvalho de Melo tgid, process, machine) < 0) 781055c67edSArnaldo Carvalho de Melo break; 782055c67edSArnaldo Carvalho de Melo 783055c67edSArnaldo Carvalho de Melo /* 784055c67edSArnaldo Carvalho de Melo * Send the prepared comm event 785055c67edSArnaldo Carvalho de Melo */ 786055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, comm_event, machine, process) != 0) 787055c67edSArnaldo Carvalho de Melo break; 788055c67edSArnaldo Carvalho de Melo 789055c67edSArnaldo Carvalho de Melo rc = 0; 79084111b9cSNamhyung Kim if (_pid == pid && !kernel_thread && needs_mmap) { 791055c67edSArnaldo Carvalho de Melo /* process the parent's maps too */ 792055c67edSArnaldo Carvalho de Melo rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 793055c67edSArnaldo Carvalho de Melo process, machine, mmap_data); 794055c67edSArnaldo Carvalho de Melo if (rc) 795055c67edSArnaldo Carvalho de Melo break; 796055c67edSArnaldo Carvalho de Melo } 797055c67edSArnaldo Carvalho de Melo } 798055c67edSArnaldo Carvalho de Melo 799473f742eSNamhyung Kim for (i = 0; i < n; i++) 800473f742eSNamhyung Kim zfree(&dirent[i]); 801473f742eSNamhyung Kim free(dirent); 802473f742eSNamhyung Kim 803055c67edSArnaldo Carvalho de Melo return rc; 804055c67edSArnaldo Carvalho de Melo } 805055c67edSArnaldo Carvalho de Melo 806055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_thread_map(struct perf_tool *tool, 807055c67edSArnaldo Carvalho de Melo struct perf_thread_map *threads, 808055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 809055c67edSArnaldo Carvalho de Melo struct machine *machine, 81084111b9cSNamhyung Kim bool needs_mmap, bool mmap_data) 811055c67edSArnaldo Carvalho de Melo { 812055c67edSArnaldo Carvalho de Melo union perf_event *comm_event, *mmap_event, *fork_event; 813055c67edSArnaldo Carvalho de Melo union perf_event *namespaces_event; 814055c67edSArnaldo Carvalho de Melo int err = -1, thread, j; 815055c67edSArnaldo Carvalho de Melo 816055c67edSArnaldo Carvalho de Melo comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 817055c67edSArnaldo Carvalho de Melo if (comm_event == NULL) 818055c67edSArnaldo Carvalho de Melo goto out; 819055c67edSArnaldo Carvalho de Melo 820055c67edSArnaldo Carvalho de Melo mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); 821055c67edSArnaldo Carvalho de Melo if (mmap_event == NULL) 822055c67edSArnaldo Carvalho de Melo goto out_free_comm; 823055c67edSArnaldo Carvalho de Melo 824055c67edSArnaldo Carvalho de Melo fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); 825055c67edSArnaldo Carvalho de Melo if (fork_event == NULL) 826055c67edSArnaldo Carvalho de Melo goto out_free_mmap; 827055c67edSArnaldo Carvalho de Melo 828055c67edSArnaldo Carvalho de Melo namespaces_event = malloc(sizeof(namespaces_event->namespaces) + 829055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 830055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 831055c67edSArnaldo Carvalho de Melo if (namespaces_event == NULL) 832055c67edSArnaldo Carvalho de Melo goto out_free_fork; 833055c67edSArnaldo Carvalho de Melo 834055c67edSArnaldo Carvalho de Melo err = 0; 835055c67edSArnaldo Carvalho de Melo for (thread = 0; thread < threads->nr; ++thread) { 836055c67edSArnaldo Carvalho de Melo if (__event__synthesize_thread(comm_event, mmap_event, 837055c67edSArnaldo Carvalho de Melo fork_event, namespaces_event, 838055c67edSArnaldo Carvalho de Melo perf_thread_map__pid(threads, thread), 0, 839055c67edSArnaldo Carvalho de Melo process, tool, machine, 84084111b9cSNamhyung Kim needs_mmap, mmap_data)) { 841055c67edSArnaldo Carvalho de Melo err = -1; 842055c67edSArnaldo Carvalho de Melo break; 843055c67edSArnaldo Carvalho de Melo } 844055c67edSArnaldo Carvalho de Melo 845055c67edSArnaldo Carvalho de Melo /* 846055c67edSArnaldo Carvalho de Melo * comm.pid is set to thread group id by 847055c67edSArnaldo Carvalho de Melo * perf_event__synthesize_comm 848055c67edSArnaldo Carvalho de Melo */ 849055c67edSArnaldo Carvalho de Melo if ((int) comm_event->comm.pid != perf_thread_map__pid(threads, thread)) { 850055c67edSArnaldo Carvalho de Melo bool need_leader = true; 851055c67edSArnaldo Carvalho de Melo 852055c67edSArnaldo Carvalho de Melo /* is thread group leader in thread_map? */ 853055c67edSArnaldo Carvalho de Melo for (j = 0; j < threads->nr; ++j) { 854055c67edSArnaldo Carvalho de Melo if ((int) comm_event->comm.pid == perf_thread_map__pid(threads, j)) { 855055c67edSArnaldo Carvalho de Melo need_leader = false; 856055c67edSArnaldo Carvalho de Melo break; 857055c67edSArnaldo Carvalho de Melo } 858055c67edSArnaldo Carvalho de Melo } 859055c67edSArnaldo Carvalho de Melo 860055c67edSArnaldo Carvalho de Melo /* if not, generate events for it */ 861055c67edSArnaldo Carvalho de Melo if (need_leader && 862055c67edSArnaldo Carvalho de Melo __event__synthesize_thread(comm_event, mmap_event, 863055c67edSArnaldo Carvalho de Melo fork_event, namespaces_event, 864055c67edSArnaldo Carvalho de Melo comm_event->comm.pid, 0, 865055c67edSArnaldo Carvalho de Melo process, tool, machine, 86684111b9cSNamhyung Kim needs_mmap, mmap_data)) { 867055c67edSArnaldo Carvalho de Melo err = -1; 868055c67edSArnaldo Carvalho de Melo break; 869055c67edSArnaldo Carvalho de Melo } 870055c67edSArnaldo Carvalho de Melo } 871055c67edSArnaldo Carvalho de Melo } 872055c67edSArnaldo Carvalho de Melo free(namespaces_event); 873055c67edSArnaldo Carvalho de Melo out_free_fork: 874055c67edSArnaldo Carvalho de Melo free(fork_event); 875055c67edSArnaldo Carvalho de Melo out_free_mmap: 876055c67edSArnaldo Carvalho de Melo free(mmap_event); 877055c67edSArnaldo Carvalho de Melo out_free_comm: 878055c67edSArnaldo Carvalho de Melo free(comm_event); 879055c67edSArnaldo Carvalho de Melo out: 880055c67edSArnaldo Carvalho de Melo return err; 881055c67edSArnaldo Carvalho de Melo } 882055c67edSArnaldo Carvalho de Melo 883055c67edSArnaldo Carvalho de Melo static int __perf_event__synthesize_threads(struct perf_tool *tool, 884055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 885055c67edSArnaldo Carvalho de Melo struct machine *machine, 88684111b9cSNamhyung Kim bool needs_mmap, 887055c67edSArnaldo Carvalho de Melo bool mmap_data, 888055c67edSArnaldo Carvalho de Melo struct dirent **dirent, 889055c67edSArnaldo Carvalho de Melo int start, 890055c67edSArnaldo Carvalho de Melo int num) 891055c67edSArnaldo Carvalho de Melo { 892055c67edSArnaldo Carvalho de Melo union perf_event *comm_event, *mmap_event, *fork_event; 893055c67edSArnaldo Carvalho de Melo union perf_event *namespaces_event; 894055c67edSArnaldo Carvalho de Melo int err = -1; 895055c67edSArnaldo Carvalho de Melo char *end; 896055c67edSArnaldo Carvalho de Melo pid_t pid; 897055c67edSArnaldo Carvalho de Melo int i; 898055c67edSArnaldo Carvalho de Melo 899055c67edSArnaldo Carvalho de Melo comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 900055c67edSArnaldo Carvalho de Melo if (comm_event == NULL) 901055c67edSArnaldo Carvalho de Melo goto out; 902055c67edSArnaldo Carvalho de Melo 903055c67edSArnaldo Carvalho de Melo mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); 904055c67edSArnaldo Carvalho de Melo if (mmap_event == NULL) 905055c67edSArnaldo Carvalho de Melo goto out_free_comm; 906055c67edSArnaldo Carvalho de Melo 907055c67edSArnaldo Carvalho de Melo fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); 908055c67edSArnaldo Carvalho de Melo if (fork_event == NULL) 909055c67edSArnaldo Carvalho de Melo goto out_free_mmap; 910055c67edSArnaldo Carvalho de Melo 911055c67edSArnaldo Carvalho de Melo namespaces_event = malloc(sizeof(namespaces_event->namespaces) + 912055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 913055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 914055c67edSArnaldo Carvalho de Melo if (namespaces_event == NULL) 915055c67edSArnaldo Carvalho de Melo goto out_free_fork; 916055c67edSArnaldo Carvalho de Melo 917055c67edSArnaldo Carvalho de Melo for (i = start; i < start + num; i++) { 918055c67edSArnaldo Carvalho de Melo if (!isdigit(dirent[i]->d_name[0])) 919055c67edSArnaldo Carvalho de Melo continue; 920055c67edSArnaldo Carvalho de Melo 921055c67edSArnaldo Carvalho de Melo pid = (pid_t)strtol(dirent[i]->d_name, &end, 10); 922055c67edSArnaldo Carvalho de Melo /* only interested in proper numerical dirents */ 923055c67edSArnaldo Carvalho de Melo if (*end) 924055c67edSArnaldo Carvalho de Melo continue; 925055c67edSArnaldo Carvalho de Melo /* 926055c67edSArnaldo Carvalho de Melo * We may race with exiting thread, so don't stop just because 927055c67edSArnaldo Carvalho de Melo * one thread couldn't be synthesized. 928055c67edSArnaldo Carvalho de Melo */ 929055c67edSArnaldo Carvalho de Melo __event__synthesize_thread(comm_event, mmap_event, fork_event, 930055c67edSArnaldo Carvalho de Melo namespaces_event, pid, 1, process, 93184111b9cSNamhyung Kim tool, machine, needs_mmap, mmap_data); 932055c67edSArnaldo Carvalho de Melo } 933055c67edSArnaldo Carvalho de Melo err = 0; 934055c67edSArnaldo Carvalho de Melo 935055c67edSArnaldo Carvalho de Melo free(namespaces_event); 936055c67edSArnaldo Carvalho de Melo out_free_fork: 937055c67edSArnaldo Carvalho de Melo free(fork_event); 938055c67edSArnaldo Carvalho de Melo out_free_mmap: 939055c67edSArnaldo Carvalho de Melo free(mmap_event); 940055c67edSArnaldo Carvalho de Melo out_free_comm: 941055c67edSArnaldo Carvalho de Melo free(comm_event); 942055c67edSArnaldo Carvalho de Melo out: 943055c67edSArnaldo Carvalho de Melo return err; 944055c67edSArnaldo Carvalho de Melo } 945055c67edSArnaldo Carvalho de Melo 946055c67edSArnaldo Carvalho de Melo struct synthesize_threads_arg { 947055c67edSArnaldo Carvalho de Melo struct perf_tool *tool; 948055c67edSArnaldo Carvalho de Melo perf_event__handler_t process; 949055c67edSArnaldo Carvalho de Melo struct machine *machine; 95084111b9cSNamhyung Kim bool needs_mmap; 951055c67edSArnaldo Carvalho de Melo bool mmap_data; 952055c67edSArnaldo Carvalho de Melo struct dirent **dirent; 953055c67edSArnaldo Carvalho de Melo int num; 954055c67edSArnaldo Carvalho de Melo int start; 955055c67edSArnaldo Carvalho de Melo }; 956055c67edSArnaldo Carvalho de Melo 957055c67edSArnaldo Carvalho de Melo static void *synthesize_threads_worker(void *arg) 958055c67edSArnaldo Carvalho de Melo { 959055c67edSArnaldo Carvalho de Melo struct synthesize_threads_arg *args = arg; 960055c67edSArnaldo Carvalho de Melo 961055c67edSArnaldo Carvalho de Melo __perf_event__synthesize_threads(args->tool, args->process, 96284111b9cSNamhyung Kim args->machine, 96384111b9cSNamhyung Kim args->needs_mmap, args->mmap_data, 964055c67edSArnaldo Carvalho de Melo args->dirent, 965055c67edSArnaldo Carvalho de Melo args->start, args->num); 966055c67edSArnaldo Carvalho de Melo return NULL; 967055c67edSArnaldo Carvalho de Melo } 968055c67edSArnaldo Carvalho de Melo 969055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_threads(struct perf_tool *tool, 970055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 971055c67edSArnaldo Carvalho de Melo struct machine *machine, 97284111b9cSNamhyung Kim bool needs_mmap, bool mmap_data, 973055c67edSArnaldo Carvalho de Melo unsigned int nr_threads_synthesize) 974055c67edSArnaldo Carvalho de Melo { 975055c67edSArnaldo Carvalho de Melo struct synthesize_threads_arg *args = NULL; 976055c67edSArnaldo Carvalho de Melo pthread_t *synthesize_threads = NULL; 977055c67edSArnaldo Carvalho de Melo char proc_path[PATH_MAX]; 978055c67edSArnaldo Carvalho de Melo struct dirent **dirent; 979055c67edSArnaldo Carvalho de Melo int num_per_thread; 980055c67edSArnaldo Carvalho de Melo int m, n, i, j; 981055c67edSArnaldo Carvalho de Melo int thread_nr; 982055c67edSArnaldo Carvalho de Melo int base = 0; 983055c67edSArnaldo Carvalho de Melo int err = -1; 984055c67edSArnaldo Carvalho de Melo 985055c67edSArnaldo Carvalho de Melo 986055c67edSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 987055c67edSArnaldo Carvalho de Melo return 0; 988055c67edSArnaldo Carvalho de Melo 989055c67edSArnaldo Carvalho de Melo snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); 990473f742eSNamhyung Kim n = scandir(proc_path, &dirent, filter_task, alphasort); 991055c67edSArnaldo Carvalho de Melo if (n < 0) 992055c67edSArnaldo Carvalho de Melo return err; 993055c67edSArnaldo Carvalho de Melo 994055c67edSArnaldo Carvalho de Melo if (nr_threads_synthesize == UINT_MAX) 995055c67edSArnaldo Carvalho de Melo thread_nr = sysconf(_SC_NPROCESSORS_ONLN); 996055c67edSArnaldo Carvalho de Melo else 997055c67edSArnaldo Carvalho de Melo thread_nr = nr_threads_synthesize; 998055c67edSArnaldo Carvalho de Melo 999055c67edSArnaldo Carvalho de Melo if (thread_nr <= 1) { 1000055c67edSArnaldo Carvalho de Melo err = __perf_event__synthesize_threads(tool, process, 100184111b9cSNamhyung Kim machine, 100284111b9cSNamhyung Kim needs_mmap, mmap_data, 1003055c67edSArnaldo Carvalho de Melo dirent, base, n); 1004055c67edSArnaldo Carvalho de Melo goto free_dirent; 1005055c67edSArnaldo Carvalho de Melo } 1006055c67edSArnaldo Carvalho de Melo if (thread_nr > n) 1007055c67edSArnaldo Carvalho de Melo thread_nr = n; 1008055c67edSArnaldo Carvalho de Melo 1009055c67edSArnaldo Carvalho de Melo synthesize_threads = calloc(sizeof(pthread_t), thread_nr); 1010055c67edSArnaldo Carvalho de Melo if (synthesize_threads == NULL) 1011055c67edSArnaldo Carvalho de Melo goto free_dirent; 1012055c67edSArnaldo Carvalho de Melo 1013055c67edSArnaldo Carvalho de Melo args = calloc(sizeof(*args), thread_nr); 1014055c67edSArnaldo Carvalho de Melo if (args == NULL) 1015055c67edSArnaldo Carvalho de Melo goto free_threads; 1016055c67edSArnaldo Carvalho de Melo 1017055c67edSArnaldo Carvalho de Melo num_per_thread = n / thread_nr; 1018055c67edSArnaldo Carvalho de Melo m = n % thread_nr; 1019055c67edSArnaldo Carvalho de Melo for (i = 0; i < thread_nr; i++) { 1020055c67edSArnaldo Carvalho de Melo args[i].tool = tool; 1021055c67edSArnaldo Carvalho de Melo args[i].process = process; 1022055c67edSArnaldo Carvalho de Melo args[i].machine = machine; 102384111b9cSNamhyung Kim args[i].needs_mmap = needs_mmap; 1024055c67edSArnaldo Carvalho de Melo args[i].mmap_data = mmap_data; 1025055c67edSArnaldo Carvalho de Melo args[i].dirent = dirent; 1026055c67edSArnaldo Carvalho de Melo } 1027055c67edSArnaldo Carvalho de Melo for (i = 0; i < m; i++) { 1028055c67edSArnaldo Carvalho de Melo args[i].num = num_per_thread + 1; 1029055c67edSArnaldo Carvalho de Melo args[i].start = i * args[i].num; 1030055c67edSArnaldo Carvalho de Melo } 1031055c67edSArnaldo Carvalho de Melo if (i != 0) 1032055c67edSArnaldo Carvalho de Melo base = args[i-1].start + args[i-1].num; 1033055c67edSArnaldo Carvalho de Melo for (j = i; j < thread_nr; j++) { 1034055c67edSArnaldo Carvalho de Melo args[j].num = num_per_thread; 1035055c67edSArnaldo Carvalho de Melo args[j].start = base + (j - i) * args[i].num; 1036055c67edSArnaldo Carvalho de Melo } 1037055c67edSArnaldo Carvalho de Melo 1038055c67edSArnaldo Carvalho de Melo for (i = 0; i < thread_nr; i++) { 1039055c67edSArnaldo Carvalho de Melo if (pthread_create(&synthesize_threads[i], NULL, 1040055c67edSArnaldo Carvalho de Melo synthesize_threads_worker, &args[i])) 1041055c67edSArnaldo Carvalho de Melo goto out_join; 1042055c67edSArnaldo Carvalho de Melo } 1043055c67edSArnaldo Carvalho de Melo err = 0; 1044055c67edSArnaldo Carvalho de Melo out_join: 1045055c67edSArnaldo Carvalho de Melo for (i = 0; i < thread_nr; i++) 1046055c67edSArnaldo Carvalho de Melo pthread_join(synthesize_threads[i], NULL); 1047055c67edSArnaldo Carvalho de Melo free(args); 1048055c67edSArnaldo Carvalho de Melo free_threads: 1049055c67edSArnaldo Carvalho de Melo free(synthesize_threads); 1050055c67edSArnaldo Carvalho de Melo free_dirent: 1051055c67edSArnaldo Carvalho de Melo for (i = 0; i < n; i++) 1052055c67edSArnaldo Carvalho de Melo zfree(&dirent[i]); 1053055c67edSArnaldo Carvalho de Melo free(dirent); 1054055c67edSArnaldo Carvalho de Melo 1055055c67edSArnaldo Carvalho de Melo return err; 1056055c67edSArnaldo Carvalho de Melo } 1057055c67edSArnaldo Carvalho de Melo 1058055c67edSArnaldo Carvalho de Melo int __weak perf_event__synthesize_extra_kmaps(struct perf_tool *tool __maybe_unused, 1059055c67edSArnaldo Carvalho de Melo perf_event__handler_t process __maybe_unused, 1060055c67edSArnaldo Carvalho de Melo struct machine *machine __maybe_unused) 1061055c67edSArnaldo Carvalho de Melo { 1062055c67edSArnaldo Carvalho de Melo return 0; 1063055c67edSArnaldo Carvalho de Melo } 1064055c67edSArnaldo Carvalho de Melo 1065055c67edSArnaldo Carvalho de Melo static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 1066055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1067055c67edSArnaldo Carvalho de Melo struct machine *machine) 1068055c67edSArnaldo Carvalho de Melo { 1069978410ffSJiri Olsa union perf_event *event; 1070978410ffSJiri Olsa size_t size = symbol_conf.buildid_mmap2 ? 1071978410ffSJiri Olsa sizeof(event->mmap2) : sizeof(event->mmap); 1072055c67edSArnaldo Carvalho de Melo struct map *map = machine__kernel_map(machine); 1073055c67edSArnaldo Carvalho de Melo struct kmap *kmap; 1074055c67edSArnaldo Carvalho de Melo int err; 1075055c67edSArnaldo Carvalho de Melo 1076055c67edSArnaldo Carvalho de Melo if (map == NULL) 1077055c67edSArnaldo Carvalho de Melo return -1; 1078055c67edSArnaldo Carvalho de Melo 1079055c67edSArnaldo Carvalho de Melo kmap = map__kmap(map); 1080055c67edSArnaldo Carvalho de Melo if (!kmap->ref_reloc_sym) 1081055c67edSArnaldo Carvalho de Melo return -1; 1082055c67edSArnaldo Carvalho de Melo 1083055c67edSArnaldo Carvalho de Melo /* 1084055c67edSArnaldo Carvalho de Melo * We should get this from /sys/kernel/sections/.text, but till that is 1085055c67edSArnaldo Carvalho de Melo * available use this, and after it is use this as a fallback for older 1086055c67edSArnaldo Carvalho de Melo * kernels. 1087055c67edSArnaldo Carvalho de Melo */ 1088978410ffSJiri Olsa event = zalloc(size + machine->id_hdr_size); 1089055c67edSArnaldo Carvalho de Melo if (event == NULL) { 1090055c67edSArnaldo Carvalho de Melo pr_debug("Not enough memory synthesizing mmap event " 1091055c67edSArnaldo Carvalho de Melo "for kernel modules\n"); 1092055c67edSArnaldo Carvalho de Melo return -1; 1093055c67edSArnaldo Carvalho de Melo } 1094055c67edSArnaldo Carvalho de Melo 1095055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) { 1096055c67edSArnaldo Carvalho de Melo /* 1097055c67edSArnaldo Carvalho de Melo * kernel uses PERF_RECORD_MISC_USER for user space maps, 1098055c67edSArnaldo Carvalho de Melo * see kernel/perf_event.c __perf_event_mmap 1099055c67edSArnaldo Carvalho de Melo */ 1100055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_KERNEL; 1101055c67edSArnaldo Carvalho de Melo } else { 1102055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 1103055c67edSArnaldo Carvalho de Melo } 1104055c67edSArnaldo Carvalho de Melo 1105978410ffSJiri Olsa if (symbol_conf.buildid_mmap2) { 1106978410ffSJiri Olsa size = snprintf(event->mmap2.filename, sizeof(event->mmap2.filename), 1107978410ffSJiri Olsa "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1; 1108978410ffSJiri Olsa size = PERF_ALIGN(size, sizeof(u64)); 1109978410ffSJiri Olsa event->mmap2.header.type = PERF_RECORD_MMAP2; 1110978410ffSJiri Olsa event->mmap2.header.size = (sizeof(event->mmap2) - 1111978410ffSJiri Olsa (sizeof(event->mmap2.filename) - size) + machine->id_hdr_size); 1112978410ffSJiri Olsa event->mmap2.pgoff = kmap->ref_reloc_sym->addr; 1113978410ffSJiri Olsa event->mmap2.start = map->start; 1114978410ffSJiri Olsa event->mmap2.len = map->end - event->mmap.start; 1115978410ffSJiri Olsa event->mmap2.pid = machine->pid; 11164183a8d7SJiri Olsa 11174183a8d7SJiri Olsa perf_record_mmap2__read_build_id(&event->mmap2, true); 1118978410ffSJiri Olsa } else { 1119055c67edSArnaldo Carvalho de Melo size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 1120055c67edSArnaldo Carvalho de Melo "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1; 1121055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 1122055c67edSArnaldo Carvalho de Melo event->mmap.header.type = PERF_RECORD_MMAP; 1123055c67edSArnaldo Carvalho de Melo event->mmap.header.size = (sizeof(event->mmap) - 1124055c67edSArnaldo Carvalho de Melo (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); 1125055c67edSArnaldo Carvalho de Melo event->mmap.pgoff = kmap->ref_reloc_sym->addr; 1126055c67edSArnaldo Carvalho de Melo event->mmap.start = map->start; 1127055c67edSArnaldo Carvalho de Melo event->mmap.len = map->end - event->mmap.start; 1128055c67edSArnaldo Carvalho de Melo event->mmap.pid = machine->pid; 1129978410ffSJiri Olsa } 1130055c67edSArnaldo Carvalho de Melo 1131055c67edSArnaldo Carvalho de Melo err = perf_tool__process_synth_event(tool, event, machine, process); 1132055c67edSArnaldo Carvalho de Melo free(event); 1133055c67edSArnaldo Carvalho de Melo 1134055c67edSArnaldo Carvalho de Melo return err; 1135055c67edSArnaldo Carvalho de Melo } 1136055c67edSArnaldo Carvalho de Melo 1137055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 1138055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1139055c67edSArnaldo Carvalho de Melo struct machine *machine) 1140055c67edSArnaldo Carvalho de Melo { 1141055c67edSArnaldo Carvalho de Melo int err; 1142055c67edSArnaldo Carvalho de Melo 1143055c67edSArnaldo Carvalho de Melo err = __perf_event__synthesize_kernel_mmap(tool, process, machine); 1144055c67edSArnaldo Carvalho de Melo if (err < 0) 1145055c67edSArnaldo Carvalho de Melo return err; 1146055c67edSArnaldo Carvalho de Melo 1147055c67edSArnaldo Carvalho de Melo return perf_event__synthesize_extra_kmaps(tool, process, machine); 1148055c67edSArnaldo Carvalho de Melo } 1149055c67edSArnaldo Carvalho de Melo 1150055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_thread_map2(struct perf_tool *tool, 1151055c67edSArnaldo Carvalho de Melo struct perf_thread_map *threads, 1152055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1153055c67edSArnaldo Carvalho de Melo struct machine *machine) 1154055c67edSArnaldo Carvalho de Melo { 1155055c67edSArnaldo Carvalho de Melo union perf_event *event; 1156055c67edSArnaldo Carvalho de Melo int i, err, size; 1157055c67edSArnaldo Carvalho de Melo 1158055c67edSArnaldo Carvalho de Melo size = sizeof(event->thread_map); 1159055c67edSArnaldo Carvalho de Melo size += threads->nr * sizeof(event->thread_map.entries[0]); 1160055c67edSArnaldo Carvalho de Melo 1161055c67edSArnaldo Carvalho de Melo event = zalloc(size); 1162055c67edSArnaldo Carvalho de Melo if (!event) 1163055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1164055c67edSArnaldo Carvalho de Melo 1165055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_THREAD_MAP; 1166055c67edSArnaldo Carvalho de Melo event->header.size = size; 1167055c67edSArnaldo Carvalho de Melo event->thread_map.nr = threads->nr; 1168055c67edSArnaldo Carvalho de Melo 1169055c67edSArnaldo Carvalho de Melo for (i = 0; i < threads->nr; i++) { 1170055c67edSArnaldo Carvalho de Melo struct perf_record_thread_map_entry *entry = &event->thread_map.entries[i]; 1171055c67edSArnaldo Carvalho de Melo char *comm = perf_thread_map__comm(threads, i); 1172055c67edSArnaldo Carvalho de Melo 1173055c67edSArnaldo Carvalho de Melo if (!comm) 1174055c67edSArnaldo Carvalho de Melo comm = (char *) ""; 1175055c67edSArnaldo Carvalho de Melo 1176055c67edSArnaldo Carvalho de Melo entry->pid = perf_thread_map__pid(threads, i); 1177055c67edSArnaldo Carvalho de Melo strncpy((char *) &entry->comm, comm, sizeof(entry->comm)); 1178055c67edSArnaldo Carvalho de Melo } 1179055c67edSArnaldo Carvalho de Melo 1180055c67edSArnaldo Carvalho de Melo err = process(tool, event, NULL, machine); 1181055c67edSArnaldo Carvalho de Melo 1182055c67edSArnaldo Carvalho de Melo free(event); 1183055c67edSArnaldo Carvalho de Melo return err; 1184055c67edSArnaldo Carvalho de Melo } 1185055c67edSArnaldo Carvalho de Melo 1186055c67edSArnaldo Carvalho de Melo static void synthesize_cpus(struct cpu_map_entries *cpus, 1187055c67edSArnaldo Carvalho de Melo struct perf_cpu_map *map) 1188055c67edSArnaldo Carvalho de Melo { 1189055c67edSArnaldo Carvalho de Melo int i; 1190055c67edSArnaldo Carvalho de Melo 1191055c67edSArnaldo Carvalho de Melo cpus->nr = map->nr; 1192055c67edSArnaldo Carvalho de Melo 1193055c67edSArnaldo Carvalho de Melo for (i = 0; i < map->nr; i++) 1194*6d18804bSIan Rogers cpus->cpu[i] = map->map[i].cpu; 1195055c67edSArnaldo Carvalho de Melo } 1196055c67edSArnaldo Carvalho de Melo 1197055c67edSArnaldo Carvalho de Melo static void synthesize_mask(struct perf_record_record_cpu_map *mask, 1198055c67edSArnaldo Carvalho de Melo struct perf_cpu_map *map, int max) 1199055c67edSArnaldo Carvalho de Melo { 1200055c67edSArnaldo Carvalho de Melo int i; 1201055c67edSArnaldo Carvalho de Melo 1202055c67edSArnaldo Carvalho de Melo mask->nr = BITS_TO_LONGS(max); 1203055c67edSArnaldo Carvalho de Melo mask->long_size = sizeof(long); 1204055c67edSArnaldo Carvalho de Melo 1205055c67edSArnaldo Carvalho de Melo for (i = 0; i < map->nr; i++) 1206*6d18804bSIan Rogers set_bit(map->map[i].cpu, mask->mask); 1207055c67edSArnaldo Carvalho de Melo } 1208055c67edSArnaldo Carvalho de Melo 1209055c67edSArnaldo Carvalho de Melo static size_t cpus_size(struct perf_cpu_map *map) 1210055c67edSArnaldo Carvalho de Melo { 1211055c67edSArnaldo Carvalho de Melo return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16); 1212055c67edSArnaldo Carvalho de Melo } 1213055c67edSArnaldo Carvalho de Melo 1214055c67edSArnaldo Carvalho de Melo static size_t mask_size(struct perf_cpu_map *map, int *max) 1215055c67edSArnaldo Carvalho de Melo { 1216055c67edSArnaldo Carvalho de Melo int i; 1217055c67edSArnaldo Carvalho de Melo 1218055c67edSArnaldo Carvalho de Melo *max = 0; 1219055c67edSArnaldo Carvalho de Melo 1220055c67edSArnaldo Carvalho de Melo for (i = 0; i < map->nr; i++) { 12214d39c89fSIngo Molnar /* bit position of the cpu is + 1 */ 1222*6d18804bSIan Rogers int bit = map->map[i].cpu + 1; 1223055c67edSArnaldo Carvalho de Melo 1224055c67edSArnaldo Carvalho de Melo if (bit > *max) 1225055c67edSArnaldo Carvalho de Melo *max = bit; 1226055c67edSArnaldo Carvalho de Melo } 1227055c67edSArnaldo Carvalho de Melo 1228055c67edSArnaldo Carvalho de Melo return sizeof(struct perf_record_record_cpu_map) + BITS_TO_LONGS(*max) * sizeof(long); 1229055c67edSArnaldo Carvalho de Melo } 1230055c67edSArnaldo Carvalho de Melo 1231055c67edSArnaldo Carvalho de Melo void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max) 1232055c67edSArnaldo Carvalho de Melo { 1233055c67edSArnaldo Carvalho de Melo size_t size_cpus, size_mask; 1234055c67edSArnaldo Carvalho de Melo bool is_dummy = perf_cpu_map__empty(map); 1235055c67edSArnaldo Carvalho de Melo 1236055c67edSArnaldo Carvalho de Melo /* 1237055c67edSArnaldo Carvalho de Melo * Both array and mask data have variable size based 1238055c67edSArnaldo Carvalho de Melo * on the number of cpus and their actual values. 1239055c67edSArnaldo Carvalho de Melo * The size of the 'struct perf_record_cpu_map_data' is: 1240055c67edSArnaldo Carvalho de Melo * 1241055c67edSArnaldo Carvalho de Melo * array = size of 'struct cpu_map_entries' + 1242055c67edSArnaldo Carvalho de Melo * number of cpus * sizeof(u64) 1243055c67edSArnaldo Carvalho de Melo * 1244055c67edSArnaldo Carvalho de Melo * mask = size of 'struct perf_record_record_cpu_map' + 1245055c67edSArnaldo Carvalho de Melo * maximum cpu bit converted to size of longs 1246055c67edSArnaldo Carvalho de Melo * 12474d39c89fSIngo Molnar * and finally + the size of 'struct perf_record_cpu_map_data'. 1248055c67edSArnaldo Carvalho de Melo */ 1249055c67edSArnaldo Carvalho de Melo size_cpus = cpus_size(map); 1250055c67edSArnaldo Carvalho de Melo size_mask = mask_size(map, max); 1251055c67edSArnaldo Carvalho de Melo 1252055c67edSArnaldo Carvalho de Melo if (is_dummy || (size_cpus < size_mask)) { 1253055c67edSArnaldo Carvalho de Melo *size += size_cpus; 1254055c67edSArnaldo Carvalho de Melo *type = PERF_CPU_MAP__CPUS; 1255055c67edSArnaldo Carvalho de Melo } else { 1256055c67edSArnaldo Carvalho de Melo *size += size_mask; 1257055c67edSArnaldo Carvalho de Melo *type = PERF_CPU_MAP__MASK; 1258055c67edSArnaldo Carvalho de Melo } 1259055c67edSArnaldo Carvalho de Melo 1260055c67edSArnaldo Carvalho de Melo *size += sizeof(struct perf_record_cpu_map_data); 1261055c67edSArnaldo Carvalho de Melo *size = PERF_ALIGN(*size, sizeof(u64)); 1262055c67edSArnaldo Carvalho de Melo return zalloc(*size); 1263055c67edSArnaldo Carvalho de Melo } 1264055c67edSArnaldo Carvalho de Melo 1265055c67edSArnaldo Carvalho de Melo void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map, 1266055c67edSArnaldo Carvalho de Melo u16 type, int max) 1267055c67edSArnaldo Carvalho de Melo { 1268055c67edSArnaldo Carvalho de Melo data->type = type; 1269055c67edSArnaldo Carvalho de Melo 1270055c67edSArnaldo Carvalho de Melo switch (type) { 1271055c67edSArnaldo Carvalho de Melo case PERF_CPU_MAP__CPUS: 1272055c67edSArnaldo Carvalho de Melo synthesize_cpus((struct cpu_map_entries *) data->data, map); 1273055c67edSArnaldo Carvalho de Melo break; 1274055c67edSArnaldo Carvalho de Melo case PERF_CPU_MAP__MASK: 1275055c67edSArnaldo Carvalho de Melo synthesize_mask((struct perf_record_record_cpu_map *)data->data, map, max); 1276055c67edSArnaldo Carvalho de Melo default: 1277055c67edSArnaldo Carvalho de Melo break; 12788284bbeaSZou Wei } 1279055c67edSArnaldo Carvalho de Melo } 1280055c67edSArnaldo Carvalho de Melo 1281055c67edSArnaldo Carvalho de Melo static struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map) 1282055c67edSArnaldo Carvalho de Melo { 1283055c67edSArnaldo Carvalho de Melo size_t size = sizeof(struct perf_record_cpu_map); 1284055c67edSArnaldo Carvalho de Melo struct perf_record_cpu_map *event; 1285055c67edSArnaldo Carvalho de Melo int max; 1286055c67edSArnaldo Carvalho de Melo u16 type; 1287055c67edSArnaldo Carvalho de Melo 1288055c67edSArnaldo Carvalho de Melo event = cpu_map_data__alloc(map, &size, &type, &max); 1289055c67edSArnaldo Carvalho de Melo if (!event) 1290055c67edSArnaldo Carvalho de Melo return NULL; 1291055c67edSArnaldo Carvalho de Melo 1292055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_CPU_MAP; 1293055c67edSArnaldo Carvalho de Melo event->header.size = size; 1294055c67edSArnaldo Carvalho de Melo event->data.type = type; 1295055c67edSArnaldo Carvalho de Melo 1296055c67edSArnaldo Carvalho de Melo cpu_map_data__synthesize(&event->data, map, type, max); 1297055c67edSArnaldo Carvalho de Melo return event; 1298055c67edSArnaldo Carvalho de Melo } 1299055c67edSArnaldo Carvalho de Melo 1300055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_cpu_map(struct perf_tool *tool, 1301055c67edSArnaldo Carvalho de Melo struct perf_cpu_map *map, 1302055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1303055c67edSArnaldo Carvalho de Melo struct machine *machine) 1304055c67edSArnaldo Carvalho de Melo { 1305055c67edSArnaldo Carvalho de Melo struct perf_record_cpu_map *event; 1306055c67edSArnaldo Carvalho de Melo int err; 1307055c67edSArnaldo Carvalho de Melo 1308055c67edSArnaldo Carvalho de Melo event = cpu_map_event__new(map); 1309055c67edSArnaldo Carvalho de Melo if (!event) 1310055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1311055c67edSArnaldo Carvalho de Melo 1312055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *) event, NULL, machine); 1313055c67edSArnaldo Carvalho de Melo 1314055c67edSArnaldo Carvalho de Melo free(event); 1315055c67edSArnaldo Carvalho de Melo return err; 1316055c67edSArnaldo Carvalho de Melo } 1317055c67edSArnaldo Carvalho de Melo 1318055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_config(struct perf_tool *tool, 1319055c67edSArnaldo Carvalho de Melo struct perf_stat_config *config, 1320055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1321055c67edSArnaldo Carvalho de Melo struct machine *machine) 1322055c67edSArnaldo Carvalho de Melo { 1323055c67edSArnaldo Carvalho de Melo struct perf_record_stat_config *event; 1324055c67edSArnaldo Carvalho de Melo int size, i = 0, err; 1325055c67edSArnaldo Carvalho de Melo 1326055c67edSArnaldo Carvalho de Melo size = sizeof(*event); 1327055c67edSArnaldo Carvalho de Melo size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0])); 1328055c67edSArnaldo Carvalho de Melo 1329055c67edSArnaldo Carvalho de Melo event = zalloc(size); 1330055c67edSArnaldo Carvalho de Melo if (!event) 1331055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1332055c67edSArnaldo Carvalho de Melo 1333055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_STAT_CONFIG; 1334055c67edSArnaldo Carvalho de Melo event->header.size = size; 1335055c67edSArnaldo Carvalho de Melo event->nr = PERF_STAT_CONFIG_TERM__MAX; 1336055c67edSArnaldo Carvalho de Melo 1337055c67edSArnaldo Carvalho de Melo #define ADD(__term, __val) \ 1338055c67edSArnaldo Carvalho de Melo event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term; \ 1339055c67edSArnaldo Carvalho de Melo event->data[i].val = __val; \ 1340055c67edSArnaldo Carvalho de Melo i++; 1341055c67edSArnaldo Carvalho de Melo 1342055c67edSArnaldo Carvalho de Melo ADD(AGGR_MODE, config->aggr_mode) 1343055c67edSArnaldo Carvalho de Melo ADD(INTERVAL, config->interval) 1344055c67edSArnaldo Carvalho de Melo ADD(SCALE, config->scale) 1345055c67edSArnaldo Carvalho de Melo 1346055c67edSArnaldo Carvalho de Melo WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX, 1347055c67edSArnaldo Carvalho de Melo "stat config terms unbalanced\n"); 1348055c67edSArnaldo Carvalho de Melo #undef ADD 1349055c67edSArnaldo Carvalho de Melo 1350055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *) event, NULL, machine); 1351055c67edSArnaldo Carvalho de Melo 1352055c67edSArnaldo Carvalho de Melo free(event); 1353055c67edSArnaldo Carvalho de Melo return err; 1354055c67edSArnaldo Carvalho de Melo } 1355055c67edSArnaldo Carvalho de Melo 1356055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat(struct perf_tool *tool, 1357*6d18804bSIan Rogers struct perf_cpu cpu, u32 thread, u64 id, 1358055c67edSArnaldo Carvalho de Melo struct perf_counts_values *count, 1359055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1360055c67edSArnaldo Carvalho de Melo struct machine *machine) 1361055c67edSArnaldo Carvalho de Melo { 1362055c67edSArnaldo Carvalho de Melo struct perf_record_stat event; 1363055c67edSArnaldo Carvalho de Melo 1364055c67edSArnaldo Carvalho de Melo event.header.type = PERF_RECORD_STAT; 1365055c67edSArnaldo Carvalho de Melo event.header.size = sizeof(event); 1366055c67edSArnaldo Carvalho de Melo event.header.misc = 0; 1367055c67edSArnaldo Carvalho de Melo 1368055c67edSArnaldo Carvalho de Melo event.id = id; 1369*6d18804bSIan Rogers event.cpu = cpu.cpu; 1370055c67edSArnaldo Carvalho de Melo event.thread = thread; 1371055c67edSArnaldo Carvalho de Melo event.val = count->val; 1372055c67edSArnaldo Carvalho de Melo event.ena = count->ena; 1373055c67edSArnaldo Carvalho de Melo event.run = count->run; 1374055c67edSArnaldo Carvalho de Melo 1375055c67edSArnaldo Carvalho de Melo return process(tool, (union perf_event *) &event, NULL, machine); 1376055c67edSArnaldo Carvalho de Melo } 1377055c67edSArnaldo Carvalho de Melo 1378055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_round(struct perf_tool *tool, 1379055c67edSArnaldo Carvalho de Melo u64 evtime, u64 type, 1380055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1381055c67edSArnaldo Carvalho de Melo struct machine *machine) 1382055c67edSArnaldo Carvalho de Melo { 1383055c67edSArnaldo Carvalho de Melo struct perf_record_stat_round event; 1384055c67edSArnaldo Carvalho de Melo 1385055c67edSArnaldo Carvalho de Melo event.header.type = PERF_RECORD_STAT_ROUND; 1386055c67edSArnaldo Carvalho de Melo event.header.size = sizeof(event); 1387055c67edSArnaldo Carvalho de Melo event.header.misc = 0; 1388055c67edSArnaldo Carvalho de Melo 1389055c67edSArnaldo Carvalho de Melo event.time = evtime; 1390055c67edSArnaldo Carvalho de Melo event.type = type; 1391055c67edSArnaldo Carvalho de Melo 1392055c67edSArnaldo Carvalho de Melo return process(tool, (union perf_event *) &event, NULL, machine); 1393055c67edSArnaldo Carvalho de Melo } 1394055c67edSArnaldo Carvalho de Melo 1395055c67edSArnaldo Carvalho de Melo size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format) 1396055c67edSArnaldo Carvalho de Melo { 1397055c67edSArnaldo Carvalho de Melo size_t sz, result = sizeof(struct perf_record_sample); 1398055c67edSArnaldo Carvalho de Melo 1399055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IDENTIFIER) 1400055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1401055c67edSArnaldo Carvalho de Melo 1402055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IP) 1403055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1404055c67edSArnaldo Carvalho de Melo 1405055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TID) 1406055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1407055c67edSArnaldo Carvalho de Melo 1408055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TIME) 1409055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1410055c67edSArnaldo Carvalho de Melo 1411055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ADDR) 1412055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1413055c67edSArnaldo Carvalho de Melo 1414055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ID) 1415055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1416055c67edSArnaldo Carvalho de Melo 1417055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STREAM_ID) 1418055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1419055c67edSArnaldo Carvalho de Melo 1420055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CPU) 1421055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1422055c67edSArnaldo Carvalho de Melo 1423055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PERIOD) 1424055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1425055c67edSArnaldo Carvalho de Melo 1426055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_READ) { 1427055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1428055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 1429055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1430055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 1431055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1432055c67edSArnaldo Carvalho de Melo /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 1433055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) { 1434055c67edSArnaldo Carvalho de Melo sz = sample->read.group.nr * 1435055c67edSArnaldo Carvalho de Melo sizeof(struct sample_read_value); 1436055c67edSArnaldo Carvalho de Melo result += sz; 1437055c67edSArnaldo Carvalho de Melo } else { 1438055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1439055c67edSArnaldo Carvalho de Melo } 1440055c67edSArnaldo Carvalho de Melo } 1441055c67edSArnaldo Carvalho de Melo 1442055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CALLCHAIN) { 1443055c67edSArnaldo Carvalho de Melo sz = (sample->callchain->nr + 1) * sizeof(u64); 1444055c67edSArnaldo Carvalho de Melo result += sz; 1445055c67edSArnaldo Carvalho de Melo } 1446055c67edSArnaldo Carvalho de Melo 1447055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_RAW) { 1448055c67edSArnaldo Carvalho de Melo result += sizeof(u32); 1449055c67edSArnaldo Carvalho de Melo result += sample->raw_size; 1450055c67edSArnaldo Carvalho de Melo } 1451055c67edSArnaldo Carvalho de Melo 1452055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_BRANCH_STACK) { 1453055c67edSArnaldo Carvalho de Melo sz = sample->branch_stack->nr * sizeof(struct branch_entry); 145442bbabedSKan Liang /* nr, hw_idx */ 145542bbabedSKan Liang sz += 2 * sizeof(u64); 1456055c67edSArnaldo Carvalho de Melo result += sz; 1457055c67edSArnaldo Carvalho de Melo } 1458055c67edSArnaldo Carvalho de Melo 1459055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_USER) { 1460055c67edSArnaldo Carvalho de Melo if (sample->user_regs.abi) { 1461055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1462055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->user_regs.mask) * sizeof(u64); 1463055c67edSArnaldo Carvalho de Melo result += sz; 1464055c67edSArnaldo Carvalho de Melo } else { 1465055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1466055c67edSArnaldo Carvalho de Melo } 1467055c67edSArnaldo Carvalho de Melo } 1468055c67edSArnaldo Carvalho de Melo 1469055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STACK_USER) { 1470055c67edSArnaldo Carvalho de Melo sz = sample->user_stack.size; 1471055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1472055c67edSArnaldo Carvalho de Melo if (sz) { 1473055c67edSArnaldo Carvalho de Melo result += sz; 1474055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1475055c67edSArnaldo Carvalho de Melo } 1476055c67edSArnaldo Carvalho de Melo } 1477055c67edSArnaldo Carvalho de Melo 1478ea8d0ed6SKan Liang if (type & PERF_SAMPLE_WEIGHT_TYPE) 1479055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1480055c67edSArnaldo Carvalho de Melo 1481055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_DATA_SRC) 1482055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1483055c67edSArnaldo Carvalho de Melo 1484055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TRANSACTION) 1485055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1486055c67edSArnaldo Carvalho de Melo 1487055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_INTR) { 1488055c67edSArnaldo Carvalho de Melo if (sample->intr_regs.abi) { 1489055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1490055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 1491055c67edSArnaldo Carvalho de Melo result += sz; 1492055c67edSArnaldo Carvalho de Melo } else { 1493055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1494055c67edSArnaldo Carvalho de Melo } 1495055c67edSArnaldo Carvalho de Melo } 1496055c67edSArnaldo Carvalho de Melo 1497055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PHYS_ADDR) 1498055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1499055c67edSArnaldo Carvalho de Melo 1500ba78c1c5SNamhyung Kim if (type & PERF_SAMPLE_CGROUP) 1501ba78c1c5SNamhyung Kim result += sizeof(u64); 1502ba78c1c5SNamhyung Kim 1503542b88fdSKan Liang if (type & PERF_SAMPLE_DATA_PAGE_SIZE) 1504542b88fdSKan Liang result += sizeof(u64); 1505542b88fdSKan Liang 1506c1de7f3dSKan Liang if (type & PERF_SAMPLE_CODE_PAGE_SIZE) 1507c1de7f3dSKan Liang result += sizeof(u64); 1508c1de7f3dSKan Liang 150998dcf14dSAdrian Hunter if (type & PERF_SAMPLE_AUX) { 151098dcf14dSAdrian Hunter result += sizeof(u64); 151198dcf14dSAdrian Hunter result += sample->aux_sample.size; 151298dcf14dSAdrian Hunter } 151398dcf14dSAdrian Hunter 1514055c67edSArnaldo Carvalho de Melo return result; 1515055c67edSArnaldo Carvalho de Melo } 1516055c67edSArnaldo Carvalho de Melo 1517fbefe9c2SKan Liang void __weak arch_perf_synthesize_sample_weight(const struct perf_sample *data, 1518fbefe9c2SKan Liang __u64 *array, u64 type __maybe_unused) 1519fbefe9c2SKan Liang { 1520fbefe9c2SKan Liang *array = data->weight; 1521fbefe9c2SKan Liang } 1522fbefe9c2SKan Liang 1523055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format, 1524055c67edSArnaldo Carvalho de Melo const struct perf_sample *sample) 1525055c67edSArnaldo Carvalho de Melo { 1526055c67edSArnaldo Carvalho de Melo __u64 *array; 1527055c67edSArnaldo Carvalho de Melo size_t sz; 1528055c67edSArnaldo Carvalho de Melo /* 1529055c67edSArnaldo Carvalho de Melo * used for cross-endian analysis. See git commit 65014ab3 1530055c67edSArnaldo Carvalho de Melo * for why this goofiness is needed. 1531055c67edSArnaldo Carvalho de Melo */ 1532055c67edSArnaldo Carvalho de Melo union u64_swap u; 1533055c67edSArnaldo Carvalho de Melo 1534055c67edSArnaldo Carvalho de Melo array = event->sample.array; 1535055c67edSArnaldo Carvalho de Melo 1536055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IDENTIFIER) { 1537055c67edSArnaldo Carvalho de Melo *array = sample->id; 1538055c67edSArnaldo Carvalho de Melo array++; 1539055c67edSArnaldo Carvalho de Melo } 1540055c67edSArnaldo Carvalho de Melo 1541055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IP) { 1542055c67edSArnaldo Carvalho de Melo *array = sample->ip; 1543055c67edSArnaldo Carvalho de Melo array++; 1544055c67edSArnaldo Carvalho de Melo } 1545055c67edSArnaldo Carvalho de Melo 1546055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TID) { 1547055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->pid; 1548055c67edSArnaldo Carvalho de Melo u.val32[1] = sample->tid; 1549055c67edSArnaldo Carvalho de Melo *array = u.val64; 1550055c67edSArnaldo Carvalho de Melo array++; 1551055c67edSArnaldo Carvalho de Melo } 1552055c67edSArnaldo Carvalho de Melo 1553055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TIME) { 1554055c67edSArnaldo Carvalho de Melo *array = sample->time; 1555055c67edSArnaldo Carvalho de Melo array++; 1556055c67edSArnaldo Carvalho de Melo } 1557055c67edSArnaldo Carvalho de Melo 1558055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ADDR) { 1559055c67edSArnaldo Carvalho de Melo *array = sample->addr; 1560055c67edSArnaldo Carvalho de Melo array++; 1561055c67edSArnaldo Carvalho de Melo } 1562055c67edSArnaldo Carvalho de Melo 1563055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ID) { 1564055c67edSArnaldo Carvalho de Melo *array = sample->id; 1565055c67edSArnaldo Carvalho de Melo array++; 1566055c67edSArnaldo Carvalho de Melo } 1567055c67edSArnaldo Carvalho de Melo 1568055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STREAM_ID) { 1569055c67edSArnaldo Carvalho de Melo *array = sample->stream_id; 1570055c67edSArnaldo Carvalho de Melo array++; 1571055c67edSArnaldo Carvalho de Melo } 1572055c67edSArnaldo Carvalho de Melo 1573055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CPU) { 1574055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->cpu; 1575055c67edSArnaldo Carvalho de Melo u.val32[1] = 0; 1576055c67edSArnaldo Carvalho de Melo *array = u.val64; 1577055c67edSArnaldo Carvalho de Melo array++; 1578055c67edSArnaldo Carvalho de Melo } 1579055c67edSArnaldo Carvalho de Melo 1580055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PERIOD) { 1581055c67edSArnaldo Carvalho de Melo *array = sample->period; 1582055c67edSArnaldo Carvalho de Melo array++; 1583055c67edSArnaldo Carvalho de Melo } 1584055c67edSArnaldo Carvalho de Melo 1585055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_READ) { 1586055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) 1587055c67edSArnaldo Carvalho de Melo *array = sample->read.group.nr; 1588055c67edSArnaldo Carvalho de Melo else 1589055c67edSArnaldo Carvalho de Melo *array = sample->read.one.value; 1590055c67edSArnaldo Carvalho de Melo array++; 1591055c67edSArnaldo Carvalho de Melo 1592055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { 1593055c67edSArnaldo Carvalho de Melo *array = sample->read.time_enabled; 1594055c67edSArnaldo Carvalho de Melo array++; 1595055c67edSArnaldo Carvalho de Melo } 1596055c67edSArnaldo Carvalho de Melo 1597055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { 1598055c67edSArnaldo Carvalho de Melo *array = sample->read.time_running; 1599055c67edSArnaldo Carvalho de Melo array++; 1600055c67edSArnaldo Carvalho de Melo } 1601055c67edSArnaldo Carvalho de Melo 1602055c67edSArnaldo Carvalho de Melo /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 1603055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) { 1604055c67edSArnaldo Carvalho de Melo sz = sample->read.group.nr * 1605055c67edSArnaldo Carvalho de Melo sizeof(struct sample_read_value); 1606055c67edSArnaldo Carvalho de Melo memcpy(array, sample->read.group.values, sz); 1607055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1608055c67edSArnaldo Carvalho de Melo } else { 1609055c67edSArnaldo Carvalho de Melo *array = sample->read.one.id; 1610055c67edSArnaldo Carvalho de Melo array++; 1611055c67edSArnaldo Carvalho de Melo } 1612055c67edSArnaldo Carvalho de Melo } 1613055c67edSArnaldo Carvalho de Melo 1614055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CALLCHAIN) { 1615055c67edSArnaldo Carvalho de Melo sz = (sample->callchain->nr + 1) * sizeof(u64); 1616055c67edSArnaldo Carvalho de Melo memcpy(array, sample->callchain, sz); 1617055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1618055c67edSArnaldo Carvalho de Melo } 1619055c67edSArnaldo Carvalho de Melo 1620055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_RAW) { 1621055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->raw_size; 1622055c67edSArnaldo Carvalho de Melo *array = u.val64; 1623055c67edSArnaldo Carvalho de Melo array = (void *)array + sizeof(u32); 1624055c67edSArnaldo Carvalho de Melo 1625055c67edSArnaldo Carvalho de Melo memcpy(array, sample->raw_data, sample->raw_size); 1626055c67edSArnaldo Carvalho de Melo array = (void *)array + sample->raw_size; 1627055c67edSArnaldo Carvalho de Melo } 1628055c67edSArnaldo Carvalho de Melo 1629055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_BRANCH_STACK) { 1630055c67edSArnaldo Carvalho de Melo sz = sample->branch_stack->nr * sizeof(struct branch_entry); 163142bbabedSKan Liang /* nr, hw_idx */ 163242bbabedSKan Liang sz += 2 * sizeof(u64); 1633055c67edSArnaldo Carvalho de Melo memcpy(array, sample->branch_stack, sz); 1634055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1635055c67edSArnaldo Carvalho de Melo } 1636055c67edSArnaldo Carvalho de Melo 1637055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_USER) { 1638055c67edSArnaldo Carvalho de Melo if (sample->user_regs.abi) { 1639055c67edSArnaldo Carvalho de Melo *array++ = sample->user_regs.abi; 1640055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->user_regs.mask) * sizeof(u64); 1641055c67edSArnaldo Carvalho de Melo memcpy(array, sample->user_regs.regs, sz); 1642055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1643055c67edSArnaldo Carvalho de Melo } else { 1644055c67edSArnaldo Carvalho de Melo *array++ = 0; 1645055c67edSArnaldo Carvalho de Melo } 1646055c67edSArnaldo Carvalho de Melo } 1647055c67edSArnaldo Carvalho de Melo 1648055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STACK_USER) { 1649055c67edSArnaldo Carvalho de Melo sz = sample->user_stack.size; 1650055c67edSArnaldo Carvalho de Melo *array++ = sz; 1651055c67edSArnaldo Carvalho de Melo if (sz) { 1652055c67edSArnaldo Carvalho de Melo memcpy(array, sample->user_stack.data, sz); 1653055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1654055c67edSArnaldo Carvalho de Melo *array++ = sz; 1655055c67edSArnaldo Carvalho de Melo } 1656055c67edSArnaldo Carvalho de Melo } 1657055c67edSArnaldo Carvalho de Melo 1658ea8d0ed6SKan Liang if (type & PERF_SAMPLE_WEIGHT_TYPE) { 1659fbefe9c2SKan Liang arch_perf_synthesize_sample_weight(sample, array, type); 1660055c67edSArnaldo Carvalho de Melo array++; 1661055c67edSArnaldo Carvalho de Melo } 1662055c67edSArnaldo Carvalho de Melo 1663055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_DATA_SRC) { 1664055c67edSArnaldo Carvalho de Melo *array = sample->data_src; 1665055c67edSArnaldo Carvalho de Melo array++; 1666055c67edSArnaldo Carvalho de Melo } 1667055c67edSArnaldo Carvalho de Melo 1668055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TRANSACTION) { 1669055c67edSArnaldo Carvalho de Melo *array = sample->transaction; 1670055c67edSArnaldo Carvalho de Melo array++; 1671055c67edSArnaldo Carvalho de Melo } 1672055c67edSArnaldo Carvalho de Melo 1673055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_INTR) { 1674055c67edSArnaldo Carvalho de Melo if (sample->intr_regs.abi) { 1675055c67edSArnaldo Carvalho de Melo *array++ = sample->intr_regs.abi; 1676055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 1677055c67edSArnaldo Carvalho de Melo memcpy(array, sample->intr_regs.regs, sz); 1678055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1679055c67edSArnaldo Carvalho de Melo } else { 1680055c67edSArnaldo Carvalho de Melo *array++ = 0; 1681055c67edSArnaldo Carvalho de Melo } 1682055c67edSArnaldo Carvalho de Melo } 1683055c67edSArnaldo Carvalho de Melo 1684055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PHYS_ADDR) { 1685055c67edSArnaldo Carvalho de Melo *array = sample->phys_addr; 1686055c67edSArnaldo Carvalho de Melo array++; 1687055c67edSArnaldo Carvalho de Melo } 1688055c67edSArnaldo Carvalho de Melo 1689ba78c1c5SNamhyung Kim if (type & PERF_SAMPLE_CGROUP) { 1690ba78c1c5SNamhyung Kim *array = sample->cgroup; 1691ba78c1c5SNamhyung Kim array++; 1692ba78c1c5SNamhyung Kim } 1693ba78c1c5SNamhyung Kim 1694542b88fdSKan Liang if (type & PERF_SAMPLE_DATA_PAGE_SIZE) { 1695542b88fdSKan Liang *array = sample->data_page_size; 1696542b88fdSKan Liang array++; 1697542b88fdSKan Liang } 1698542b88fdSKan Liang 1699c1de7f3dSKan Liang if (type & PERF_SAMPLE_CODE_PAGE_SIZE) { 1700c1de7f3dSKan Liang *array = sample->code_page_size; 1701c1de7f3dSKan Liang array++; 1702c1de7f3dSKan Liang } 1703c1de7f3dSKan Liang 170498dcf14dSAdrian Hunter if (type & PERF_SAMPLE_AUX) { 170598dcf14dSAdrian Hunter sz = sample->aux_sample.size; 170698dcf14dSAdrian Hunter *array++ = sz; 170798dcf14dSAdrian Hunter memcpy(array, sample->aux_sample.data, sz); 170898dcf14dSAdrian Hunter array = (void *)array + sz; 170998dcf14dSAdrian Hunter } 171098dcf14dSAdrian Hunter 1711055c67edSArnaldo Carvalho de Melo return 0; 1712055c67edSArnaldo Carvalho de Melo } 1713055c67edSArnaldo Carvalho de Melo 1714055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, 1715055c67edSArnaldo Carvalho de Melo struct evlist *evlist, struct machine *machine) 1716055c67edSArnaldo Carvalho de Melo { 1717055c67edSArnaldo Carvalho de Melo union perf_event *ev; 1718055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 1719055c67edSArnaldo Carvalho de Melo size_t nr = 0, i = 0, sz, max_nr, n; 1720055c67edSArnaldo Carvalho de Melo int err; 1721055c67edSArnaldo Carvalho de Melo 1722055c67edSArnaldo Carvalho de Melo pr_debug2("Synthesizing id index\n"); 1723055c67edSArnaldo Carvalho de Melo 1724055c67edSArnaldo Carvalho de Melo max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / 1725055c67edSArnaldo Carvalho de Melo sizeof(struct id_index_entry); 1726055c67edSArnaldo Carvalho de Melo 1727055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) 1728e7eb9002SJiri Olsa nr += evsel->core.ids; 1729055c67edSArnaldo Carvalho de Melo 1730055c67edSArnaldo Carvalho de Melo n = nr > max_nr ? max_nr : nr; 1731055c67edSArnaldo Carvalho de Melo sz = sizeof(struct perf_record_id_index) + n * sizeof(struct id_index_entry); 1732055c67edSArnaldo Carvalho de Melo ev = zalloc(sz); 1733055c67edSArnaldo Carvalho de Melo if (!ev) 1734055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1735055c67edSArnaldo Carvalho de Melo 1736055c67edSArnaldo Carvalho de Melo ev->id_index.header.type = PERF_RECORD_ID_INDEX; 1737055c67edSArnaldo Carvalho de Melo ev->id_index.header.size = sz; 1738055c67edSArnaldo Carvalho de Melo ev->id_index.nr = n; 1739055c67edSArnaldo Carvalho de Melo 1740055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) { 1741055c67edSArnaldo Carvalho de Melo u32 j; 1742055c67edSArnaldo Carvalho de Melo 1743e7eb9002SJiri Olsa for (j = 0; j < evsel->core.ids; j++) { 1744055c67edSArnaldo Carvalho de Melo struct id_index_entry *e; 1745055c67edSArnaldo Carvalho de Melo struct perf_sample_id *sid; 1746055c67edSArnaldo Carvalho de Melo 1747055c67edSArnaldo Carvalho de Melo if (i >= n) { 1748055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, machine); 1749055c67edSArnaldo Carvalho de Melo if (err) 1750055c67edSArnaldo Carvalho de Melo goto out_err; 1751055c67edSArnaldo Carvalho de Melo nr -= n; 1752055c67edSArnaldo Carvalho de Melo i = 0; 1753055c67edSArnaldo Carvalho de Melo } 1754055c67edSArnaldo Carvalho de Melo 1755055c67edSArnaldo Carvalho de Melo e = &ev->id_index.entries[i++]; 1756055c67edSArnaldo Carvalho de Melo 1757deaf3219SJiri Olsa e->id = evsel->core.id[j]; 1758055c67edSArnaldo Carvalho de Melo 17593ccf8a7bSArnaldo Carvalho de Melo sid = evlist__id2sid(evlist, e->id); 1760055c67edSArnaldo Carvalho de Melo if (!sid) { 1761055c67edSArnaldo Carvalho de Melo free(ev); 1762055c67edSArnaldo Carvalho de Melo return -ENOENT; 1763055c67edSArnaldo Carvalho de Melo } 1764055c67edSArnaldo Carvalho de Melo 1765055c67edSArnaldo Carvalho de Melo e->idx = sid->idx; 1766*6d18804bSIan Rogers e->cpu = sid->cpu.cpu; 1767055c67edSArnaldo Carvalho de Melo e->tid = sid->tid; 1768055c67edSArnaldo Carvalho de Melo } 1769055c67edSArnaldo Carvalho de Melo } 1770055c67edSArnaldo Carvalho de Melo 1771055c67edSArnaldo Carvalho de Melo sz = sizeof(struct perf_record_id_index) + nr * sizeof(struct id_index_entry); 1772055c67edSArnaldo Carvalho de Melo ev->id_index.header.size = sz; 1773055c67edSArnaldo Carvalho de Melo ev->id_index.nr = nr; 1774055c67edSArnaldo Carvalho de Melo 1775055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, machine); 1776055c67edSArnaldo Carvalho de Melo out_err: 1777055c67edSArnaldo Carvalho de Melo free(ev); 1778055c67edSArnaldo Carvalho de Melo 1779055c67edSArnaldo Carvalho de Melo return err; 1780055c67edSArnaldo Carvalho de Melo } 1781055c67edSArnaldo Carvalho de Melo 1782055c67edSArnaldo Carvalho de Melo int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, 1783055c67edSArnaldo Carvalho de Melo struct target *target, struct perf_thread_map *threads, 178484111b9cSNamhyung Kim perf_event__handler_t process, bool needs_mmap, 178584111b9cSNamhyung Kim bool data_mmap, unsigned int nr_threads_synthesize) 1786055c67edSArnaldo Carvalho de Melo { 1787055c67edSArnaldo Carvalho de Melo if (target__has_task(target)) 178884111b9cSNamhyung Kim return perf_event__synthesize_thread_map(tool, threads, process, machine, 178984111b9cSNamhyung Kim needs_mmap, data_mmap); 1790055c67edSArnaldo Carvalho de Melo else if (target__has_cpu(target)) 179184111b9cSNamhyung Kim return perf_event__synthesize_threads(tool, process, machine, 179284111b9cSNamhyung Kim needs_mmap, data_mmap, 1793055c67edSArnaldo Carvalho de Melo nr_threads_synthesize); 1794055c67edSArnaldo Carvalho de Melo /* command specified */ 1795055c67edSArnaldo Carvalho de Melo return 0; 1796055c67edSArnaldo Carvalho de Melo } 1797055c67edSArnaldo Carvalho de Melo 1798055c67edSArnaldo Carvalho de Melo int machine__synthesize_threads(struct machine *machine, struct target *target, 179984111b9cSNamhyung Kim struct perf_thread_map *threads, bool needs_mmap, 180084111b9cSNamhyung Kim bool data_mmap, unsigned int nr_threads_synthesize) 1801055c67edSArnaldo Carvalho de Melo { 1802055c67edSArnaldo Carvalho de Melo return __machine__synthesize_threads(machine, NULL, target, threads, 180384111b9cSNamhyung Kim perf_event__process, needs_mmap, 180484111b9cSNamhyung Kim data_mmap, nr_threads_synthesize); 1805055c67edSArnaldo Carvalho de Melo } 1806055c67edSArnaldo Carvalho de Melo 1807055c67edSArnaldo Carvalho de Melo static struct perf_record_event_update *event_update_event__new(size_t size, u64 type, u64 id) 1808055c67edSArnaldo Carvalho de Melo { 1809055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1810055c67edSArnaldo Carvalho de Melo 1811055c67edSArnaldo Carvalho de Melo size += sizeof(*ev); 1812055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 1813055c67edSArnaldo Carvalho de Melo 1814055c67edSArnaldo Carvalho de Melo ev = zalloc(size); 1815055c67edSArnaldo Carvalho de Melo if (ev) { 1816055c67edSArnaldo Carvalho de Melo ev->header.type = PERF_RECORD_EVENT_UPDATE; 1817055c67edSArnaldo Carvalho de Melo ev->header.size = (u16)size; 1818055c67edSArnaldo Carvalho de Melo ev->type = type; 1819055c67edSArnaldo Carvalho de Melo ev->id = id; 1820055c67edSArnaldo Carvalho de Melo } 1821055c67edSArnaldo Carvalho de Melo return ev; 1822055c67edSArnaldo Carvalho de Melo } 1823055c67edSArnaldo Carvalho de Melo 1824055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_unit(struct perf_tool *tool, struct evsel *evsel, 1825055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1826055c67edSArnaldo Carvalho de Melo { 1827055c67edSArnaldo Carvalho de Melo size_t size = strlen(evsel->unit); 1828055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1829055c67edSArnaldo Carvalho de Melo int err; 1830055c67edSArnaldo Carvalho de Melo 1831deaf3219SJiri Olsa ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->core.id[0]); 1832055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1833055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1834055c67edSArnaldo Carvalho de Melo 1835055c67edSArnaldo Carvalho de Melo strlcpy(ev->data, evsel->unit, size + 1); 1836055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1837055c67edSArnaldo Carvalho de Melo free(ev); 1838055c67edSArnaldo Carvalho de Melo return err; 1839055c67edSArnaldo Carvalho de Melo } 1840055c67edSArnaldo Carvalho de Melo 1841055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_scale(struct perf_tool *tool, struct evsel *evsel, 1842055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1843055c67edSArnaldo Carvalho de Melo { 1844055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1845055c67edSArnaldo Carvalho de Melo struct perf_record_event_update_scale *ev_data; 1846055c67edSArnaldo Carvalho de Melo int err; 1847055c67edSArnaldo Carvalho de Melo 1848deaf3219SJiri Olsa ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->core.id[0]); 1849055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1850055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1851055c67edSArnaldo Carvalho de Melo 1852055c67edSArnaldo Carvalho de Melo ev_data = (struct perf_record_event_update_scale *)ev->data; 1853055c67edSArnaldo Carvalho de Melo ev_data->scale = evsel->scale; 1854055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1855055c67edSArnaldo Carvalho de Melo free(ev); 1856055c67edSArnaldo Carvalho de Melo return err; 1857055c67edSArnaldo Carvalho de Melo } 1858055c67edSArnaldo Carvalho de Melo 1859055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_name(struct perf_tool *tool, struct evsel *evsel, 1860055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1861055c67edSArnaldo Carvalho de Melo { 1862055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1863055c67edSArnaldo Carvalho de Melo size_t len = strlen(evsel->name); 1864055c67edSArnaldo Carvalho de Melo int err; 1865055c67edSArnaldo Carvalho de Melo 1866deaf3219SJiri Olsa ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->core.id[0]); 1867055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1868055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1869055c67edSArnaldo Carvalho de Melo 1870055c67edSArnaldo Carvalho de Melo strlcpy(ev->data, evsel->name, len + 1); 1871055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1872055c67edSArnaldo Carvalho de Melo free(ev); 1873055c67edSArnaldo Carvalho de Melo return err; 1874055c67edSArnaldo Carvalho de Melo } 1875055c67edSArnaldo Carvalho de Melo 1876055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, struct evsel *evsel, 1877055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1878055c67edSArnaldo Carvalho de Melo { 1879055c67edSArnaldo Carvalho de Melo size_t size = sizeof(struct perf_record_event_update); 1880055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1881055c67edSArnaldo Carvalho de Melo int max, err; 1882055c67edSArnaldo Carvalho de Melo u16 type; 1883055c67edSArnaldo Carvalho de Melo 1884055c67edSArnaldo Carvalho de Melo if (!evsel->core.own_cpus) 1885055c67edSArnaldo Carvalho de Melo return 0; 1886055c67edSArnaldo Carvalho de Melo 1887055c67edSArnaldo Carvalho de Melo ev = cpu_map_data__alloc(evsel->core.own_cpus, &size, &type, &max); 1888055c67edSArnaldo Carvalho de Melo if (!ev) 1889055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1890055c67edSArnaldo Carvalho de Melo 1891055c67edSArnaldo Carvalho de Melo ev->header.type = PERF_RECORD_EVENT_UPDATE; 1892055c67edSArnaldo Carvalho de Melo ev->header.size = (u16)size; 1893055c67edSArnaldo Carvalho de Melo ev->type = PERF_EVENT_UPDATE__CPUS; 1894deaf3219SJiri Olsa ev->id = evsel->core.id[0]; 1895055c67edSArnaldo Carvalho de Melo 1896055c67edSArnaldo Carvalho de Melo cpu_map_data__synthesize((struct perf_record_cpu_map_data *)ev->data, 1897055c67edSArnaldo Carvalho de Melo evsel->core.own_cpus, type, max); 1898055c67edSArnaldo Carvalho de Melo 1899055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1900055c67edSArnaldo Carvalho de Melo free(ev); 1901055c67edSArnaldo Carvalho de Melo return err; 1902055c67edSArnaldo Carvalho de Melo } 1903055c67edSArnaldo Carvalho de Melo 1904055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_attrs(struct perf_tool *tool, struct evlist *evlist, 1905055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1906055c67edSArnaldo Carvalho de Melo { 1907055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 1908055c67edSArnaldo Carvalho de Melo int err = 0; 1909055c67edSArnaldo Carvalho de Melo 1910055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) { 1911e7eb9002SJiri Olsa err = perf_event__synthesize_attr(tool, &evsel->core.attr, evsel->core.ids, 1912deaf3219SJiri Olsa evsel->core.id, process); 1913055c67edSArnaldo Carvalho de Melo if (err) { 1914055c67edSArnaldo Carvalho de Melo pr_debug("failed to create perf header attribute\n"); 1915055c67edSArnaldo Carvalho de Melo return err; 1916055c67edSArnaldo Carvalho de Melo } 1917055c67edSArnaldo Carvalho de Melo } 1918055c67edSArnaldo Carvalho de Melo 1919055c67edSArnaldo Carvalho de Melo return err; 1920055c67edSArnaldo Carvalho de Melo } 1921055c67edSArnaldo Carvalho de Melo 1922055c67edSArnaldo Carvalho de Melo static bool has_unit(struct evsel *evsel) 1923055c67edSArnaldo Carvalho de Melo { 1924055c67edSArnaldo Carvalho de Melo return evsel->unit && *evsel->unit; 1925055c67edSArnaldo Carvalho de Melo } 1926055c67edSArnaldo Carvalho de Melo 1927055c67edSArnaldo Carvalho de Melo static bool has_scale(struct evsel *evsel) 1928055c67edSArnaldo Carvalho de Melo { 1929055c67edSArnaldo Carvalho de Melo return evsel->scale != 1; 1930055c67edSArnaldo Carvalho de Melo } 1931055c67edSArnaldo Carvalho de Melo 1932055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_extra_attr(struct perf_tool *tool, struct evlist *evsel_list, 1933055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, bool is_pipe) 1934055c67edSArnaldo Carvalho de Melo { 1935055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 1936055c67edSArnaldo Carvalho de Melo int err; 1937055c67edSArnaldo Carvalho de Melo 1938055c67edSArnaldo Carvalho de Melo /* 1939055c67edSArnaldo Carvalho de Melo * Synthesize other events stuff not carried within 1940055c67edSArnaldo Carvalho de Melo * attr event - unit, scale, name 1941055c67edSArnaldo Carvalho de Melo */ 1942055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evsel_list, evsel) { 1943055c67edSArnaldo Carvalho de Melo if (!evsel->supported) 1944055c67edSArnaldo Carvalho de Melo continue; 1945055c67edSArnaldo Carvalho de Melo 1946055c67edSArnaldo Carvalho de Melo /* 1947055c67edSArnaldo Carvalho de Melo * Synthesize unit and scale only if it's defined. 1948055c67edSArnaldo Carvalho de Melo */ 1949055c67edSArnaldo Carvalho de Melo if (has_unit(evsel)) { 1950055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_unit(tool, evsel, process); 1951055c67edSArnaldo Carvalho de Melo if (err < 0) { 1952055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel unit.\n"); 1953055c67edSArnaldo Carvalho de Melo return err; 1954055c67edSArnaldo Carvalho de Melo } 1955055c67edSArnaldo Carvalho de Melo } 1956055c67edSArnaldo Carvalho de Melo 1957055c67edSArnaldo Carvalho de Melo if (has_scale(evsel)) { 1958055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_scale(tool, evsel, process); 1959055c67edSArnaldo Carvalho de Melo if (err < 0) { 1960055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel evsel.\n"); 1961055c67edSArnaldo Carvalho de Melo return err; 1962055c67edSArnaldo Carvalho de Melo } 1963055c67edSArnaldo Carvalho de Melo } 1964055c67edSArnaldo Carvalho de Melo 1965055c67edSArnaldo Carvalho de Melo if (evsel->core.own_cpus) { 1966055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_cpus(tool, evsel, process); 1967055c67edSArnaldo Carvalho de Melo if (err < 0) { 1968055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel cpus.\n"); 1969055c67edSArnaldo Carvalho de Melo return err; 1970055c67edSArnaldo Carvalho de Melo } 1971055c67edSArnaldo Carvalho de Melo } 1972055c67edSArnaldo Carvalho de Melo 1973055c67edSArnaldo Carvalho de Melo /* 1974055c67edSArnaldo Carvalho de Melo * Name is needed only for pipe output, 1975055c67edSArnaldo Carvalho de Melo * perf.data carries event names. 1976055c67edSArnaldo Carvalho de Melo */ 1977055c67edSArnaldo Carvalho de Melo if (is_pipe) { 1978055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_name(tool, evsel, process); 1979055c67edSArnaldo Carvalho de Melo if (err < 0) { 1980055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel name.\n"); 1981055c67edSArnaldo Carvalho de Melo return err; 1982055c67edSArnaldo Carvalho de Melo } 1983055c67edSArnaldo Carvalho de Melo } 1984055c67edSArnaldo Carvalho de Melo } 1985055c67edSArnaldo Carvalho de Melo return 0; 1986055c67edSArnaldo Carvalho de Melo } 1987055c67edSArnaldo Carvalho de Melo 1988055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, 1989055c67edSArnaldo Carvalho de Melo u32 ids, u64 *id, perf_event__handler_t process) 1990055c67edSArnaldo Carvalho de Melo { 1991055c67edSArnaldo Carvalho de Melo union perf_event *ev; 1992055c67edSArnaldo Carvalho de Melo size_t size; 1993055c67edSArnaldo Carvalho de Melo int err; 1994055c67edSArnaldo Carvalho de Melo 1995055c67edSArnaldo Carvalho de Melo size = sizeof(struct perf_event_attr); 1996055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 1997055c67edSArnaldo Carvalho de Melo size += sizeof(struct perf_event_header); 1998055c67edSArnaldo Carvalho de Melo size += ids * sizeof(u64); 1999055c67edSArnaldo Carvalho de Melo 2000055c67edSArnaldo Carvalho de Melo ev = zalloc(size); 2001055c67edSArnaldo Carvalho de Melo 2002055c67edSArnaldo Carvalho de Melo if (ev == NULL) 2003055c67edSArnaldo Carvalho de Melo return -ENOMEM; 2004055c67edSArnaldo Carvalho de Melo 2005055c67edSArnaldo Carvalho de Melo ev->attr.attr = *attr; 2006055c67edSArnaldo Carvalho de Melo memcpy(ev->attr.id, id, ids * sizeof(u64)); 2007055c67edSArnaldo Carvalho de Melo 2008055c67edSArnaldo Carvalho de Melo ev->attr.header.type = PERF_RECORD_HEADER_ATTR; 2009055c67edSArnaldo Carvalho de Melo ev->attr.header.size = (u16)size; 2010055c67edSArnaldo Carvalho de Melo 2011055c67edSArnaldo Carvalho de Melo if (ev->attr.header.size == size) 2012055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, NULL); 2013055c67edSArnaldo Carvalho de Melo else 2014055c67edSArnaldo Carvalho de Melo err = -E2BIG; 2015055c67edSArnaldo Carvalho de Melo 2016055c67edSArnaldo Carvalho de Melo free(ev); 2017055c67edSArnaldo Carvalho de Melo 2018055c67edSArnaldo Carvalho de Melo return err; 2019055c67edSArnaldo Carvalho de Melo } 2020055c67edSArnaldo Carvalho de Melo 2021055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct evlist *evlist, 2022055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 2023055c67edSArnaldo Carvalho de Melo { 2024055c67edSArnaldo Carvalho de Melo union perf_event ev; 2025055c67edSArnaldo Carvalho de Melo struct tracing_data *tdata; 2026055c67edSArnaldo Carvalho de Melo ssize_t size = 0, aligned_size = 0, padding; 2027055c67edSArnaldo Carvalho de Melo struct feat_fd ff; 2028055c67edSArnaldo Carvalho de Melo 2029055c67edSArnaldo Carvalho de Melo /* 2030055c67edSArnaldo Carvalho de Melo * We are going to store the size of the data followed 2031055c67edSArnaldo Carvalho de Melo * by the data contents. Since the fd descriptor is a pipe, 2032055c67edSArnaldo Carvalho de Melo * we cannot seek back to store the size of the data once 2033055c67edSArnaldo Carvalho de Melo * we know it. Instead we: 2034055c67edSArnaldo Carvalho de Melo * 2035055c67edSArnaldo Carvalho de Melo * - write the tracing data to the temp file 2036055c67edSArnaldo Carvalho de Melo * - get/write the data size to pipe 2037055c67edSArnaldo Carvalho de Melo * - write the tracing data from the temp file 2038055c67edSArnaldo Carvalho de Melo * to the pipe 2039055c67edSArnaldo Carvalho de Melo */ 2040055c67edSArnaldo Carvalho de Melo tdata = tracing_data_get(&evlist->core.entries, fd, true); 2041055c67edSArnaldo Carvalho de Melo if (!tdata) 2042055c67edSArnaldo Carvalho de Melo return -1; 2043055c67edSArnaldo Carvalho de Melo 2044055c67edSArnaldo Carvalho de Melo memset(&ev, 0, sizeof(ev)); 2045055c67edSArnaldo Carvalho de Melo 2046055c67edSArnaldo Carvalho de Melo ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 2047055c67edSArnaldo Carvalho de Melo size = tdata->size; 2048055c67edSArnaldo Carvalho de Melo aligned_size = PERF_ALIGN(size, sizeof(u64)); 2049055c67edSArnaldo Carvalho de Melo padding = aligned_size - size; 2050055c67edSArnaldo Carvalho de Melo ev.tracing_data.header.size = sizeof(ev.tracing_data); 2051055c67edSArnaldo Carvalho de Melo ev.tracing_data.size = aligned_size; 2052055c67edSArnaldo Carvalho de Melo 2053055c67edSArnaldo Carvalho de Melo process(tool, &ev, NULL, NULL); 2054055c67edSArnaldo Carvalho de Melo 2055055c67edSArnaldo Carvalho de Melo /* 2056055c67edSArnaldo Carvalho de Melo * The put function will copy all the tracing data 2057055c67edSArnaldo Carvalho de Melo * stored in temp file to the pipe. 2058055c67edSArnaldo Carvalho de Melo */ 2059055c67edSArnaldo Carvalho de Melo tracing_data_put(tdata); 2060055c67edSArnaldo Carvalho de Melo 2061055c67edSArnaldo Carvalho de Melo ff = (struct feat_fd){ .fd = fd }; 2062055c67edSArnaldo Carvalho de Melo if (write_padded(&ff, NULL, 0, padding)) 2063055c67edSArnaldo Carvalho de Melo return -1; 2064055c67edSArnaldo Carvalho de Melo 2065055c67edSArnaldo Carvalho de Melo return aligned_size; 2066055c67edSArnaldo Carvalho de Melo } 2067055c67edSArnaldo Carvalho de Melo 2068055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_build_id(struct perf_tool *tool, struct dso *pos, u16 misc, 2069055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, struct machine *machine) 2070055c67edSArnaldo Carvalho de Melo { 2071055c67edSArnaldo Carvalho de Melo union perf_event ev; 2072055c67edSArnaldo Carvalho de Melo size_t len; 2073055c67edSArnaldo Carvalho de Melo 2074055c67edSArnaldo Carvalho de Melo if (!pos->hit) 2075055c67edSArnaldo Carvalho de Melo return 0; 2076055c67edSArnaldo Carvalho de Melo 2077055c67edSArnaldo Carvalho de Melo memset(&ev, 0, sizeof(ev)); 2078055c67edSArnaldo Carvalho de Melo 2079055c67edSArnaldo Carvalho de Melo len = pos->long_name_len + 1; 2080055c67edSArnaldo Carvalho de Melo len = PERF_ALIGN(len, NAME_ALIGN); 20810aba7f03SJiri Olsa memcpy(&ev.build_id.build_id, pos->bid.data, sizeof(pos->bid.data)); 2082055c67edSArnaldo Carvalho de Melo ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; 2083055c67edSArnaldo Carvalho de Melo ev.build_id.header.misc = misc; 2084055c67edSArnaldo Carvalho de Melo ev.build_id.pid = machine->pid; 2085055c67edSArnaldo Carvalho de Melo ev.build_id.header.size = sizeof(ev.build_id) + len; 2086055c67edSArnaldo Carvalho de Melo memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); 2087055c67edSArnaldo Carvalho de Melo 2088055c67edSArnaldo Carvalho de Melo return process(tool, &ev, NULL, machine); 2089055c67edSArnaldo Carvalho de Melo } 2090055c67edSArnaldo Carvalho de Melo 2091055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_events(struct perf_stat_config *config, struct perf_tool *tool, 2092055c67edSArnaldo Carvalho de Melo struct evlist *evlist, perf_event__handler_t process, bool attrs) 2093055c67edSArnaldo Carvalho de Melo { 2094055c67edSArnaldo Carvalho de Melo int err; 2095055c67edSArnaldo Carvalho de Melo 2096055c67edSArnaldo Carvalho de Melo if (attrs) { 2097055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_attrs(tool, evlist, process); 2098055c67edSArnaldo Carvalho de Melo if (err < 0) { 2099055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize attrs.\n"); 2100055c67edSArnaldo Carvalho de Melo return err; 2101055c67edSArnaldo Carvalho de Melo } 2102055c67edSArnaldo Carvalho de Melo } 2103055c67edSArnaldo Carvalho de Melo 2104055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_extra_attr(tool, evlist, process, attrs); 2105055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_thread_map2(tool, evlist->core.threads, process, NULL); 2106055c67edSArnaldo Carvalho de Melo if (err < 0) { 2107055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize thread map.\n"); 2108055c67edSArnaldo Carvalho de Melo return err; 2109055c67edSArnaldo Carvalho de Melo } 2110055c67edSArnaldo Carvalho de Melo 2111055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_cpu_map(tool, evlist->core.cpus, process, NULL); 2112055c67edSArnaldo Carvalho de Melo if (err < 0) { 2113055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize thread map.\n"); 2114055c67edSArnaldo Carvalho de Melo return err; 2115055c67edSArnaldo Carvalho de Melo } 2116055c67edSArnaldo Carvalho de Melo 2117055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_stat_config(tool, config, process, NULL); 2118055c67edSArnaldo Carvalho de Melo if (err < 0) { 2119055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize config.\n"); 2120055c67edSArnaldo Carvalho de Melo return err; 2121055c67edSArnaldo Carvalho de Melo } 2122055c67edSArnaldo Carvalho de Melo 2123055c67edSArnaldo Carvalho de Melo return 0; 2124055c67edSArnaldo Carvalho de Melo } 2125055c67edSArnaldo Carvalho de Melo 2126055c67edSArnaldo Carvalho de Melo extern const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE]; 2127055c67edSArnaldo Carvalho de Melo 2128055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, 2129055c67edSArnaldo Carvalho de Melo struct evlist *evlist, perf_event__handler_t process) 2130055c67edSArnaldo Carvalho de Melo { 2131055c67edSArnaldo Carvalho de Melo struct perf_header *header = &session->header; 2132055c67edSArnaldo Carvalho de Melo struct perf_record_header_feature *fe; 2133055c67edSArnaldo Carvalho de Melo struct feat_fd ff; 2134055c67edSArnaldo Carvalho de Melo size_t sz, sz_hdr; 2135055c67edSArnaldo Carvalho de Melo int feat, ret; 2136055c67edSArnaldo Carvalho de Melo 2137055c67edSArnaldo Carvalho de Melo sz_hdr = sizeof(fe->header); 2138055c67edSArnaldo Carvalho de Melo sz = sizeof(union perf_event); 2139055c67edSArnaldo Carvalho de Melo /* get a nice alignment */ 2140055c67edSArnaldo Carvalho de Melo sz = PERF_ALIGN(sz, page_size); 2141055c67edSArnaldo Carvalho de Melo 2142055c67edSArnaldo Carvalho de Melo memset(&ff, 0, sizeof(ff)); 2143055c67edSArnaldo Carvalho de Melo 2144055c67edSArnaldo Carvalho de Melo ff.buf = malloc(sz); 2145055c67edSArnaldo Carvalho de Melo if (!ff.buf) 2146055c67edSArnaldo Carvalho de Melo return -ENOMEM; 2147055c67edSArnaldo Carvalho de Melo 2148055c67edSArnaldo Carvalho de Melo ff.size = sz - sz_hdr; 2149055c67edSArnaldo Carvalho de Melo ff.ph = &session->header; 2150055c67edSArnaldo Carvalho de Melo 2151055c67edSArnaldo Carvalho de Melo for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { 2152055c67edSArnaldo Carvalho de Melo if (!feat_ops[feat].synthesize) { 2153055c67edSArnaldo Carvalho de Melo pr_debug("No record header feature for header :%d\n", feat); 2154055c67edSArnaldo Carvalho de Melo continue; 2155055c67edSArnaldo Carvalho de Melo } 2156055c67edSArnaldo Carvalho de Melo 2157055c67edSArnaldo Carvalho de Melo ff.offset = sizeof(*fe); 2158055c67edSArnaldo Carvalho de Melo 2159055c67edSArnaldo Carvalho de Melo ret = feat_ops[feat].write(&ff, evlist); 2160055c67edSArnaldo Carvalho de Melo if (ret || ff.offset <= (ssize_t)sizeof(*fe)) { 2161055c67edSArnaldo Carvalho de Melo pr_debug("Error writing feature\n"); 2162055c67edSArnaldo Carvalho de Melo continue; 2163055c67edSArnaldo Carvalho de Melo } 2164055c67edSArnaldo Carvalho de Melo /* ff.buf may have changed due to realloc in do_write() */ 2165055c67edSArnaldo Carvalho de Melo fe = ff.buf; 2166055c67edSArnaldo Carvalho de Melo memset(fe, 0, sizeof(*fe)); 2167055c67edSArnaldo Carvalho de Melo 2168055c67edSArnaldo Carvalho de Melo fe->feat_id = feat; 2169055c67edSArnaldo Carvalho de Melo fe->header.type = PERF_RECORD_HEADER_FEATURE; 2170055c67edSArnaldo Carvalho de Melo fe->header.size = ff.offset; 2171055c67edSArnaldo Carvalho de Melo 2172055c67edSArnaldo Carvalho de Melo ret = process(tool, ff.buf, NULL, NULL); 2173055c67edSArnaldo Carvalho de Melo if (ret) { 2174055c67edSArnaldo Carvalho de Melo free(ff.buf); 2175055c67edSArnaldo Carvalho de Melo return ret; 2176055c67edSArnaldo Carvalho de Melo } 2177055c67edSArnaldo Carvalho de Melo } 2178055c67edSArnaldo Carvalho de Melo 2179055c67edSArnaldo Carvalho de Melo /* Send HEADER_LAST_FEATURE mark. */ 2180055c67edSArnaldo Carvalho de Melo fe = ff.buf; 2181055c67edSArnaldo Carvalho de Melo fe->feat_id = HEADER_LAST_FEATURE; 2182055c67edSArnaldo Carvalho de Melo fe->header.type = PERF_RECORD_HEADER_FEATURE; 2183055c67edSArnaldo Carvalho de Melo fe->header.size = sizeof(*fe); 2184055c67edSArnaldo Carvalho de Melo 2185055c67edSArnaldo Carvalho de Melo ret = process(tool, ff.buf, NULL, NULL); 2186055c67edSArnaldo Carvalho de Melo 2187055c67edSArnaldo Carvalho de Melo free(ff.buf); 2188055c67edSArnaldo Carvalho de Melo return ret; 2189055c67edSArnaldo Carvalho de Melo } 2190c3a057dcSNamhyung Kim 2191c3a057dcSNamhyung Kim int perf_event__synthesize_for_pipe(struct perf_tool *tool, 2192c3a057dcSNamhyung Kim struct perf_session *session, 2193c3a057dcSNamhyung Kim struct perf_data *data, 2194c3a057dcSNamhyung Kim perf_event__handler_t process) 2195c3a057dcSNamhyung Kim { 2196c3a057dcSNamhyung Kim int err; 2197c3a057dcSNamhyung Kim int ret = 0; 2198c3a057dcSNamhyung Kim struct evlist *evlist = session->evlist; 2199c3a057dcSNamhyung Kim 2200c3a057dcSNamhyung Kim /* 2201c3a057dcSNamhyung Kim * We need to synthesize events first, because some 2202c3a057dcSNamhyung Kim * features works on top of them (on report side). 2203c3a057dcSNamhyung Kim */ 2204c3a057dcSNamhyung Kim err = perf_event__synthesize_attrs(tool, evlist, process); 2205c3a057dcSNamhyung Kim if (err < 0) { 2206c3a057dcSNamhyung Kim pr_err("Couldn't synthesize attrs.\n"); 2207c3a057dcSNamhyung Kim return err; 2208c3a057dcSNamhyung Kim } 2209c3a057dcSNamhyung Kim ret += err; 2210c3a057dcSNamhyung Kim 2211c3a057dcSNamhyung Kim err = perf_event__synthesize_features(tool, session, evlist, process); 2212c3a057dcSNamhyung Kim if (err < 0) { 2213c3a057dcSNamhyung Kim pr_err("Couldn't synthesize features.\n"); 2214c3a057dcSNamhyung Kim return err; 2215c3a057dcSNamhyung Kim } 2216c3a057dcSNamhyung Kim ret += err; 2217c3a057dcSNamhyung Kim 2218c3a057dcSNamhyung Kim if (have_tracepoints(&evlist->core.entries)) { 2219c3a057dcSNamhyung Kim int fd = perf_data__fd(data); 2220c3a057dcSNamhyung Kim 2221c3a057dcSNamhyung Kim /* 2222c3a057dcSNamhyung Kim * FIXME err <= 0 here actually means that 2223c3a057dcSNamhyung Kim * there were no tracepoints so its not really 2224c3a057dcSNamhyung Kim * an error, just that we don't need to 2225c3a057dcSNamhyung Kim * synthesize anything. We really have to 2226c3a057dcSNamhyung Kim * return this more properly and also 2227c3a057dcSNamhyung Kim * propagate errors that now are calling die() 2228c3a057dcSNamhyung Kim */ 2229c3a057dcSNamhyung Kim err = perf_event__synthesize_tracing_data(tool, fd, evlist, 2230c3a057dcSNamhyung Kim process); 2231c3a057dcSNamhyung Kim if (err <= 0) { 2232c3a057dcSNamhyung Kim pr_err("Couldn't record tracing data.\n"); 2233c3a057dcSNamhyung Kim return err; 2234c3a057dcSNamhyung Kim } 2235c3a057dcSNamhyung Kim ret += err; 2236c3a057dcSNamhyung Kim } 2237c3a057dcSNamhyung Kim 2238c3a057dcSNamhyung Kim return ret; 2239c3a057dcSNamhyung Kim } 224041b740b6SNamhyung Kim 224141b740b6SNamhyung Kim int parse_synth_opt(char *synth) 224241b740b6SNamhyung Kim { 224341b740b6SNamhyung Kim char *p, *q; 224441b740b6SNamhyung Kim int ret = 0; 224541b740b6SNamhyung Kim 224641b740b6SNamhyung Kim if (synth == NULL) 224741b740b6SNamhyung Kim return -1; 224841b740b6SNamhyung Kim 224941b740b6SNamhyung Kim for (q = synth; (p = strsep(&q, ",")); p = q) { 225041b740b6SNamhyung Kim if (!strcasecmp(p, "no") || !strcasecmp(p, "none")) 225141b740b6SNamhyung Kim return 0; 225241b740b6SNamhyung Kim 225341b740b6SNamhyung Kim if (!strcasecmp(p, "all")) 225441b740b6SNamhyung Kim return PERF_SYNTH_ALL; 225541b740b6SNamhyung Kim 225641b740b6SNamhyung Kim if (!strcasecmp(p, "task")) 225741b740b6SNamhyung Kim ret |= PERF_SYNTH_TASK; 225841b740b6SNamhyung Kim else if (!strcasecmp(p, "mmap")) 225941b740b6SNamhyung Kim ret |= PERF_SYNTH_TASK | PERF_SYNTH_MMAP; 226041b740b6SNamhyung Kim else if (!strcasecmp(p, "cgroup")) 226141b740b6SNamhyung Kim ret |= PERF_SYNTH_CGROUP; 226241b740b6SNamhyung Kim else 226341b740b6SNamhyung Kim return -1; 226441b740b6SNamhyung Kim } 226541b740b6SNamhyung Kim 226641b740b6SNamhyung Kim return ret; 226741b740b6SNamhyung Kim } 2268