1055c67edSArnaldo Carvalho de Melo // SPDX-License-Identifier: GPL-2.0-only 2055c67edSArnaldo Carvalho de Melo 3055c67edSArnaldo Carvalho de Melo #include "util/debug.h" 4055c67edSArnaldo Carvalho de Melo #include "util/dso.h" 5055c67edSArnaldo Carvalho de Melo #include "util/event.h" 6055c67edSArnaldo Carvalho de Melo #include "util/evlist.h" 7055c67edSArnaldo Carvalho de Melo #include "util/machine.h" 8055c67edSArnaldo Carvalho de Melo #include "util/map.h" 9055c67edSArnaldo Carvalho de Melo #include "util/map_symbol.h" 10055c67edSArnaldo Carvalho de Melo #include "util/branch.h" 11055c67edSArnaldo Carvalho de Melo #include "util/memswap.h" 12055c67edSArnaldo Carvalho de Melo #include "util/namespaces.h" 13055c67edSArnaldo Carvalho de Melo #include "util/session.h" 14055c67edSArnaldo Carvalho de Melo #include "util/stat.h" 15055c67edSArnaldo Carvalho de Melo #include "util/symbol.h" 16055c67edSArnaldo Carvalho de Melo #include "util/synthetic-events.h" 17055c67edSArnaldo Carvalho de Melo #include "util/target.h" 18055c67edSArnaldo Carvalho de Melo #include "util/time-utils.h" 19ab64069fSNamhyung Kim #include "util/cgroup.h" 20055c67edSArnaldo Carvalho de Melo #include <linux/bitops.h> 21055c67edSArnaldo Carvalho de Melo #include <linux/kernel.h> 22055c67edSArnaldo Carvalho de Melo #include <linux/string.h> 23055c67edSArnaldo Carvalho de Melo #include <linux/zalloc.h> 24055c67edSArnaldo Carvalho de Melo #include <linux/perf_event.h> 25055c67edSArnaldo Carvalho de Melo #include <asm/bug.h> 26055c67edSArnaldo Carvalho de Melo #include <perf/evsel.h> 27055c67edSArnaldo Carvalho de Melo #include <internal/cpumap.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 */ 72055c67edSArnaldo Carvalho de Melo static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len, 73055c67edSArnaldo Carvalho de Melo pid_t *tgid, pid_t *ppid) 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; 79055c67edSArnaldo Carvalho de Melo char *name, *tgids, *ppids; 80055c67edSArnaldo Carvalho de Melo 81055c67edSArnaldo Carvalho de Melo *tgid = -1; 82055c67edSArnaldo Carvalho de Melo *ppid = -1; 83055c67edSArnaldo Carvalho de Melo 8404ed4ccbSIan Rogers snprintf(bf, sizeof(bf), "/proc/%d/status", pid); 85055c67edSArnaldo Carvalho de Melo 8604ed4ccbSIan Rogers fd = open(bf, O_RDONLY); 87055c67edSArnaldo Carvalho de Melo if (fd < 0) { 8804ed4ccbSIan Rogers pr_debug("couldn't open %s\n", bf); 89055c67edSArnaldo Carvalho de Melo return -1; 90055c67edSArnaldo Carvalho de Melo } 91055c67edSArnaldo Carvalho de Melo 92055c67edSArnaldo Carvalho de Melo n = read(fd, bf, sizeof(bf) - 1); 93055c67edSArnaldo Carvalho de Melo close(fd); 94055c67edSArnaldo Carvalho de Melo if (n <= 0) { 95055c67edSArnaldo Carvalho de Melo pr_warning("Couldn't get COMM, tigd and ppid for pid %d\n", 96055c67edSArnaldo Carvalho de Melo pid); 97055c67edSArnaldo Carvalho de Melo return -1; 98055c67edSArnaldo Carvalho de Melo } 99055c67edSArnaldo Carvalho de Melo bf[n] = '\0'; 100055c67edSArnaldo Carvalho de Melo 101055c67edSArnaldo Carvalho de Melo name = strstr(bf, "Name:"); 102055c67edSArnaldo Carvalho de Melo tgids = strstr(bf, "Tgid:"); 103055c67edSArnaldo Carvalho de Melo ppids = strstr(bf, "PPid:"); 104055c67edSArnaldo Carvalho de Melo 105055c67edSArnaldo Carvalho de Melo if (name) { 106055c67edSArnaldo Carvalho de Melo char *nl; 107055c67edSArnaldo Carvalho de Melo 108055c67edSArnaldo Carvalho de Melo name = skip_spaces(name + 5); /* strlen("Name:") */ 109055c67edSArnaldo Carvalho de Melo nl = strchr(name, '\n'); 110055c67edSArnaldo Carvalho de Melo if (nl) 111055c67edSArnaldo Carvalho de Melo *nl = '\0'; 112055c67edSArnaldo Carvalho de Melo 113055c67edSArnaldo Carvalho de Melo size = strlen(name); 114055c67edSArnaldo Carvalho de Melo if (size >= len) 115055c67edSArnaldo Carvalho de Melo size = len - 1; 116055c67edSArnaldo Carvalho de Melo memcpy(comm, name, size); 117055c67edSArnaldo Carvalho de Melo comm[size] = '\0'; 118055c67edSArnaldo Carvalho de Melo } else { 119055c67edSArnaldo Carvalho de Melo pr_debug("Name: string not found for pid %d\n", pid); 120055c67edSArnaldo Carvalho de Melo } 121055c67edSArnaldo Carvalho de Melo 122055c67edSArnaldo Carvalho de Melo if (tgids) { 123055c67edSArnaldo Carvalho de Melo tgids += 5; /* strlen("Tgid:") */ 124055c67edSArnaldo Carvalho de Melo *tgid = atoi(tgids); 125055c67edSArnaldo Carvalho de Melo } else { 126055c67edSArnaldo Carvalho de Melo pr_debug("Tgid: string not found for pid %d\n", pid); 127055c67edSArnaldo Carvalho de Melo } 128055c67edSArnaldo Carvalho de Melo 129055c67edSArnaldo Carvalho de Melo if (ppids) { 130055c67edSArnaldo Carvalho de Melo ppids += 5; /* strlen("PPid:") */ 131055c67edSArnaldo Carvalho de Melo *ppid = atoi(ppids); 132055c67edSArnaldo Carvalho de Melo } else { 133055c67edSArnaldo Carvalho de Melo pr_debug("PPid: string not found for pid %d\n", pid); 134055c67edSArnaldo Carvalho de Melo } 135055c67edSArnaldo Carvalho de Melo 136055c67edSArnaldo Carvalho de Melo return 0; 137055c67edSArnaldo Carvalho de Melo } 138055c67edSArnaldo Carvalho de Melo 139055c67edSArnaldo Carvalho de Melo static int perf_event__prepare_comm(union perf_event *event, pid_t pid, 140055c67edSArnaldo Carvalho de Melo struct machine *machine, 141055c67edSArnaldo Carvalho de Melo pid_t *tgid, pid_t *ppid) 142055c67edSArnaldo Carvalho de Melo { 143055c67edSArnaldo Carvalho de Melo size_t size; 144055c67edSArnaldo Carvalho de Melo 145055c67edSArnaldo Carvalho de Melo *ppid = -1; 146055c67edSArnaldo Carvalho de Melo 147055c67edSArnaldo Carvalho de Melo memset(&event->comm, 0, sizeof(event->comm)); 148055c67edSArnaldo Carvalho de Melo 149055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) { 150055c67edSArnaldo Carvalho de Melo if (perf_event__get_comm_ids(pid, event->comm.comm, 151055c67edSArnaldo Carvalho de Melo sizeof(event->comm.comm), 152055c67edSArnaldo Carvalho de Melo tgid, ppid) != 0) { 153055c67edSArnaldo Carvalho de Melo return -1; 154055c67edSArnaldo Carvalho de Melo } 155055c67edSArnaldo Carvalho de Melo } else { 156055c67edSArnaldo Carvalho de Melo *tgid = machine->pid; 157055c67edSArnaldo Carvalho de Melo } 158055c67edSArnaldo Carvalho de Melo 159055c67edSArnaldo Carvalho de Melo if (*tgid < 0) 160055c67edSArnaldo Carvalho de Melo return -1; 161055c67edSArnaldo Carvalho de Melo 162055c67edSArnaldo Carvalho de Melo event->comm.pid = *tgid; 163055c67edSArnaldo Carvalho de Melo event->comm.header.type = PERF_RECORD_COMM; 164055c67edSArnaldo Carvalho de Melo 165055c67edSArnaldo Carvalho de Melo size = strlen(event->comm.comm) + 1; 166055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 167055c67edSArnaldo Carvalho de Melo memset(event->comm.comm + size, 0, machine->id_hdr_size); 168055c67edSArnaldo Carvalho de Melo event->comm.header.size = (sizeof(event->comm) - 169055c67edSArnaldo Carvalho de Melo (sizeof(event->comm.comm) - size) + 170055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 171055c67edSArnaldo Carvalho de Melo event->comm.tid = pid; 172055c67edSArnaldo Carvalho de Melo 173055c67edSArnaldo Carvalho de Melo return 0; 174055c67edSArnaldo Carvalho de Melo } 175055c67edSArnaldo Carvalho de Melo 176055c67edSArnaldo Carvalho de Melo pid_t perf_event__synthesize_comm(struct perf_tool *tool, 177055c67edSArnaldo Carvalho de Melo union perf_event *event, pid_t pid, 178055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 179055c67edSArnaldo Carvalho de Melo struct machine *machine) 180055c67edSArnaldo Carvalho de Melo { 181055c67edSArnaldo Carvalho de Melo pid_t tgid, ppid; 182055c67edSArnaldo Carvalho de Melo 183055c67edSArnaldo Carvalho de Melo if (perf_event__prepare_comm(event, pid, machine, &tgid, &ppid) != 0) 184055c67edSArnaldo Carvalho de Melo return -1; 185055c67edSArnaldo Carvalho de Melo 186055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) 187055c67edSArnaldo Carvalho de Melo return -1; 188055c67edSArnaldo Carvalho de Melo 189055c67edSArnaldo Carvalho de Melo return tgid; 190055c67edSArnaldo Carvalho de Melo } 191055c67edSArnaldo Carvalho de Melo 192055c67edSArnaldo Carvalho de Melo static void perf_event__get_ns_link_info(pid_t pid, const char *ns, 193055c67edSArnaldo Carvalho de Melo struct perf_ns_link_info *ns_link_info) 194055c67edSArnaldo Carvalho de Melo { 195055c67edSArnaldo Carvalho de Melo struct stat64 st; 196055c67edSArnaldo Carvalho de Melo char proc_ns[128]; 197055c67edSArnaldo Carvalho de Melo 198055c67edSArnaldo Carvalho de Melo sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns); 199055c67edSArnaldo Carvalho de Melo if (stat64(proc_ns, &st) == 0) { 200055c67edSArnaldo Carvalho de Melo ns_link_info->dev = st.st_dev; 201055c67edSArnaldo Carvalho de Melo ns_link_info->ino = st.st_ino; 202055c67edSArnaldo Carvalho de Melo } 203055c67edSArnaldo Carvalho de Melo } 204055c67edSArnaldo Carvalho de Melo 205055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_namespaces(struct perf_tool *tool, 206055c67edSArnaldo Carvalho de Melo union perf_event *event, 207055c67edSArnaldo Carvalho de Melo pid_t pid, pid_t tgid, 208055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 209055c67edSArnaldo Carvalho de Melo struct machine *machine) 210055c67edSArnaldo Carvalho de Melo { 211055c67edSArnaldo Carvalho de Melo u32 idx; 212055c67edSArnaldo Carvalho de Melo struct perf_ns_link_info *ns_link_info; 213055c67edSArnaldo Carvalho de Melo 214055c67edSArnaldo Carvalho de Melo if (!tool || !tool->namespace_events) 215055c67edSArnaldo Carvalho de Melo return 0; 216055c67edSArnaldo Carvalho de Melo 217055c67edSArnaldo Carvalho de Melo memset(&event->namespaces, 0, (sizeof(event->namespaces) + 218055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 219055c67edSArnaldo Carvalho de Melo machine->id_hdr_size)); 220055c67edSArnaldo Carvalho de Melo 221055c67edSArnaldo Carvalho de Melo event->namespaces.pid = tgid; 222055c67edSArnaldo Carvalho de Melo event->namespaces.tid = pid; 223055c67edSArnaldo Carvalho de Melo 224055c67edSArnaldo Carvalho de Melo event->namespaces.nr_namespaces = NR_NAMESPACES; 225055c67edSArnaldo Carvalho de Melo 226055c67edSArnaldo Carvalho de Melo ns_link_info = event->namespaces.link_info; 227055c67edSArnaldo Carvalho de Melo 228055c67edSArnaldo Carvalho de Melo for (idx = 0; idx < event->namespaces.nr_namespaces; idx++) 229055c67edSArnaldo Carvalho de Melo perf_event__get_ns_link_info(pid, perf_ns__name(idx), 230055c67edSArnaldo Carvalho de Melo &ns_link_info[idx]); 231055c67edSArnaldo Carvalho de Melo 232055c67edSArnaldo Carvalho de Melo event->namespaces.header.type = PERF_RECORD_NAMESPACES; 233055c67edSArnaldo Carvalho de Melo 234055c67edSArnaldo Carvalho de Melo event->namespaces.header.size = (sizeof(event->namespaces) + 235055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 236055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 237055c67edSArnaldo Carvalho de Melo 238055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) 239055c67edSArnaldo Carvalho de Melo return -1; 240055c67edSArnaldo Carvalho de Melo 241055c67edSArnaldo Carvalho de Melo return 0; 242055c67edSArnaldo Carvalho de Melo } 243055c67edSArnaldo Carvalho de Melo 244055c67edSArnaldo Carvalho de Melo static int perf_event__synthesize_fork(struct perf_tool *tool, 245055c67edSArnaldo Carvalho de Melo union perf_event *event, 246055c67edSArnaldo Carvalho de Melo pid_t pid, pid_t tgid, pid_t ppid, 247055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 248055c67edSArnaldo Carvalho de Melo struct machine *machine) 249055c67edSArnaldo Carvalho de Melo { 250055c67edSArnaldo Carvalho de Melo memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size); 251055c67edSArnaldo Carvalho de Melo 252055c67edSArnaldo Carvalho de Melo /* 253055c67edSArnaldo Carvalho de Melo * for main thread set parent to ppid from status file. For other 254055c67edSArnaldo Carvalho de Melo * threads set parent pid to main thread. ie., assume main thread 255055c67edSArnaldo Carvalho de Melo * spawns all threads in a process 256055c67edSArnaldo Carvalho de Melo */ 257055c67edSArnaldo Carvalho de Melo if (tgid == pid) { 258055c67edSArnaldo Carvalho de Melo event->fork.ppid = ppid; 259055c67edSArnaldo Carvalho de Melo event->fork.ptid = ppid; 260055c67edSArnaldo Carvalho de Melo } else { 261055c67edSArnaldo Carvalho de Melo event->fork.ppid = tgid; 262055c67edSArnaldo Carvalho de Melo event->fork.ptid = tgid; 263055c67edSArnaldo Carvalho de Melo } 264055c67edSArnaldo Carvalho de Melo event->fork.pid = tgid; 265055c67edSArnaldo Carvalho de Melo event->fork.tid = pid; 266055c67edSArnaldo Carvalho de Melo event->fork.header.type = PERF_RECORD_FORK; 267055c67edSArnaldo Carvalho de Melo event->fork.header.misc = PERF_RECORD_MISC_FORK_EXEC; 268055c67edSArnaldo Carvalho de Melo 269055c67edSArnaldo Carvalho de Melo event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); 270055c67edSArnaldo Carvalho de Melo 271055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) 272055c67edSArnaldo Carvalho de Melo return -1; 273055c67edSArnaldo Carvalho de Melo 274055c67edSArnaldo Carvalho de Melo return 0; 275055c67edSArnaldo Carvalho de Melo } 276055c67edSArnaldo Carvalho de Melo 2772069425eSIan Rogers static bool read_proc_maps_line(struct io *io, __u64 *start, __u64 *end, 2782069425eSIan Rogers u32 *prot, u32 *flags, __u64 *offset, 2792069425eSIan Rogers u32 *maj, u32 *min, 2802069425eSIan Rogers __u64 *inode, 2812069425eSIan Rogers ssize_t pathname_size, char *pathname) 2822069425eSIan Rogers { 2832069425eSIan Rogers __u64 temp; 2842069425eSIan Rogers int ch; 2852069425eSIan Rogers char *start_pathname = pathname; 2862069425eSIan Rogers 2872069425eSIan Rogers if (io__get_hex(io, start) != '-') 2882069425eSIan Rogers return false; 2892069425eSIan Rogers if (io__get_hex(io, end) != ' ') 2902069425eSIan Rogers return false; 2912069425eSIan Rogers 2922069425eSIan Rogers /* map protection and flags bits */ 2932069425eSIan Rogers *prot = 0; 2942069425eSIan Rogers ch = io__get_char(io); 2952069425eSIan Rogers if (ch == 'r') 2962069425eSIan Rogers *prot |= PROT_READ; 2972069425eSIan Rogers else if (ch != '-') 2982069425eSIan Rogers return false; 2992069425eSIan Rogers ch = io__get_char(io); 3002069425eSIan Rogers if (ch == 'w') 3012069425eSIan Rogers *prot |= PROT_WRITE; 3022069425eSIan Rogers else if (ch != '-') 3032069425eSIan Rogers return false; 3042069425eSIan Rogers ch = io__get_char(io); 3052069425eSIan Rogers if (ch == 'x') 3062069425eSIan Rogers *prot |= PROT_EXEC; 3072069425eSIan Rogers else if (ch != '-') 3082069425eSIan Rogers return false; 3092069425eSIan Rogers ch = io__get_char(io); 3102069425eSIan Rogers if (ch == 's') 3112069425eSIan Rogers *flags = MAP_SHARED; 3122069425eSIan Rogers else if (ch == 'p') 3132069425eSIan Rogers *flags = MAP_PRIVATE; 3142069425eSIan Rogers else 3152069425eSIan Rogers return false; 3162069425eSIan Rogers if (io__get_char(io) != ' ') 3172069425eSIan Rogers return false; 3182069425eSIan Rogers 3192069425eSIan Rogers if (io__get_hex(io, offset) != ' ') 3202069425eSIan Rogers return false; 3212069425eSIan Rogers 3222069425eSIan Rogers if (io__get_hex(io, &temp) != ':') 3232069425eSIan Rogers return false; 3242069425eSIan Rogers *maj = temp; 3252069425eSIan Rogers if (io__get_hex(io, &temp) != ' ') 3262069425eSIan Rogers return false; 3272069425eSIan Rogers *min = temp; 3282069425eSIan Rogers 3292069425eSIan Rogers ch = io__get_dec(io, inode); 3302069425eSIan Rogers if (ch != ' ') { 3312069425eSIan Rogers *pathname = '\0'; 3322069425eSIan Rogers return ch == '\n'; 3332069425eSIan Rogers } 3342069425eSIan Rogers do { 3352069425eSIan Rogers ch = io__get_char(io); 3362069425eSIan Rogers } while (ch == ' '); 3372069425eSIan Rogers while (true) { 3382069425eSIan Rogers if (ch < 0) 3392069425eSIan Rogers return false; 3402069425eSIan Rogers if (ch == '\0' || ch == '\n' || 3412069425eSIan Rogers (pathname + 1 - start_pathname) >= pathname_size) { 3422069425eSIan Rogers *pathname = '\0'; 3432069425eSIan Rogers return true; 3442069425eSIan Rogers } 3452069425eSIan Rogers *pathname++ = ch; 3462069425eSIan Rogers ch = io__get_char(io); 3472069425eSIan Rogers } 3482069425eSIan Rogers } 3492069425eSIan Rogers 350055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_mmap_events(struct perf_tool *tool, 351055c67edSArnaldo Carvalho de Melo union perf_event *event, 352055c67edSArnaldo Carvalho de Melo pid_t pid, pid_t tgid, 353055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 354055c67edSArnaldo Carvalho de Melo struct machine *machine, 355055c67edSArnaldo Carvalho de Melo bool mmap_data) 356055c67edSArnaldo Carvalho de Melo { 357055c67edSArnaldo Carvalho de Melo unsigned long long t; 35804ed4ccbSIan Rogers char bf[BUFSIZ]; 3592069425eSIan Rogers struct io io; 360055c67edSArnaldo Carvalho de Melo bool truncation = false; 361055c67edSArnaldo Carvalho de Melo unsigned long long timeout = proc_map_timeout * 1000000ULL; 362055c67edSArnaldo Carvalho de Melo int rc = 0; 363055c67edSArnaldo Carvalho de Melo const char *hugetlbfs_mnt = hugetlbfs__mountpoint(); 364055c67edSArnaldo Carvalho de Melo int hugetlbfs_mnt_len = hugetlbfs_mnt ? strlen(hugetlbfs_mnt) : 0; 365055c67edSArnaldo Carvalho de Melo 366055c67edSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 367055c67edSArnaldo Carvalho de Melo return 0; 368055c67edSArnaldo Carvalho de Melo 36904ed4ccbSIan Rogers snprintf(bf, sizeof(bf), "%s/proc/%d/task/%d/maps", 370055c67edSArnaldo Carvalho de Melo machine->root_dir, pid, pid); 371055c67edSArnaldo Carvalho de Melo 3722069425eSIan Rogers io.fd = open(bf, O_RDONLY, 0); 3732069425eSIan Rogers if (io.fd < 0) { 374055c67edSArnaldo Carvalho de Melo /* 375055c67edSArnaldo Carvalho de Melo * We raced with a task exiting - just return: 376055c67edSArnaldo Carvalho de Melo */ 37704ed4ccbSIan Rogers pr_debug("couldn't open %s\n", bf); 378055c67edSArnaldo Carvalho de Melo return -1; 379055c67edSArnaldo Carvalho de Melo } 3802069425eSIan Rogers io__init(&io, io.fd, bf, sizeof(bf)); 381055c67edSArnaldo Carvalho de Melo 382055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_MMAP2; 383055c67edSArnaldo Carvalho de Melo t = rdclock(); 384055c67edSArnaldo Carvalho de Melo 3852069425eSIan Rogers while (!io.eof) { 3862069425eSIan Rogers static const char anonstr[] = "//anon"; 387055c67edSArnaldo Carvalho de Melo size_t size; 388055c67edSArnaldo Carvalho de Melo 3892069425eSIan Rogers /* ensure null termination since stack will be reused. */ 3902069425eSIan Rogers event->mmap2.filename[0] = '\0'; 3912069425eSIan Rogers 3922069425eSIan Rogers /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 3932069425eSIan Rogers if (!read_proc_maps_line(&io, 3942069425eSIan Rogers &event->mmap2.start, 3952069425eSIan Rogers &event->mmap2.len, 3962069425eSIan Rogers &event->mmap2.prot, 3972069425eSIan Rogers &event->mmap2.flags, 3982069425eSIan Rogers &event->mmap2.pgoff, 3992069425eSIan Rogers &event->mmap2.maj, 4002069425eSIan Rogers &event->mmap2.min, 4012069425eSIan Rogers &event->mmap2.ino, 4022069425eSIan Rogers sizeof(event->mmap2.filename), 4032069425eSIan Rogers event->mmap2.filename)) 4042069425eSIan Rogers continue; 405055c67edSArnaldo Carvalho de Melo 406055c67edSArnaldo Carvalho de Melo if ((rdclock() - t) > timeout) { 40704ed4ccbSIan Rogers pr_warning("Reading %s/proc/%d/task/%d/maps time out. " 408055c67edSArnaldo Carvalho de Melo "You may want to increase " 409055c67edSArnaldo Carvalho de Melo "the time limit by --proc-map-timeout\n", 41004ed4ccbSIan Rogers machine->root_dir, pid, pid); 411055c67edSArnaldo Carvalho de Melo truncation = true; 412055c67edSArnaldo Carvalho de Melo goto out; 413055c67edSArnaldo Carvalho de Melo } 414055c67edSArnaldo Carvalho de Melo 4153b7a15b0SIan Rogers event->mmap2.ino_generation = 0; 416055c67edSArnaldo Carvalho de Melo 417055c67edSArnaldo Carvalho de Melo /* 418055c67edSArnaldo Carvalho de Melo * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 419055c67edSArnaldo Carvalho de Melo */ 420055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) 421055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_USER; 422055c67edSArnaldo Carvalho de Melo else 423055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_GUEST_USER; 424055c67edSArnaldo Carvalho de Melo 4252069425eSIan Rogers if ((event->mmap2.prot & PROT_EXEC) == 0) { 4262069425eSIan Rogers if (!mmap_data || (event->mmap2.prot & PROT_READ) == 0) 427055c67edSArnaldo Carvalho de Melo continue; 428055c67edSArnaldo Carvalho de Melo 429055c67edSArnaldo Carvalho de Melo event->header.misc |= PERF_RECORD_MISC_MMAP_DATA; 430055c67edSArnaldo Carvalho de Melo } 431055c67edSArnaldo Carvalho de Melo 432055c67edSArnaldo Carvalho de Melo out: 433055c67edSArnaldo Carvalho de Melo if (truncation) 434055c67edSArnaldo Carvalho de Melo event->header.misc |= PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT; 435055c67edSArnaldo Carvalho de Melo 4362069425eSIan Rogers if (!strcmp(event->mmap2.filename, "")) 4372069425eSIan Rogers strcpy(event->mmap2.filename, anonstr); 438055c67edSArnaldo Carvalho de Melo 439055c67edSArnaldo Carvalho de Melo if (hugetlbfs_mnt_len && 4402069425eSIan Rogers !strncmp(event->mmap2.filename, hugetlbfs_mnt, 4412069425eSIan Rogers hugetlbfs_mnt_len)) { 4422069425eSIan Rogers strcpy(event->mmap2.filename, anonstr); 443055c67edSArnaldo Carvalho de Melo event->mmap2.flags |= MAP_HUGETLB; 444055c67edSArnaldo Carvalho de Melo } 445055c67edSArnaldo Carvalho de Melo 4462069425eSIan Rogers size = strlen(event->mmap2.filename) + 1; 447055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 448055c67edSArnaldo Carvalho de Melo event->mmap2.len -= event->mmap.start; 449055c67edSArnaldo Carvalho de Melo event->mmap2.header.size = (sizeof(event->mmap2) - 450055c67edSArnaldo Carvalho de Melo (sizeof(event->mmap2.filename) - size)); 451055c67edSArnaldo Carvalho de Melo memset(event->mmap2.filename + size, 0, machine->id_hdr_size); 452055c67edSArnaldo Carvalho de Melo event->mmap2.header.size += machine->id_hdr_size; 453055c67edSArnaldo Carvalho de Melo event->mmap2.pid = tgid; 454055c67edSArnaldo Carvalho de Melo event->mmap2.tid = pid; 455055c67edSArnaldo Carvalho de Melo 456055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { 457055c67edSArnaldo Carvalho de Melo rc = -1; 458055c67edSArnaldo Carvalho de Melo break; 459055c67edSArnaldo Carvalho de Melo } 460055c67edSArnaldo Carvalho de Melo 461055c67edSArnaldo Carvalho de Melo if (truncation) 462055c67edSArnaldo Carvalho de Melo break; 463055c67edSArnaldo Carvalho de Melo } 464055c67edSArnaldo Carvalho de Melo 4652069425eSIan Rogers close(io.fd); 466055c67edSArnaldo Carvalho de Melo return rc; 467055c67edSArnaldo Carvalho de Melo } 468055c67edSArnaldo Carvalho de Melo 469ab64069fSNamhyung Kim #ifdef HAVE_FILE_HANDLE 470ab64069fSNamhyung Kim static int perf_event__synthesize_cgroup(struct perf_tool *tool, 471ab64069fSNamhyung Kim union perf_event *event, 472ab64069fSNamhyung Kim char *path, size_t mount_len, 473ab64069fSNamhyung Kim perf_event__handler_t process, 474ab64069fSNamhyung Kim struct machine *machine) 475ab64069fSNamhyung Kim { 476ab64069fSNamhyung Kim size_t event_size = sizeof(event->cgroup) - sizeof(event->cgroup.path); 477ab64069fSNamhyung Kim size_t path_len = strlen(path) - mount_len + 1; 478ab64069fSNamhyung Kim struct { 479ab64069fSNamhyung Kim struct file_handle fh; 480ab64069fSNamhyung Kim uint64_t cgroup_id; 481ab64069fSNamhyung Kim } handle; 482ab64069fSNamhyung Kim int mount_id; 483ab64069fSNamhyung Kim 484ab64069fSNamhyung Kim while (path_len % sizeof(u64)) 485ab64069fSNamhyung Kim path[mount_len + path_len++] = '\0'; 486ab64069fSNamhyung Kim 487ab64069fSNamhyung Kim memset(&event->cgroup, 0, event_size); 488ab64069fSNamhyung Kim 489ab64069fSNamhyung Kim event->cgroup.header.type = PERF_RECORD_CGROUP; 490ab64069fSNamhyung Kim event->cgroup.header.size = event_size + path_len + machine->id_hdr_size; 491ab64069fSNamhyung Kim 492ab64069fSNamhyung Kim handle.fh.handle_bytes = sizeof(handle.cgroup_id); 493ab64069fSNamhyung Kim if (name_to_handle_at(AT_FDCWD, path, &handle.fh, &mount_id, 0) < 0) { 494ab64069fSNamhyung Kim pr_debug("stat failed: %s\n", path); 495ab64069fSNamhyung Kim return -1; 496ab64069fSNamhyung Kim } 497ab64069fSNamhyung Kim 498ab64069fSNamhyung Kim event->cgroup.id = handle.cgroup_id; 499ab64069fSNamhyung Kim strncpy(event->cgroup.path, path + mount_len, path_len); 500ab64069fSNamhyung Kim memset(event->cgroup.path + path_len, 0, machine->id_hdr_size); 501ab64069fSNamhyung Kim 502ab64069fSNamhyung Kim if (perf_tool__process_synth_event(tool, event, machine, process) < 0) { 503ab64069fSNamhyung Kim pr_debug("process synth event failed\n"); 504ab64069fSNamhyung Kim return -1; 505ab64069fSNamhyung Kim } 506ab64069fSNamhyung Kim 507ab64069fSNamhyung Kim return 0; 508ab64069fSNamhyung Kim } 509ab64069fSNamhyung Kim 510ab64069fSNamhyung Kim static int perf_event__walk_cgroup_tree(struct perf_tool *tool, 511ab64069fSNamhyung Kim union perf_event *event, 512ab64069fSNamhyung Kim char *path, size_t mount_len, 513ab64069fSNamhyung Kim perf_event__handler_t process, 514ab64069fSNamhyung Kim struct machine *machine) 515ab64069fSNamhyung Kim { 516ab64069fSNamhyung Kim size_t pos = strlen(path); 517ab64069fSNamhyung Kim DIR *d; 518ab64069fSNamhyung Kim struct dirent *dent; 519ab64069fSNamhyung Kim int ret = 0; 520ab64069fSNamhyung Kim 521ab64069fSNamhyung Kim if (perf_event__synthesize_cgroup(tool, event, path, mount_len, 522ab64069fSNamhyung Kim process, machine) < 0) 523ab64069fSNamhyung Kim return -1; 524ab64069fSNamhyung Kim 525ab64069fSNamhyung Kim d = opendir(path); 526ab64069fSNamhyung Kim if (d == NULL) { 527ab64069fSNamhyung Kim pr_debug("failed to open directory: %s\n", path); 528ab64069fSNamhyung Kim return -1; 529ab64069fSNamhyung Kim } 530ab64069fSNamhyung Kim 531ab64069fSNamhyung Kim while ((dent = readdir(d)) != NULL) { 532ab64069fSNamhyung Kim if (dent->d_type != DT_DIR) 533ab64069fSNamhyung Kim continue; 534ab64069fSNamhyung Kim if (!strcmp(dent->d_name, ".") || 535ab64069fSNamhyung Kim !strcmp(dent->d_name, "..")) 536ab64069fSNamhyung Kim continue; 537ab64069fSNamhyung Kim 538ab64069fSNamhyung Kim /* any sane path should be less than PATH_MAX */ 539ab64069fSNamhyung Kim if (strlen(path) + strlen(dent->d_name) + 1 >= PATH_MAX) 540ab64069fSNamhyung Kim continue; 541ab64069fSNamhyung Kim 542ab64069fSNamhyung Kim if (path[pos - 1] != '/') 543ab64069fSNamhyung Kim strcat(path, "/"); 544ab64069fSNamhyung Kim strcat(path, dent->d_name); 545ab64069fSNamhyung Kim 546ab64069fSNamhyung Kim ret = perf_event__walk_cgroup_tree(tool, event, path, 547ab64069fSNamhyung Kim mount_len, process, machine); 548ab64069fSNamhyung Kim if (ret < 0) 549ab64069fSNamhyung Kim break; 550ab64069fSNamhyung Kim 551ab64069fSNamhyung Kim path[pos] = '\0'; 552ab64069fSNamhyung Kim } 553ab64069fSNamhyung Kim 554ab64069fSNamhyung Kim closedir(d); 555ab64069fSNamhyung Kim return ret; 556ab64069fSNamhyung Kim } 557ab64069fSNamhyung Kim 558ab64069fSNamhyung Kim int perf_event__synthesize_cgroups(struct perf_tool *tool, 559ab64069fSNamhyung Kim perf_event__handler_t process, 560ab64069fSNamhyung Kim struct machine *machine) 561ab64069fSNamhyung Kim { 562ab64069fSNamhyung Kim union perf_event event; 563ab64069fSNamhyung Kim char cgrp_root[PATH_MAX]; 564ab64069fSNamhyung Kim size_t mount_len; /* length of mount point in the path */ 565ab64069fSNamhyung Kim 566aa50d953SNamhyung Kim if (!tool || !tool->cgroup_events) 567aa50d953SNamhyung Kim return 0; 568aa50d953SNamhyung Kim 569ab64069fSNamhyung Kim if (cgroupfs_find_mountpoint(cgrp_root, PATH_MAX, "perf_event") < 0) { 570ab64069fSNamhyung Kim pr_debug("cannot find cgroup mount point\n"); 571ab64069fSNamhyung Kim return -1; 572ab64069fSNamhyung Kim } 573ab64069fSNamhyung Kim 574ab64069fSNamhyung Kim mount_len = strlen(cgrp_root); 575ab64069fSNamhyung Kim /* make sure the path starts with a slash (after mount point) */ 576ab64069fSNamhyung Kim strcat(cgrp_root, "/"); 577ab64069fSNamhyung Kim 578ab64069fSNamhyung Kim if (perf_event__walk_cgroup_tree(tool, &event, cgrp_root, mount_len, 579ab64069fSNamhyung Kim process, machine) < 0) 580ab64069fSNamhyung Kim return -1; 581ab64069fSNamhyung Kim 582ab64069fSNamhyung Kim return 0; 583ab64069fSNamhyung Kim } 584ab64069fSNamhyung Kim #else 585ab64069fSNamhyung Kim int perf_event__synthesize_cgroups(struct perf_tool *tool __maybe_unused, 586ab64069fSNamhyung Kim perf_event__handler_t process __maybe_unused, 587ab64069fSNamhyung Kim struct machine *machine __maybe_unused) 588ab64069fSNamhyung Kim { 589ab64069fSNamhyung Kim return -1; 590ab64069fSNamhyung Kim } 591ab64069fSNamhyung Kim #endif 592ab64069fSNamhyung Kim 593055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process, 594055c67edSArnaldo Carvalho de Melo struct machine *machine) 595055c67edSArnaldo Carvalho de Melo { 596055c67edSArnaldo Carvalho de Melo int rc = 0; 597055c67edSArnaldo Carvalho de Melo struct map *pos; 598055c67edSArnaldo Carvalho de Melo struct maps *maps = machine__kernel_maps(machine); 599055c67edSArnaldo Carvalho de Melo union perf_event *event = zalloc((sizeof(event->mmap) + 600055c67edSArnaldo Carvalho de Melo machine->id_hdr_size)); 601055c67edSArnaldo Carvalho de Melo if (event == NULL) { 602055c67edSArnaldo Carvalho de Melo pr_debug("Not enough memory synthesizing mmap event " 603055c67edSArnaldo Carvalho de Melo "for kernel modules\n"); 604055c67edSArnaldo Carvalho de Melo return -1; 605055c67edSArnaldo Carvalho de Melo } 606055c67edSArnaldo Carvalho de Melo 607055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_MMAP; 608055c67edSArnaldo Carvalho de Melo 609055c67edSArnaldo Carvalho de Melo /* 610055c67edSArnaldo Carvalho de Melo * kernel uses 0 for user space maps, see kernel/perf_event.c 611055c67edSArnaldo Carvalho de Melo * __perf_event_mmap 612055c67edSArnaldo Carvalho de Melo */ 613055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) 614055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_KERNEL; 615055c67edSArnaldo Carvalho de Melo else 616055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 617055c67edSArnaldo Carvalho de Melo 6188efc4f05SArnaldo Carvalho de Melo maps__for_each_entry(maps, pos) { 619055c67edSArnaldo Carvalho de Melo size_t size; 620055c67edSArnaldo Carvalho de Melo 621055c67edSArnaldo Carvalho de Melo if (!__map__is_kmodule(pos)) 622055c67edSArnaldo Carvalho de Melo continue; 623055c67edSArnaldo Carvalho de Melo 624055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); 625055c67edSArnaldo Carvalho de Melo event->mmap.header.type = PERF_RECORD_MMAP; 626055c67edSArnaldo Carvalho de Melo event->mmap.header.size = (sizeof(event->mmap) - 627055c67edSArnaldo Carvalho de Melo (sizeof(event->mmap.filename) - size)); 628055c67edSArnaldo Carvalho de Melo memset(event->mmap.filename + size, 0, machine->id_hdr_size); 629055c67edSArnaldo Carvalho de Melo event->mmap.header.size += machine->id_hdr_size; 630055c67edSArnaldo Carvalho de Melo event->mmap.start = pos->start; 631055c67edSArnaldo Carvalho de Melo event->mmap.len = pos->end - pos->start; 632055c67edSArnaldo Carvalho de Melo event->mmap.pid = machine->pid; 633055c67edSArnaldo Carvalho de Melo 634055c67edSArnaldo Carvalho de Melo memcpy(event->mmap.filename, pos->dso->long_name, 635055c67edSArnaldo Carvalho de Melo pos->dso->long_name_len + 1); 636055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { 637055c67edSArnaldo Carvalho de Melo rc = -1; 638055c67edSArnaldo Carvalho de Melo break; 639055c67edSArnaldo Carvalho de Melo } 640055c67edSArnaldo Carvalho de Melo } 641055c67edSArnaldo Carvalho de Melo 642055c67edSArnaldo Carvalho de Melo free(event); 643055c67edSArnaldo Carvalho de Melo return rc; 644055c67edSArnaldo Carvalho de Melo } 645055c67edSArnaldo Carvalho de Melo 646055c67edSArnaldo Carvalho de Melo static int __event__synthesize_thread(union perf_event *comm_event, 647055c67edSArnaldo Carvalho de Melo union perf_event *mmap_event, 648055c67edSArnaldo Carvalho de Melo union perf_event *fork_event, 649055c67edSArnaldo Carvalho de Melo union perf_event *namespaces_event, 650055c67edSArnaldo Carvalho de Melo pid_t pid, int full, perf_event__handler_t process, 651055c67edSArnaldo Carvalho de Melo struct perf_tool *tool, struct machine *machine, bool mmap_data) 652055c67edSArnaldo Carvalho de Melo { 653055c67edSArnaldo Carvalho de Melo char filename[PATH_MAX]; 654055c67edSArnaldo Carvalho de Melo DIR *tasks; 655055c67edSArnaldo Carvalho de Melo struct dirent *dirent; 656055c67edSArnaldo Carvalho de Melo pid_t tgid, ppid; 657055c67edSArnaldo Carvalho de Melo int rc = 0; 658055c67edSArnaldo Carvalho de Melo 659055c67edSArnaldo Carvalho de Melo /* special case: only send one comm event using passed in pid */ 660055c67edSArnaldo Carvalho de Melo if (!full) { 661055c67edSArnaldo Carvalho de Melo tgid = perf_event__synthesize_comm(tool, comm_event, pid, 662055c67edSArnaldo Carvalho de Melo process, machine); 663055c67edSArnaldo Carvalho de Melo 664055c67edSArnaldo Carvalho de Melo if (tgid == -1) 665055c67edSArnaldo Carvalho de Melo return -1; 666055c67edSArnaldo Carvalho de Melo 667055c67edSArnaldo Carvalho de Melo if (perf_event__synthesize_namespaces(tool, namespaces_event, pid, 668055c67edSArnaldo Carvalho de Melo tgid, process, machine) < 0) 669055c67edSArnaldo Carvalho de Melo return -1; 670055c67edSArnaldo Carvalho de Melo 671055c67edSArnaldo Carvalho de Melo /* 672055c67edSArnaldo Carvalho de Melo * send mmap only for thread group leader 67379b6bb73SArnaldo Carvalho de Melo * see thread__init_maps() 674055c67edSArnaldo Carvalho de Melo */ 675055c67edSArnaldo Carvalho de Melo if (pid == tgid && 676055c67edSArnaldo Carvalho de Melo perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 677055c67edSArnaldo Carvalho de Melo process, machine, mmap_data)) 678055c67edSArnaldo Carvalho de Melo return -1; 679055c67edSArnaldo Carvalho de Melo 680055c67edSArnaldo Carvalho de Melo return 0; 681055c67edSArnaldo Carvalho de Melo } 682055c67edSArnaldo Carvalho de Melo 683055c67edSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 684055c67edSArnaldo Carvalho de Melo return 0; 685055c67edSArnaldo Carvalho de Melo 686055c67edSArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), "%s/proc/%d/task", 687055c67edSArnaldo Carvalho de Melo machine->root_dir, pid); 688055c67edSArnaldo Carvalho de Melo 689055c67edSArnaldo Carvalho de Melo tasks = opendir(filename); 690055c67edSArnaldo Carvalho de Melo if (tasks == NULL) { 691055c67edSArnaldo Carvalho de Melo pr_debug("couldn't open %s\n", filename); 692055c67edSArnaldo Carvalho de Melo return 0; 693055c67edSArnaldo Carvalho de Melo } 694055c67edSArnaldo Carvalho de Melo 695055c67edSArnaldo Carvalho de Melo while ((dirent = readdir(tasks)) != NULL) { 696055c67edSArnaldo Carvalho de Melo char *end; 697055c67edSArnaldo Carvalho de Melo pid_t _pid; 698055c67edSArnaldo Carvalho de Melo 699055c67edSArnaldo Carvalho de Melo _pid = strtol(dirent->d_name, &end, 10); 700055c67edSArnaldo Carvalho de Melo if (*end) 701055c67edSArnaldo Carvalho de Melo continue; 702055c67edSArnaldo Carvalho de Melo 703055c67edSArnaldo Carvalho de Melo rc = -1; 704055c67edSArnaldo Carvalho de Melo if (perf_event__prepare_comm(comm_event, _pid, machine, 705055c67edSArnaldo Carvalho de Melo &tgid, &ppid) != 0) 706055c67edSArnaldo Carvalho de Melo break; 707055c67edSArnaldo Carvalho de Melo 708055c67edSArnaldo Carvalho de Melo if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid, 709055c67edSArnaldo Carvalho de Melo ppid, process, machine) < 0) 710055c67edSArnaldo Carvalho de Melo break; 711055c67edSArnaldo Carvalho de Melo 712055c67edSArnaldo Carvalho de Melo if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid, 713055c67edSArnaldo Carvalho de Melo tgid, process, machine) < 0) 714055c67edSArnaldo Carvalho de Melo break; 715055c67edSArnaldo Carvalho de Melo 716055c67edSArnaldo Carvalho de Melo /* 717055c67edSArnaldo Carvalho de Melo * Send the prepared comm event 718055c67edSArnaldo Carvalho de Melo */ 719055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, comm_event, machine, process) != 0) 720055c67edSArnaldo Carvalho de Melo break; 721055c67edSArnaldo Carvalho de Melo 722055c67edSArnaldo Carvalho de Melo rc = 0; 723055c67edSArnaldo Carvalho de Melo if (_pid == pid) { 724055c67edSArnaldo Carvalho de Melo /* process the parent's maps too */ 725055c67edSArnaldo Carvalho de Melo rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 726055c67edSArnaldo Carvalho de Melo process, machine, mmap_data); 727055c67edSArnaldo Carvalho de Melo if (rc) 728055c67edSArnaldo Carvalho de Melo break; 729055c67edSArnaldo Carvalho de Melo } 730055c67edSArnaldo Carvalho de Melo } 731055c67edSArnaldo Carvalho de Melo 732055c67edSArnaldo Carvalho de Melo closedir(tasks); 733055c67edSArnaldo Carvalho de Melo return rc; 734055c67edSArnaldo Carvalho de Melo } 735055c67edSArnaldo Carvalho de Melo 736055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_thread_map(struct perf_tool *tool, 737055c67edSArnaldo Carvalho de Melo struct perf_thread_map *threads, 738055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 739055c67edSArnaldo Carvalho de Melo struct machine *machine, 740055c67edSArnaldo Carvalho de Melo bool mmap_data) 741055c67edSArnaldo Carvalho de Melo { 742055c67edSArnaldo Carvalho de Melo union perf_event *comm_event, *mmap_event, *fork_event; 743055c67edSArnaldo Carvalho de Melo union perf_event *namespaces_event; 744055c67edSArnaldo Carvalho de Melo int err = -1, thread, j; 745055c67edSArnaldo Carvalho de Melo 746055c67edSArnaldo Carvalho de Melo comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 747055c67edSArnaldo Carvalho de Melo if (comm_event == NULL) 748055c67edSArnaldo Carvalho de Melo goto out; 749055c67edSArnaldo Carvalho de Melo 750055c67edSArnaldo Carvalho de Melo mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); 751055c67edSArnaldo Carvalho de Melo if (mmap_event == NULL) 752055c67edSArnaldo Carvalho de Melo goto out_free_comm; 753055c67edSArnaldo Carvalho de Melo 754055c67edSArnaldo Carvalho de Melo fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); 755055c67edSArnaldo Carvalho de Melo if (fork_event == NULL) 756055c67edSArnaldo Carvalho de Melo goto out_free_mmap; 757055c67edSArnaldo Carvalho de Melo 758055c67edSArnaldo Carvalho de Melo namespaces_event = malloc(sizeof(namespaces_event->namespaces) + 759055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 760055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 761055c67edSArnaldo Carvalho de Melo if (namespaces_event == NULL) 762055c67edSArnaldo Carvalho de Melo goto out_free_fork; 763055c67edSArnaldo Carvalho de Melo 764055c67edSArnaldo Carvalho de Melo err = 0; 765055c67edSArnaldo Carvalho de Melo for (thread = 0; thread < threads->nr; ++thread) { 766055c67edSArnaldo Carvalho de Melo if (__event__synthesize_thread(comm_event, mmap_event, 767055c67edSArnaldo Carvalho de Melo fork_event, namespaces_event, 768055c67edSArnaldo Carvalho de Melo perf_thread_map__pid(threads, thread), 0, 769055c67edSArnaldo Carvalho de Melo process, tool, machine, 770055c67edSArnaldo Carvalho de Melo mmap_data)) { 771055c67edSArnaldo Carvalho de Melo err = -1; 772055c67edSArnaldo Carvalho de Melo break; 773055c67edSArnaldo Carvalho de Melo } 774055c67edSArnaldo Carvalho de Melo 775055c67edSArnaldo Carvalho de Melo /* 776055c67edSArnaldo Carvalho de Melo * comm.pid is set to thread group id by 777055c67edSArnaldo Carvalho de Melo * perf_event__synthesize_comm 778055c67edSArnaldo Carvalho de Melo */ 779055c67edSArnaldo Carvalho de Melo if ((int) comm_event->comm.pid != perf_thread_map__pid(threads, thread)) { 780055c67edSArnaldo Carvalho de Melo bool need_leader = true; 781055c67edSArnaldo Carvalho de Melo 782055c67edSArnaldo Carvalho de Melo /* is thread group leader in thread_map? */ 783055c67edSArnaldo Carvalho de Melo for (j = 0; j < threads->nr; ++j) { 784055c67edSArnaldo Carvalho de Melo if ((int) comm_event->comm.pid == perf_thread_map__pid(threads, j)) { 785055c67edSArnaldo Carvalho de Melo need_leader = false; 786055c67edSArnaldo Carvalho de Melo break; 787055c67edSArnaldo Carvalho de Melo } 788055c67edSArnaldo Carvalho de Melo } 789055c67edSArnaldo Carvalho de Melo 790055c67edSArnaldo Carvalho de Melo /* if not, generate events for it */ 791055c67edSArnaldo Carvalho de Melo if (need_leader && 792055c67edSArnaldo Carvalho de Melo __event__synthesize_thread(comm_event, mmap_event, 793055c67edSArnaldo Carvalho de Melo fork_event, namespaces_event, 794055c67edSArnaldo Carvalho de Melo comm_event->comm.pid, 0, 795055c67edSArnaldo Carvalho de Melo process, tool, machine, 796055c67edSArnaldo Carvalho de Melo mmap_data)) { 797055c67edSArnaldo Carvalho de Melo err = -1; 798055c67edSArnaldo Carvalho de Melo break; 799055c67edSArnaldo Carvalho de Melo } 800055c67edSArnaldo Carvalho de Melo } 801055c67edSArnaldo Carvalho de Melo } 802055c67edSArnaldo Carvalho de Melo free(namespaces_event); 803055c67edSArnaldo Carvalho de Melo out_free_fork: 804055c67edSArnaldo Carvalho de Melo free(fork_event); 805055c67edSArnaldo Carvalho de Melo out_free_mmap: 806055c67edSArnaldo Carvalho de Melo free(mmap_event); 807055c67edSArnaldo Carvalho de Melo out_free_comm: 808055c67edSArnaldo Carvalho de Melo free(comm_event); 809055c67edSArnaldo Carvalho de Melo out: 810055c67edSArnaldo Carvalho de Melo return err; 811055c67edSArnaldo Carvalho de Melo } 812055c67edSArnaldo Carvalho de Melo 813055c67edSArnaldo Carvalho de Melo static int __perf_event__synthesize_threads(struct perf_tool *tool, 814055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 815055c67edSArnaldo Carvalho de Melo struct machine *machine, 816055c67edSArnaldo Carvalho de Melo bool mmap_data, 817055c67edSArnaldo Carvalho de Melo struct dirent **dirent, 818055c67edSArnaldo Carvalho de Melo int start, 819055c67edSArnaldo Carvalho de Melo int num) 820055c67edSArnaldo Carvalho de Melo { 821055c67edSArnaldo Carvalho de Melo union perf_event *comm_event, *mmap_event, *fork_event; 822055c67edSArnaldo Carvalho de Melo union perf_event *namespaces_event; 823055c67edSArnaldo Carvalho de Melo int err = -1; 824055c67edSArnaldo Carvalho de Melo char *end; 825055c67edSArnaldo Carvalho de Melo pid_t pid; 826055c67edSArnaldo Carvalho de Melo int i; 827055c67edSArnaldo Carvalho de Melo 828055c67edSArnaldo Carvalho de Melo comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 829055c67edSArnaldo Carvalho de Melo if (comm_event == NULL) 830055c67edSArnaldo Carvalho de Melo goto out; 831055c67edSArnaldo Carvalho de Melo 832055c67edSArnaldo Carvalho de Melo mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); 833055c67edSArnaldo Carvalho de Melo if (mmap_event == NULL) 834055c67edSArnaldo Carvalho de Melo goto out_free_comm; 835055c67edSArnaldo Carvalho de Melo 836055c67edSArnaldo Carvalho de Melo fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); 837055c67edSArnaldo Carvalho de Melo if (fork_event == NULL) 838055c67edSArnaldo Carvalho de Melo goto out_free_mmap; 839055c67edSArnaldo Carvalho de Melo 840055c67edSArnaldo Carvalho de Melo namespaces_event = malloc(sizeof(namespaces_event->namespaces) + 841055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 842055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 843055c67edSArnaldo Carvalho de Melo if (namespaces_event == NULL) 844055c67edSArnaldo Carvalho de Melo goto out_free_fork; 845055c67edSArnaldo Carvalho de Melo 846055c67edSArnaldo Carvalho de Melo for (i = start; i < start + num; i++) { 847055c67edSArnaldo Carvalho de Melo if (!isdigit(dirent[i]->d_name[0])) 848055c67edSArnaldo Carvalho de Melo continue; 849055c67edSArnaldo Carvalho de Melo 850055c67edSArnaldo Carvalho de Melo pid = (pid_t)strtol(dirent[i]->d_name, &end, 10); 851055c67edSArnaldo Carvalho de Melo /* only interested in proper numerical dirents */ 852055c67edSArnaldo Carvalho de Melo if (*end) 853055c67edSArnaldo Carvalho de Melo continue; 854055c67edSArnaldo Carvalho de Melo /* 855055c67edSArnaldo Carvalho de Melo * We may race with exiting thread, so don't stop just because 856055c67edSArnaldo Carvalho de Melo * one thread couldn't be synthesized. 857055c67edSArnaldo Carvalho de Melo */ 858055c67edSArnaldo Carvalho de Melo __event__synthesize_thread(comm_event, mmap_event, fork_event, 859055c67edSArnaldo Carvalho de Melo namespaces_event, pid, 1, process, 860055c67edSArnaldo Carvalho de Melo tool, machine, mmap_data); 861055c67edSArnaldo Carvalho de Melo } 862055c67edSArnaldo Carvalho de Melo err = 0; 863055c67edSArnaldo Carvalho de Melo 864055c67edSArnaldo Carvalho de Melo free(namespaces_event); 865055c67edSArnaldo Carvalho de Melo out_free_fork: 866055c67edSArnaldo Carvalho de Melo free(fork_event); 867055c67edSArnaldo Carvalho de Melo out_free_mmap: 868055c67edSArnaldo Carvalho de Melo free(mmap_event); 869055c67edSArnaldo Carvalho de Melo out_free_comm: 870055c67edSArnaldo Carvalho de Melo free(comm_event); 871055c67edSArnaldo Carvalho de Melo out: 872055c67edSArnaldo Carvalho de Melo return err; 873055c67edSArnaldo Carvalho de Melo } 874055c67edSArnaldo Carvalho de Melo 875055c67edSArnaldo Carvalho de Melo struct synthesize_threads_arg { 876055c67edSArnaldo Carvalho de Melo struct perf_tool *tool; 877055c67edSArnaldo Carvalho de Melo perf_event__handler_t process; 878055c67edSArnaldo Carvalho de Melo struct machine *machine; 879055c67edSArnaldo Carvalho de Melo bool mmap_data; 880055c67edSArnaldo Carvalho de Melo struct dirent **dirent; 881055c67edSArnaldo Carvalho de Melo int num; 882055c67edSArnaldo Carvalho de Melo int start; 883055c67edSArnaldo Carvalho de Melo }; 884055c67edSArnaldo Carvalho de Melo 885055c67edSArnaldo Carvalho de Melo static void *synthesize_threads_worker(void *arg) 886055c67edSArnaldo Carvalho de Melo { 887055c67edSArnaldo Carvalho de Melo struct synthesize_threads_arg *args = arg; 888055c67edSArnaldo Carvalho de Melo 889055c67edSArnaldo Carvalho de Melo __perf_event__synthesize_threads(args->tool, args->process, 890055c67edSArnaldo Carvalho de Melo args->machine, args->mmap_data, 891055c67edSArnaldo Carvalho de Melo args->dirent, 892055c67edSArnaldo Carvalho de Melo args->start, args->num); 893055c67edSArnaldo Carvalho de Melo return NULL; 894055c67edSArnaldo Carvalho de Melo } 895055c67edSArnaldo Carvalho de Melo 896055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_threads(struct perf_tool *tool, 897055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 898055c67edSArnaldo Carvalho de Melo struct machine *machine, 899055c67edSArnaldo Carvalho de Melo bool mmap_data, 900055c67edSArnaldo Carvalho de Melo unsigned int nr_threads_synthesize) 901055c67edSArnaldo Carvalho de Melo { 902055c67edSArnaldo Carvalho de Melo struct synthesize_threads_arg *args = NULL; 903055c67edSArnaldo Carvalho de Melo pthread_t *synthesize_threads = NULL; 904055c67edSArnaldo Carvalho de Melo char proc_path[PATH_MAX]; 905055c67edSArnaldo Carvalho de Melo struct dirent **dirent; 906055c67edSArnaldo Carvalho de Melo int num_per_thread; 907055c67edSArnaldo Carvalho de Melo int m, n, i, j; 908055c67edSArnaldo Carvalho de Melo int thread_nr; 909055c67edSArnaldo Carvalho de Melo int base = 0; 910055c67edSArnaldo Carvalho de Melo int err = -1; 911055c67edSArnaldo Carvalho de Melo 912055c67edSArnaldo Carvalho de Melo 913055c67edSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 914055c67edSArnaldo Carvalho de Melo return 0; 915055c67edSArnaldo Carvalho de Melo 916055c67edSArnaldo Carvalho de Melo snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); 917055c67edSArnaldo Carvalho de Melo n = scandir(proc_path, &dirent, 0, alphasort); 918055c67edSArnaldo Carvalho de Melo if (n < 0) 919055c67edSArnaldo Carvalho de Melo return err; 920055c67edSArnaldo Carvalho de Melo 921055c67edSArnaldo Carvalho de Melo if (nr_threads_synthesize == UINT_MAX) 922055c67edSArnaldo Carvalho de Melo thread_nr = sysconf(_SC_NPROCESSORS_ONLN); 923055c67edSArnaldo Carvalho de Melo else 924055c67edSArnaldo Carvalho de Melo thread_nr = nr_threads_synthesize; 925055c67edSArnaldo Carvalho de Melo 926055c67edSArnaldo Carvalho de Melo if (thread_nr <= 1) { 927055c67edSArnaldo Carvalho de Melo err = __perf_event__synthesize_threads(tool, process, 928055c67edSArnaldo Carvalho de Melo machine, mmap_data, 929055c67edSArnaldo Carvalho de Melo dirent, base, n); 930055c67edSArnaldo Carvalho de Melo goto free_dirent; 931055c67edSArnaldo Carvalho de Melo } 932055c67edSArnaldo Carvalho de Melo if (thread_nr > n) 933055c67edSArnaldo Carvalho de Melo thread_nr = n; 934055c67edSArnaldo Carvalho de Melo 935055c67edSArnaldo Carvalho de Melo synthesize_threads = calloc(sizeof(pthread_t), thread_nr); 936055c67edSArnaldo Carvalho de Melo if (synthesize_threads == NULL) 937055c67edSArnaldo Carvalho de Melo goto free_dirent; 938055c67edSArnaldo Carvalho de Melo 939055c67edSArnaldo Carvalho de Melo args = calloc(sizeof(*args), thread_nr); 940055c67edSArnaldo Carvalho de Melo if (args == NULL) 941055c67edSArnaldo Carvalho de Melo goto free_threads; 942055c67edSArnaldo Carvalho de Melo 943055c67edSArnaldo Carvalho de Melo num_per_thread = n / thread_nr; 944055c67edSArnaldo Carvalho de Melo m = n % thread_nr; 945055c67edSArnaldo Carvalho de Melo for (i = 0; i < thread_nr; i++) { 946055c67edSArnaldo Carvalho de Melo args[i].tool = tool; 947055c67edSArnaldo Carvalho de Melo args[i].process = process; 948055c67edSArnaldo Carvalho de Melo args[i].machine = machine; 949055c67edSArnaldo Carvalho de Melo args[i].mmap_data = mmap_data; 950055c67edSArnaldo Carvalho de Melo args[i].dirent = dirent; 951055c67edSArnaldo Carvalho de Melo } 952055c67edSArnaldo Carvalho de Melo for (i = 0; i < m; i++) { 953055c67edSArnaldo Carvalho de Melo args[i].num = num_per_thread + 1; 954055c67edSArnaldo Carvalho de Melo args[i].start = i * args[i].num; 955055c67edSArnaldo Carvalho de Melo } 956055c67edSArnaldo Carvalho de Melo if (i != 0) 957055c67edSArnaldo Carvalho de Melo base = args[i-1].start + args[i-1].num; 958055c67edSArnaldo Carvalho de Melo for (j = i; j < thread_nr; j++) { 959055c67edSArnaldo Carvalho de Melo args[j].num = num_per_thread; 960055c67edSArnaldo Carvalho de Melo args[j].start = base + (j - i) * args[i].num; 961055c67edSArnaldo Carvalho de Melo } 962055c67edSArnaldo Carvalho de Melo 963055c67edSArnaldo Carvalho de Melo for (i = 0; i < thread_nr; i++) { 964055c67edSArnaldo Carvalho de Melo if (pthread_create(&synthesize_threads[i], NULL, 965055c67edSArnaldo Carvalho de Melo synthesize_threads_worker, &args[i])) 966055c67edSArnaldo Carvalho de Melo goto out_join; 967055c67edSArnaldo Carvalho de Melo } 968055c67edSArnaldo Carvalho de Melo err = 0; 969055c67edSArnaldo Carvalho de Melo out_join: 970055c67edSArnaldo Carvalho de Melo for (i = 0; i < thread_nr; i++) 971055c67edSArnaldo Carvalho de Melo pthread_join(synthesize_threads[i], NULL); 972055c67edSArnaldo Carvalho de Melo free(args); 973055c67edSArnaldo Carvalho de Melo free_threads: 974055c67edSArnaldo Carvalho de Melo free(synthesize_threads); 975055c67edSArnaldo Carvalho de Melo free_dirent: 976055c67edSArnaldo Carvalho de Melo for (i = 0; i < n; i++) 977055c67edSArnaldo Carvalho de Melo zfree(&dirent[i]); 978055c67edSArnaldo Carvalho de Melo free(dirent); 979055c67edSArnaldo Carvalho de Melo 980055c67edSArnaldo Carvalho de Melo return err; 981055c67edSArnaldo Carvalho de Melo } 982055c67edSArnaldo Carvalho de Melo 983055c67edSArnaldo Carvalho de Melo int __weak perf_event__synthesize_extra_kmaps(struct perf_tool *tool __maybe_unused, 984055c67edSArnaldo Carvalho de Melo perf_event__handler_t process __maybe_unused, 985055c67edSArnaldo Carvalho de Melo struct machine *machine __maybe_unused) 986055c67edSArnaldo Carvalho de Melo { 987055c67edSArnaldo Carvalho de Melo return 0; 988055c67edSArnaldo Carvalho de Melo } 989055c67edSArnaldo Carvalho de Melo 990055c67edSArnaldo Carvalho de Melo static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 991055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 992055c67edSArnaldo Carvalho de Melo struct machine *machine) 993055c67edSArnaldo Carvalho de Melo { 994*978410ffSJiri Olsa union perf_event *event; 995*978410ffSJiri Olsa size_t size = symbol_conf.buildid_mmap2 ? 996*978410ffSJiri Olsa sizeof(event->mmap2) : sizeof(event->mmap); 997055c67edSArnaldo Carvalho de Melo struct map *map = machine__kernel_map(machine); 998055c67edSArnaldo Carvalho de Melo struct kmap *kmap; 999055c67edSArnaldo Carvalho de Melo int err; 1000055c67edSArnaldo Carvalho de Melo 1001055c67edSArnaldo Carvalho de Melo if (map == NULL) 1002055c67edSArnaldo Carvalho de Melo return -1; 1003055c67edSArnaldo Carvalho de Melo 1004055c67edSArnaldo Carvalho de Melo kmap = map__kmap(map); 1005055c67edSArnaldo Carvalho de Melo if (!kmap->ref_reloc_sym) 1006055c67edSArnaldo Carvalho de Melo return -1; 1007055c67edSArnaldo Carvalho de Melo 1008055c67edSArnaldo Carvalho de Melo /* 1009055c67edSArnaldo Carvalho de Melo * We should get this from /sys/kernel/sections/.text, but till that is 1010055c67edSArnaldo Carvalho de Melo * available use this, and after it is use this as a fallback for older 1011055c67edSArnaldo Carvalho de Melo * kernels. 1012055c67edSArnaldo Carvalho de Melo */ 1013*978410ffSJiri Olsa event = zalloc(size + machine->id_hdr_size); 1014055c67edSArnaldo Carvalho de Melo if (event == NULL) { 1015055c67edSArnaldo Carvalho de Melo pr_debug("Not enough memory synthesizing mmap event " 1016055c67edSArnaldo Carvalho de Melo "for kernel modules\n"); 1017055c67edSArnaldo Carvalho de Melo return -1; 1018055c67edSArnaldo Carvalho de Melo } 1019055c67edSArnaldo Carvalho de Melo 1020055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) { 1021055c67edSArnaldo Carvalho de Melo /* 1022055c67edSArnaldo Carvalho de Melo * kernel uses PERF_RECORD_MISC_USER for user space maps, 1023055c67edSArnaldo Carvalho de Melo * see kernel/perf_event.c __perf_event_mmap 1024055c67edSArnaldo Carvalho de Melo */ 1025055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_KERNEL; 1026055c67edSArnaldo Carvalho de Melo } else { 1027055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 1028055c67edSArnaldo Carvalho de Melo } 1029055c67edSArnaldo Carvalho de Melo 1030*978410ffSJiri Olsa if (symbol_conf.buildid_mmap2) { 1031*978410ffSJiri Olsa size = snprintf(event->mmap2.filename, sizeof(event->mmap2.filename), 1032*978410ffSJiri Olsa "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1; 1033*978410ffSJiri Olsa size = PERF_ALIGN(size, sizeof(u64)); 1034*978410ffSJiri Olsa event->mmap2.header.type = PERF_RECORD_MMAP2; 1035*978410ffSJiri Olsa event->mmap2.header.size = (sizeof(event->mmap2) - 1036*978410ffSJiri Olsa (sizeof(event->mmap2.filename) - size) + machine->id_hdr_size); 1037*978410ffSJiri Olsa event->mmap2.pgoff = kmap->ref_reloc_sym->addr; 1038*978410ffSJiri Olsa event->mmap2.start = map->start; 1039*978410ffSJiri Olsa event->mmap2.len = map->end - event->mmap.start; 1040*978410ffSJiri Olsa event->mmap2.pid = machine->pid; 1041*978410ffSJiri Olsa } else { 1042055c67edSArnaldo Carvalho de Melo size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 1043055c67edSArnaldo Carvalho de Melo "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1; 1044055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 1045055c67edSArnaldo Carvalho de Melo event->mmap.header.type = PERF_RECORD_MMAP; 1046055c67edSArnaldo Carvalho de Melo event->mmap.header.size = (sizeof(event->mmap) - 1047055c67edSArnaldo Carvalho de Melo (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); 1048055c67edSArnaldo Carvalho de Melo event->mmap.pgoff = kmap->ref_reloc_sym->addr; 1049055c67edSArnaldo Carvalho de Melo event->mmap.start = map->start; 1050055c67edSArnaldo Carvalho de Melo event->mmap.len = map->end - event->mmap.start; 1051055c67edSArnaldo Carvalho de Melo event->mmap.pid = machine->pid; 1052*978410ffSJiri Olsa } 1053055c67edSArnaldo Carvalho de Melo 1054055c67edSArnaldo Carvalho de Melo err = perf_tool__process_synth_event(tool, event, machine, process); 1055055c67edSArnaldo Carvalho de Melo free(event); 1056055c67edSArnaldo Carvalho de Melo 1057055c67edSArnaldo Carvalho de Melo return err; 1058055c67edSArnaldo Carvalho de Melo } 1059055c67edSArnaldo Carvalho de Melo 1060055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 1061055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1062055c67edSArnaldo Carvalho de Melo struct machine *machine) 1063055c67edSArnaldo Carvalho de Melo { 1064055c67edSArnaldo Carvalho de Melo int err; 1065055c67edSArnaldo Carvalho de Melo 1066055c67edSArnaldo Carvalho de Melo err = __perf_event__synthesize_kernel_mmap(tool, process, machine); 1067055c67edSArnaldo Carvalho de Melo if (err < 0) 1068055c67edSArnaldo Carvalho de Melo return err; 1069055c67edSArnaldo Carvalho de Melo 1070055c67edSArnaldo Carvalho de Melo return perf_event__synthesize_extra_kmaps(tool, process, machine); 1071055c67edSArnaldo Carvalho de Melo } 1072055c67edSArnaldo Carvalho de Melo 1073055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_thread_map2(struct perf_tool *tool, 1074055c67edSArnaldo Carvalho de Melo struct perf_thread_map *threads, 1075055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1076055c67edSArnaldo Carvalho de Melo struct machine *machine) 1077055c67edSArnaldo Carvalho de Melo { 1078055c67edSArnaldo Carvalho de Melo union perf_event *event; 1079055c67edSArnaldo Carvalho de Melo int i, err, size; 1080055c67edSArnaldo Carvalho de Melo 1081055c67edSArnaldo Carvalho de Melo size = sizeof(event->thread_map); 1082055c67edSArnaldo Carvalho de Melo size += threads->nr * sizeof(event->thread_map.entries[0]); 1083055c67edSArnaldo Carvalho de Melo 1084055c67edSArnaldo Carvalho de Melo event = zalloc(size); 1085055c67edSArnaldo Carvalho de Melo if (!event) 1086055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1087055c67edSArnaldo Carvalho de Melo 1088055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_THREAD_MAP; 1089055c67edSArnaldo Carvalho de Melo event->header.size = size; 1090055c67edSArnaldo Carvalho de Melo event->thread_map.nr = threads->nr; 1091055c67edSArnaldo Carvalho de Melo 1092055c67edSArnaldo Carvalho de Melo for (i = 0; i < threads->nr; i++) { 1093055c67edSArnaldo Carvalho de Melo struct perf_record_thread_map_entry *entry = &event->thread_map.entries[i]; 1094055c67edSArnaldo Carvalho de Melo char *comm = perf_thread_map__comm(threads, i); 1095055c67edSArnaldo Carvalho de Melo 1096055c67edSArnaldo Carvalho de Melo if (!comm) 1097055c67edSArnaldo Carvalho de Melo comm = (char *) ""; 1098055c67edSArnaldo Carvalho de Melo 1099055c67edSArnaldo Carvalho de Melo entry->pid = perf_thread_map__pid(threads, i); 1100055c67edSArnaldo Carvalho de Melo strncpy((char *) &entry->comm, comm, sizeof(entry->comm)); 1101055c67edSArnaldo Carvalho de Melo } 1102055c67edSArnaldo Carvalho de Melo 1103055c67edSArnaldo Carvalho de Melo err = process(tool, event, NULL, machine); 1104055c67edSArnaldo Carvalho de Melo 1105055c67edSArnaldo Carvalho de Melo free(event); 1106055c67edSArnaldo Carvalho de Melo return err; 1107055c67edSArnaldo Carvalho de Melo } 1108055c67edSArnaldo Carvalho de Melo 1109055c67edSArnaldo Carvalho de Melo static void synthesize_cpus(struct cpu_map_entries *cpus, 1110055c67edSArnaldo Carvalho de Melo struct perf_cpu_map *map) 1111055c67edSArnaldo Carvalho de Melo { 1112055c67edSArnaldo Carvalho de Melo int i; 1113055c67edSArnaldo Carvalho de Melo 1114055c67edSArnaldo Carvalho de Melo cpus->nr = map->nr; 1115055c67edSArnaldo Carvalho de Melo 1116055c67edSArnaldo Carvalho de Melo for (i = 0; i < map->nr; i++) 1117055c67edSArnaldo Carvalho de Melo cpus->cpu[i] = map->map[i]; 1118055c67edSArnaldo Carvalho de Melo } 1119055c67edSArnaldo Carvalho de Melo 1120055c67edSArnaldo Carvalho de Melo static void synthesize_mask(struct perf_record_record_cpu_map *mask, 1121055c67edSArnaldo Carvalho de Melo struct perf_cpu_map *map, int max) 1122055c67edSArnaldo Carvalho de Melo { 1123055c67edSArnaldo Carvalho de Melo int i; 1124055c67edSArnaldo Carvalho de Melo 1125055c67edSArnaldo Carvalho de Melo mask->nr = BITS_TO_LONGS(max); 1126055c67edSArnaldo Carvalho de Melo mask->long_size = sizeof(long); 1127055c67edSArnaldo Carvalho de Melo 1128055c67edSArnaldo Carvalho de Melo for (i = 0; i < map->nr; i++) 1129055c67edSArnaldo Carvalho de Melo set_bit(map->map[i], mask->mask); 1130055c67edSArnaldo Carvalho de Melo } 1131055c67edSArnaldo Carvalho de Melo 1132055c67edSArnaldo Carvalho de Melo static size_t cpus_size(struct perf_cpu_map *map) 1133055c67edSArnaldo Carvalho de Melo { 1134055c67edSArnaldo Carvalho de Melo return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16); 1135055c67edSArnaldo Carvalho de Melo } 1136055c67edSArnaldo Carvalho de Melo 1137055c67edSArnaldo Carvalho de Melo static size_t mask_size(struct perf_cpu_map *map, int *max) 1138055c67edSArnaldo Carvalho de Melo { 1139055c67edSArnaldo Carvalho de Melo int i; 1140055c67edSArnaldo Carvalho de Melo 1141055c67edSArnaldo Carvalho de Melo *max = 0; 1142055c67edSArnaldo Carvalho de Melo 1143055c67edSArnaldo Carvalho de Melo for (i = 0; i < map->nr; i++) { 1144055c67edSArnaldo Carvalho de Melo /* bit possition of the cpu is + 1 */ 1145055c67edSArnaldo Carvalho de Melo int bit = map->map[i] + 1; 1146055c67edSArnaldo Carvalho de Melo 1147055c67edSArnaldo Carvalho de Melo if (bit > *max) 1148055c67edSArnaldo Carvalho de Melo *max = bit; 1149055c67edSArnaldo Carvalho de Melo } 1150055c67edSArnaldo Carvalho de Melo 1151055c67edSArnaldo Carvalho de Melo return sizeof(struct perf_record_record_cpu_map) + BITS_TO_LONGS(*max) * sizeof(long); 1152055c67edSArnaldo Carvalho de Melo } 1153055c67edSArnaldo Carvalho de Melo 1154055c67edSArnaldo Carvalho de Melo void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max) 1155055c67edSArnaldo Carvalho de Melo { 1156055c67edSArnaldo Carvalho de Melo size_t size_cpus, size_mask; 1157055c67edSArnaldo Carvalho de Melo bool is_dummy = perf_cpu_map__empty(map); 1158055c67edSArnaldo Carvalho de Melo 1159055c67edSArnaldo Carvalho de Melo /* 1160055c67edSArnaldo Carvalho de Melo * Both array and mask data have variable size based 1161055c67edSArnaldo Carvalho de Melo * on the number of cpus and their actual values. 1162055c67edSArnaldo Carvalho de Melo * The size of the 'struct perf_record_cpu_map_data' is: 1163055c67edSArnaldo Carvalho de Melo * 1164055c67edSArnaldo Carvalho de Melo * array = size of 'struct cpu_map_entries' + 1165055c67edSArnaldo Carvalho de Melo * number of cpus * sizeof(u64) 1166055c67edSArnaldo Carvalho de Melo * 1167055c67edSArnaldo Carvalho de Melo * mask = size of 'struct perf_record_record_cpu_map' + 1168055c67edSArnaldo Carvalho de Melo * maximum cpu bit converted to size of longs 1169055c67edSArnaldo Carvalho de Melo * 1170055c67edSArnaldo Carvalho de Melo * and finaly + the size of 'struct perf_record_cpu_map_data'. 1171055c67edSArnaldo Carvalho de Melo */ 1172055c67edSArnaldo Carvalho de Melo size_cpus = cpus_size(map); 1173055c67edSArnaldo Carvalho de Melo size_mask = mask_size(map, max); 1174055c67edSArnaldo Carvalho de Melo 1175055c67edSArnaldo Carvalho de Melo if (is_dummy || (size_cpus < size_mask)) { 1176055c67edSArnaldo Carvalho de Melo *size += size_cpus; 1177055c67edSArnaldo Carvalho de Melo *type = PERF_CPU_MAP__CPUS; 1178055c67edSArnaldo Carvalho de Melo } else { 1179055c67edSArnaldo Carvalho de Melo *size += size_mask; 1180055c67edSArnaldo Carvalho de Melo *type = PERF_CPU_MAP__MASK; 1181055c67edSArnaldo Carvalho de Melo } 1182055c67edSArnaldo Carvalho de Melo 1183055c67edSArnaldo Carvalho de Melo *size += sizeof(struct perf_record_cpu_map_data); 1184055c67edSArnaldo Carvalho de Melo *size = PERF_ALIGN(*size, sizeof(u64)); 1185055c67edSArnaldo Carvalho de Melo return zalloc(*size); 1186055c67edSArnaldo Carvalho de Melo } 1187055c67edSArnaldo Carvalho de Melo 1188055c67edSArnaldo Carvalho de Melo void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map, 1189055c67edSArnaldo Carvalho de Melo u16 type, int max) 1190055c67edSArnaldo Carvalho de Melo { 1191055c67edSArnaldo Carvalho de Melo data->type = type; 1192055c67edSArnaldo Carvalho de Melo 1193055c67edSArnaldo Carvalho de Melo switch (type) { 1194055c67edSArnaldo Carvalho de Melo case PERF_CPU_MAP__CPUS: 1195055c67edSArnaldo Carvalho de Melo synthesize_cpus((struct cpu_map_entries *) data->data, map); 1196055c67edSArnaldo Carvalho de Melo break; 1197055c67edSArnaldo Carvalho de Melo case PERF_CPU_MAP__MASK: 1198055c67edSArnaldo Carvalho de Melo synthesize_mask((struct perf_record_record_cpu_map *)data->data, map, max); 1199055c67edSArnaldo Carvalho de Melo default: 1200055c67edSArnaldo Carvalho de Melo break; 12018284bbeaSZou Wei } 1202055c67edSArnaldo Carvalho de Melo } 1203055c67edSArnaldo Carvalho de Melo 1204055c67edSArnaldo Carvalho de Melo static struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map) 1205055c67edSArnaldo Carvalho de Melo { 1206055c67edSArnaldo Carvalho de Melo size_t size = sizeof(struct perf_record_cpu_map); 1207055c67edSArnaldo Carvalho de Melo struct perf_record_cpu_map *event; 1208055c67edSArnaldo Carvalho de Melo int max; 1209055c67edSArnaldo Carvalho de Melo u16 type; 1210055c67edSArnaldo Carvalho de Melo 1211055c67edSArnaldo Carvalho de Melo event = cpu_map_data__alloc(map, &size, &type, &max); 1212055c67edSArnaldo Carvalho de Melo if (!event) 1213055c67edSArnaldo Carvalho de Melo return NULL; 1214055c67edSArnaldo Carvalho de Melo 1215055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_CPU_MAP; 1216055c67edSArnaldo Carvalho de Melo event->header.size = size; 1217055c67edSArnaldo Carvalho de Melo event->data.type = type; 1218055c67edSArnaldo Carvalho de Melo 1219055c67edSArnaldo Carvalho de Melo cpu_map_data__synthesize(&event->data, map, type, max); 1220055c67edSArnaldo Carvalho de Melo return event; 1221055c67edSArnaldo Carvalho de Melo } 1222055c67edSArnaldo Carvalho de Melo 1223055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_cpu_map(struct perf_tool *tool, 1224055c67edSArnaldo Carvalho de Melo struct perf_cpu_map *map, 1225055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1226055c67edSArnaldo Carvalho de Melo struct machine *machine) 1227055c67edSArnaldo Carvalho de Melo { 1228055c67edSArnaldo Carvalho de Melo struct perf_record_cpu_map *event; 1229055c67edSArnaldo Carvalho de Melo int err; 1230055c67edSArnaldo Carvalho de Melo 1231055c67edSArnaldo Carvalho de Melo event = cpu_map_event__new(map); 1232055c67edSArnaldo Carvalho de Melo if (!event) 1233055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1234055c67edSArnaldo Carvalho de Melo 1235055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *) event, NULL, machine); 1236055c67edSArnaldo Carvalho de Melo 1237055c67edSArnaldo Carvalho de Melo free(event); 1238055c67edSArnaldo Carvalho de Melo return err; 1239055c67edSArnaldo Carvalho de Melo } 1240055c67edSArnaldo Carvalho de Melo 1241055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_config(struct perf_tool *tool, 1242055c67edSArnaldo Carvalho de Melo struct perf_stat_config *config, 1243055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1244055c67edSArnaldo Carvalho de Melo struct machine *machine) 1245055c67edSArnaldo Carvalho de Melo { 1246055c67edSArnaldo Carvalho de Melo struct perf_record_stat_config *event; 1247055c67edSArnaldo Carvalho de Melo int size, i = 0, err; 1248055c67edSArnaldo Carvalho de Melo 1249055c67edSArnaldo Carvalho de Melo size = sizeof(*event); 1250055c67edSArnaldo Carvalho de Melo size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0])); 1251055c67edSArnaldo Carvalho de Melo 1252055c67edSArnaldo Carvalho de Melo event = zalloc(size); 1253055c67edSArnaldo Carvalho de Melo if (!event) 1254055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1255055c67edSArnaldo Carvalho de Melo 1256055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_STAT_CONFIG; 1257055c67edSArnaldo Carvalho de Melo event->header.size = size; 1258055c67edSArnaldo Carvalho de Melo event->nr = PERF_STAT_CONFIG_TERM__MAX; 1259055c67edSArnaldo Carvalho de Melo 1260055c67edSArnaldo Carvalho de Melo #define ADD(__term, __val) \ 1261055c67edSArnaldo Carvalho de Melo event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term; \ 1262055c67edSArnaldo Carvalho de Melo event->data[i].val = __val; \ 1263055c67edSArnaldo Carvalho de Melo i++; 1264055c67edSArnaldo Carvalho de Melo 1265055c67edSArnaldo Carvalho de Melo ADD(AGGR_MODE, config->aggr_mode) 1266055c67edSArnaldo Carvalho de Melo ADD(INTERVAL, config->interval) 1267055c67edSArnaldo Carvalho de Melo ADD(SCALE, config->scale) 1268055c67edSArnaldo Carvalho de Melo 1269055c67edSArnaldo Carvalho de Melo WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX, 1270055c67edSArnaldo Carvalho de Melo "stat config terms unbalanced\n"); 1271055c67edSArnaldo Carvalho de Melo #undef ADD 1272055c67edSArnaldo Carvalho de Melo 1273055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *) event, NULL, machine); 1274055c67edSArnaldo Carvalho de Melo 1275055c67edSArnaldo Carvalho de Melo free(event); 1276055c67edSArnaldo Carvalho de Melo return err; 1277055c67edSArnaldo Carvalho de Melo } 1278055c67edSArnaldo Carvalho de Melo 1279055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat(struct perf_tool *tool, 1280055c67edSArnaldo Carvalho de Melo u32 cpu, u32 thread, u64 id, 1281055c67edSArnaldo Carvalho de Melo struct perf_counts_values *count, 1282055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1283055c67edSArnaldo Carvalho de Melo struct machine *machine) 1284055c67edSArnaldo Carvalho de Melo { 1285055c67edSArnaldo Carvalho de Melo struct perf_record_stat event; 1286055c67edSArnaldo Carvalho de Melo 1287055c67edSArnaldo Carvalho de Melo event.header.type = PERF_RECORD_STAT; 1288055c67edSArnaldo Carvalho de Melo event.header.size = sizeof(event); 1289055c67edSArnaldo Carvalho de Melo event.header.misc = 0; 1290055c67edSArnaldo Carvalho de Melo 1291055c67edSArnaldo Carvalho de Melo event.id = id; 1292055c67edSArnaldo Carvalho de Melo event.cpu = cpu; 1293055c67edSArnaldo Carvalho de Melo event.thread = thread; 1294055c67edSArnaldo Carvalho de Melo event.val = count->val; 1295055c67edSArnaldo Carvalho de Melo event.ena = count->ena; 1296055c67edSArnaldo Carvalho de Melo event.run = count->run; 1297055c67edSArnaldo Carvalho de Melo 1298055c67edSArnaldo Carvalho de Melo return process(tool, (union perf_event *) &event, NULL, machine); 1299055c67edSArnaldo Carvalho de Melo } 1300055c67edSArnaldo Carvalho de Melo 1301055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_round(struct perf_tool *tool, 1302055c67edSArnaldo Carvalho de Melo u64 evtime, u64 type, 1303055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1304055c67edSArnaldo Carvalho de Melo struct machine *machine) 1305055c67edSArnaldo Carvalho de Melo { 1306055c67edSArnaldo Carvalho de Melo struct perf_record_stat_round event; 1307055c67edSArnaldo Carvalho de Melo 1308055c67edSArnaldo Carvalho de Melo event.header.type = PERF_RECORD_STAT_ROUND; 1309055c67edSArnaldo Carvalho de Melo event.header.size = sizeof(event); 1310055c67edSArnaldo Carvalho de Melo event.header.misc = 0; 1311055c67edSArnaldo Carvalho de Melo 1312055c67edSArnaldo Carvalho de Melo event.time = evtime; 1313055c67edSArnaldo Carvalho de Melo event.type = type; 1314055c67edSArnaldo Carvalho de Melo 1315055c67edSArnaldo Carvalho de Melo return process(tool, (union perf_event *) &event, NULL, machine); 1316055c67edSArnaldo Carvalho de Melo } 1317055c67edSArnaldo Carvalho de Melo 1318055c67edSArnaldo Carvalho de Melo size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format) 1319055c67edSArnaldo Carvalho de Melo { 1320055c67edSArnaldo Carvalho de Melo size_t sz, result = sizeof(struct perf_record_sample); 1321055c67edSArnaldo Carvalho de Melo 1322055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IDENTIFIER) 1323055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1324055c67edSArnaldo Carvalho de Melo 1325055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IP) 1326055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1327055c67edSArnaldo Carvalho de Melo 1328055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TID) 1329055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1330055c67edSArnaldo Carvalho de Melo 1331055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TIME) 1332055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1333055c67edSArnaldo Carvalho de Melo 1334055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ADDR) 1335055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1336055c67edSArnaldo Carvalho de Melo 1337055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ID) 1338055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1339055c67edSArnaldo Carvalho de Melo 1340055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STREAM_ID) 1341055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1342055c67edSArnaldo Carvalho de Melo 1343055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CPU) 1344055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1345055c67edSArnaldo Carvalho de Melo 1346055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PERIOD) 1347055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1348055c67edSArnaldo Carvalho de Melo 1349055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_READ) { 1350055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1351055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 1352055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1353055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 1354055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1355055c67edSArnaldo Carvalho de Melo /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 1356055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) { 1357055c67edSArnaldo Carvalho de Melo sz = sample->read.group.nr * 1358055c67edSArnaldo Carvalho de Melo sizeof(struct sample_read_value); 1359055c67edSArnaldo Carvalho de Melo result += sz; 1360055c67edSArnaldo Carvalho de Melo } else { 1361055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1362055c67edSArnaldo Carvalho de Melo } 1363055c67edSArnaldo Carvalho de Melo } 1364055c67edSArnaldo Carvalho de Melo 1365055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CALLCHAIN) { 1366055c67edSArnaldo Carvalho de Melo sz = (sample->callchain->nr + 1) * sizeof(u64); 1367055c67edSArnaldo Carvalho de Melo result += sz; 1368055c67edSArnaldo Carvalho de Melo } 1369055c67edSArnaldo Carvalho de Melo 1370055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_RAW) { 1371055c67edSArnaldo Carvalho de Melo result += sizeof(u32); 1372055c67edSArnaldo Carvalho de Melo result += sample->raw_size; 1373055c67edSArnaldo Carvalho de Melo } 1374055c67edSArnaldo Carvalho de Melo 1375055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_BRANCH_STACK) { 1376055c67edSArnaldo Carvalho de Melo sz = sample->branch_stack->nr * sizeof(struct branch_entry); 137742bbabedSKan Liang /* nr, hw_idx */ 137842bbabedSKan Liang sz += 2 * sizeof(u64); 1379055c67edSArnaldo Carvalho de Melo result += sz; 1380055c67edSArnaldo Carvalho de Melo } 1381055c67edSArnaldo Carvalho de Melo 1382055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_USER) { 1383055c67edSArnaldo Carvalho de Melo if (sample->user_regs.abi) { 1384055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1385055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->user_regs.mask) * sizeof(u64); 1386055c67edSArnaldo Carvalho de Melo result += sz; 1387055c67edSArnaldo Carvalho de Melo } else { 1388055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1389055c67edSArnaldo Carvalho de Melo } 1390055c67edSArnaldo Carvalho de Melo } 1391055c67edSArnaldo Carvalho de Melo 1392055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STACK_USER) { 1393055c67edSArnaldo Carvalho de Melo sz = sample->user_stack.size; 1394055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1395055c67edSArnaldo Carvalho de Melo if (sz) { 1396055c67edSArnaldo Carvalho de Melo result += sz; 1397055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1398055c67edSArnaldo Carvalho de Melo } 1399055c67edSArnaldo Carvalho de Melo } 1400055c67edSArnaldo Carvalho de Melo 1401055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_WEIGHT) 1402055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1403055c67edSArnaldo Carvalho de Melo 1404055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_DATA_SRC) 1405055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1406055c67edSArnaldo Carvalho de Melo 1407055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TRANSACTION) 1408055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1409055c67edSArnaldo Carvalho de Melo 1410055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_INTR) { 1411055c67edSArnaldo Carvalho de Melo if (sample->intr_regs.abi) { 1412055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1413055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 1414055c67edSArnaldo Carvalho de Melo result += sz; 1415055c67edSArnaldo Carvalho de Melo } else { 1416055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1417055c67edSArnaldo Carvalho de Melo } 1418055c67edSArnaldo Carvalho de Melo } 1419055c67edSArnaldo Carvalho de Melo 1420055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PHYS_ADDR) 1421055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1422055c67edSArnaldo Carvalho de Melo 1423ba78c1c5SNamhyung Kim if (type & PERF_SAMPLE_CGROUP) 1424ba78c1c5SNamhyung Kim result += sizeof(u64); 1425ba78c1c5SNamhyung Kim 1426542b88fdSKan Liang if (type & PERF_SAMPLE_DATA_PAGE_SIZE) 1427542b88fdSKan Liang result += sizeof(u64); 1428542b88fdSKan Liang 142998dcf14dSAdrian Hunter if (type & PERF_SAMPLE_AUX) { 143098dcf14dSAdrian Hunter result += sizeof(u64); 143198dcf14dSAdrian Hunter result += sample->aux_sample.size; 143298dcf14dSAdrian Hunter } 143398dcf14dSAdrian Hunter 1434055c67edSArnaldo Carvalho de Melo return result; 1435055c67edSArnaldo Carvalho de Melo } 1436055c67edSArnaldo Carvalho de Melo 1437055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format, 1438055c67edSArnaldo Carvalho de Melo const struct perf_sample *sample) 1439055c67edSArnaldo Carvalho de Melo { 1440055c67edSArnaldo Carvalho de Melo __u64 *array; 1441055c67edSArnaldo Carvalho de Melo size_t sz; 1442055c67edSArnaldo Carvalho de Melo /* 1443055c67edSArnaldo Carvalho de Melo * used for cross-endian analysis. See git commit 65014ab3 1444055c67edSArnaldo Carvalho de Melo * for why this goofiness is needed. 1445055c67edSArnaldo Carvalho de Melo */ 1446055c67edSArnaldo Carvalho de Melo union u64_swap u; 1447055c67edSArnaldo Carvalho de Melo 1448055c67edSArnaldo Carvalho de Melo array = event->sample.array; 1449055c67edSArnaldo Carvalho de Melo 1450055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IDENTIFIER) { 1451055c67edSArnaldo Carvalho de Melo *array = sample->id; 1452055c67edSArnaldo Carvalho de Melo array++; 1453055c67edSArnaldo Carvalho de Melo } 1454055c67edSArnaldo Carvalho de Melo 1455055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IP) { 1456055c67edSArnaldo Carvalho de Melo *array = sample->ip; 1457055c67edSArnaldo Carvalho de Melo array++; 1458055c67edSArnaldo Carvalho de Melo } 1459055c67edSArnaldo Carvalho de Melo 1460055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TID) { 1461055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->pid; 1462055c67edSArnaldo Carvalho de Melo u.val32[1] = sample->tid; 1463055c67edSArnaldo Carvalho de Melo *array = u.val64; 1464055c67edSArnaldo Carvalho de Melo array++; 1465055c67edSArnaldo Carvalho de Melo } 1466055c67edSArnaldo Carvalho de Melo 1467055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TIME) { 1468055c67edSArnaldo Carvalho de Melo *array = sample->time; 1469055c67edSArnaldo Carvalho de Melo array++; 1470055c67edSArnaldo Carvalho de Melo } 1471055c67edSArnaldo Carvalho de Melo 1472055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ADDR) { 1473055c67edSArnaldo Carvalho de Melo *array = sample->addr; 1474055c67edSArnaldo Carvalho de Melo array++; 1475055c67edSArnaldo Carvalho de Melo } 1476055c67edSArnaldo Carvalho de Melo 1477055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ID) { 1478055c67edSArnaldo Carvalho de Melo *array = sample->id; 1479055c67edSArnaldo Carvalho de Melo array++; 1480055c67edSArnaldo Carvalho de Melo } 1481055c67edSArnaldo Carvalho de Melo 1482055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STREAM_ID) { 1483055c67edSArnaldo Carvalho de Melo *array = sample->stream_id; 1484055c67edSArnaldo Carvalho de Melo array++; 1485055c67edSArnaldo Carvalho de Melo } 1486055c67edSArnaldo Carvalho de Melo 1487055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CPU) { 1488055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->cpu; 1489055c67edSArnaldo Carvalho de Melo u.val32[1] = 0; 1490055c67edSArnaldo Carvalho de Melo *array = u.val64; 1491055c67edSArnaldo Carvalho de Melo array++; 1492055c67edSArnaldo Carvalho de Melo } 1493055c67edSArnaldo Carvalho de Melo 1494055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PERIOD) { 1495055c67edSArnaldo Carvalho de Melo *array = sample->period; 1496055c67edSArnaldo Carvalho de Melo array++; 1497055c67edSArnaldo Carvalho de Melo } 1498055c67edSArnaldo Carvalho de Melo 1499055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_READ) { 1500055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) 1501055c67edSArnaldo Carvalho de Melo *array = sample->read.group.nr; 1502055c67edSArnaldo Carvalho de Melo else 1503055c67edSArnaldo Carvalho de Melo *array = sample->read.one.value; 1504055c67edSArnaldo Carvalho de Melo array++; 1505055c67edSArnaldo Carvalho de Melo 1506055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { 1507055c67edSArnaldo Carvalho de Melo *array = sample->read.time_enabled; 1508055c67edSArnaldo Carvalho de Melo array++; 1509055c67edSArnaldo Carvalho de Melo } 1510055c67edSArnaldo Carvalho de Melo 1511055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { 1512055c67edSArnaldo Carvalho de Melo *array = sample->read.time_running; 1513055c67edSArnaldo Carvalho de Melo array++; 1514055c67edSArnaldo Carvalho de Melo } 1515055c67edSArnaldo Carvalho de Melo 1516055c67edSArnaldo Carvalho de Melo /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 1517055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) { 1518055c67edSArnaldo Carvalho de Melo sz = sample->read.group.nr * 1519055c67edSArnaldo Carvalho de Melo sizeof(struct sample_read_value); 1520055c67edSArnaldo Carvalho de Melo memcpy(array, sample->read.group.values, sz); 1521055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1522055c67edSArnaldo Carvalho de Melo } else { 1523055c67edSArnaldo Carvalho de Melo *array = sample->read.one.id; 1524055c67edSArnaldo Carvalho de Melo array++; 1525055c67edSArnaldo Carvalho de Melo } 1526055c67edSArnaldo Carvalho de Melo } 1527055c67edSArnaldo Carvalho de Melo 1528055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CALLCHAIN) { 1529055c67edSArnaldo Carvalho de Melo sz = (sample->callchain->nr + 1) * sizeof(u64); 1530055c67edSArnaldo Carvalho de Melo memcpy(array, sample->callchain, sz); 1531055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1532055c67edSArnaldo Carvalho de Melo } 1533055c67edSArnaldo Carvalho de Melo 1534055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_RAW) { 1535055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->raw_size; 1536055c67edSArnaldo Carvalho de Melo *array = u.val64; 1537055c67edSArnaldo Carvalho de Melo array = (void *)array + sizeof(u32); 1538055c67edSArnaldo Carvalho de Melo 1539055c67edSArnaldo Carvalho de Melo memcpy(array, sample->raw_data, sample->raw_size); 1540055c67edSArnaldo Carvalho de Melo array = (void *)array + sample->raw_size; 1541055c67edSArnaldo Carvalho de Melo } 1542055c67edSArnaldo Carvalho de Melo 1543055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_BRANCH_STACK) { 1544055c67edSArnaldo Carvalho de Melo sz = sample->branch_stack->nr * sizeof(struct branch_entry); 154542bbabedSKan Liang /* nr, hw_idx */ 154642bbabedSKan Liang sz += 2 * sizeof(u64); 1547055c67edSArnaldo Carvalho de Melo memcpy(array, sample->branch_stack, sz); 1548055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1549055c67edSArnaldo Carvalho de Melo } 1550055c67edSArnaldo Carvalho de Melo 1551055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_USER) { 1552055c67edSArnaldo Carvalho de Melo if (sample->user_regs.abi) { 1553055c67edSArnaldo Carvalho de Melo *array++ = sample->user_regs.abi; 1554055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->user_regs.mask) * sizeof(u64); 1555055c67edSArnaldo Carvalho de Melo memcpy(array, sample->user_regs.regs, sz); 1556055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1557055c67edSArnaldo Carvalho de Melo } else { 1558055c67edSArnaldo Carvalho de Melo *array++ = 0; 1559055c67edSArnaldo Carvalho de Melo } 1560055c67edSArnaldo Carvalho de Melo } 1561055c67edSArnaldo Carvalho de Melo 1562055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STACK_USER) { 1563055c67edSArnaldo Carvalho de Melo sz = sample->user_stack.size; 1564055c67edSArnaldo Carvalho de Melo *array++ = sz; 1565055c67edSArnaldo Carvalho de Melo if (sz) { 1566055c67edSArnaldo Carvalho de Melo memcpy(array, sample->user_stack.data, sz); 1567055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1568055c67edSArnaldo Carvalho de Melo *array++ = sz; 1569055c67edSArnaldo Carvalho de Melo } 1570055c67edSArnaldo Carvalho de Melo } 1571055c67edSArnaldo Carvalho de Melo 1572055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_WEIGHT) { 1573055c67edSArnaldo Carvalho de Melo *array = sample->weight; 1574055c67edSArnaldo Carvalho de Melo array++; 1575055c67edSArnaldo Carvalho de Melo } 1576055c67edSArnaldo Carvalho de Melo 1577055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_DATA_SRC) { 1578055c67edSArnaldo Carvalho de Melo *array = sample->data_src; 1579055c67edSArnaldo Carvalho de Melo array++; 1580055c67edSArnaldo Carvalho de Melo } 1581055c67edSArnaldo Carvalho de Melo 1582055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TRANSACTION) { 1583055c67edSArnaldo Carvalho de Melo *array = sample->transaction; 1584055c67edSArnaldo Carvalho de Melo array++; 1585055c67edSArnaldo Carvalho de Melo } 1586055c67edSArnaldo Carvalho de Melo 1587055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_INTR) { 1588055c67edSArnaldo Carvalho de Melo if (sample->intr_regs.abi) { 1589055c67edSArnaldo Carvalho de Melo *array++ = sample->intr_regs.abi; 1590055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 1591055c67edSArnaldo Carvalho de Melo memcpy(array, sample->intr_regs.regs, sz); 1592055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1593055c67edSArnaldo Carvalho de Melo } else { 1594055c67edSArnaldo Carvalho de Melo *array++ = 0; 1595055c67edSArnaldo Carvalho de Melo } 1596055c67edSArnaldo Carvalho de Melo } 1597055c67edSArnaldo Carvalho de Melo 1598055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PHYS_ADDR) { 1599055c67edSArnaldo Carvalho de Melo *array = sample->phys_addr; 1600055c67edSArnaldo Carvalho de Melo array++; 1601055c67edSArnaldo Carvalho de Melo } 1602055c67edSArnaldo Carvalho de Melo 1603ba78c1c5SNamhyung Kim if (type & PERF_SAMPLE_CGROUP) { 1604ba78c1c5SNamhyung Kim *array = sample->cgroup; 1605ba78c1c5SNamhyung Kim array++; 1606ba78c1c5SNamhyung Kim } 1607ba78c1c5SNamhyung Kim 1608542b88fdSKan Liang if (type & PERF_SAMPLE_DATA_PAGE_SIZE) { 1609542b88fdSKan Liang *array = sample->data_page_size; 1610542b88fdSKan Liang array++; 1611542b88fdSKan Liang } 1612542b88fdSKan Liang 161398dcf14dSAdrian Hunter if (type & PERF_SAMPLE_AUX) { 161498dcf14dSAdrian Hunter sz = sample->aux_sample.size; 161598dcf14dSAdrian Hunter *array++ = sz; 161698dcf14dSAdrian Hunter memcpy(array, sample->aux_sample.data, sz); 161798dcf14dSAdrian Hunter array = (void *)array + sz; 161898dcf14dSAdrian Hunter } 161998dcf14dSAdrian Hunter 1620055c67edSArnaldo Carvalho de Melo return 0; 1621055c67edSArnaldo Carvalho de Melo } 1622055c67edSArnaldo Carvalho de Melo 1623055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, 1624055c67edSArnaldo Carvalho de Melo struct evlist *evlist, struct machine *machine) 1625055c67edSArnaldo Carvalho de Melo { 1626055c67edSArnaldo Carvalho de Melo union perf_event *ev; 1627055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 1628055c67edSArnaldo Carvalho de Melo size_t nr = 0, i = 0, sz, max_nr, n; 1629055c67edSArnaldo Carvalho de Melo int err; 1630055c67edSArnaldo Carvalho de Melo 1631055c67edSArnaldo Carvalho de Melo pr_debug2("Synthesizing id index\n"); 1632055c67edSArnaldo Carvalho de Melo 1633055c67edSArnaldo Carvalho de Melo max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / 1634055c67edSArnaldo Carvalho de Melo sizeof(struct id_index_entry); 1635055c67edSArnaldo Carvalho de Melo 1636055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) 1637e7eb9002SJiri Olsa nr += evsel->core.ids; 1638055c67edSArnaldo Carvalho de Melo 1639055c67edSArnaldo Carvalho de Melo n = nr > max_nr ? max_nr : nr; 1640055c67edSArnaldo Carvalho de Melo sz = sizeof(struct perf_record_id_index) + n * sizeof(struct id_index_entry); 1641055c67edSArnaldo Carvalho de Melo ev = zalloc(sz); 1642055c67edSArnaldo Carvalho de Melo if (!ev) 1643055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1644055c67edSArnaldo Carvalho de Melo 1645055c67edSArnaldo Carvalho de Melo ev->id_index.header.type = PERF_RECORD_ID_INDEX; 1646055c67edSArnaldo Carvalho de Melo ev->id_index.header.size = sz; 1647055c67edSArnaldo Carvalho de Melo ev->id_index.nr = n; 1648055c67edSArnaldo Carvalho de Melo 1649055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) { 1650055c67edSArnaldo Carvalho de Melo u32 j; 1651055c67edSArnaldo Carvalho de Melo 1652e7eb9002SJiri Olsa for (j = 0; j < evsel->core.ids; j++) { 1653055c67edSArnaldo Carvalho de Melo struct id_index_entry *e; 1654055c67edSArnaldo Carvalho de Melo struct perf_sample_id *sid; 1655055c67edSArnaldo Carvalho de Melo 1656055c67edSArnaldo Carvalho de Melo if (i >= n) { 1657055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, machine); 1658055c67edSArnaldo Carvalho de Melo if (err) 1659055c67edSArnaldo Carvalho de Melo goto out_err; 1660055c67edSArnaldo Carvalho de Melo nr -= n; 1661055c67edSArnaldo Carvalho de Melo i = 0; 1662055c67edSArnaldo Carvalho de Melo } 1663055c67edSArnaldo Carvalho de Melo 1664055c67edSArnaldo Carvalho de Melo e = &ev->id_index.entries[i++]; 1665055c67edSArnaldo Carvalho de Melo 1666deaf3219SJiri Olsa e->id = evsel->core.id[j]; 1667055c67edSArnaldo Carvalho de Melo 16683ccf8a7bSArnaldo Carvalho de Melo sid = evlist__id2sid(evlist, e->id); 1669055c67edSArnaldo Carvalho de Melo if (!sid) { 1670055c67edSArnaldo Carvalho de Melo free(ev); 1671055c67edSArnaldo Carvalho de Melo return -ENOENT; 1672055c67edSArnaldo Carvalho de Melo } 1673055c67edSArnaldo Carvalho de Melo 1674055c67edSArnaldo Carvalho de Melo e->idx = sid->idx; 1675055c67edSArnaldo Carvalho de Melo e->cpu = sid->cpu; 1676055c67edSArnaldo Carvalho de Melo e->tid = sid->tid; 1677055c67edSArnaldo Carvalho de Melo } 1678055c67edSArnaldo Carvalho de Melo } 1679055c67edSArnaldo Carvalho de Melo 1680055c67edSArnaldo Carvalho de Melo sz = sizeof(struct perf_record_id_index) + nr * sizeof(struct id_index_entry); 1681055c67edSArnaldo Carvalho de Melo ev->id_index.header.size = sz; 1682055c67edSArnaldo Carvalho de Melo ev->id_index.nr = nr; 1683055c67edSArnaldo Carvalho de Melo 1684055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, machine); 1685055c67edSArnaldo Carvalho de Melo out_err: 1686055c67edSArnaldo Carvalho de Melo free(ev); 1687055c67edSArnaldo Carvalho de Melo 1688055c67edSArnaldo Carvalho de Melo return err; 1689055c67edSArnaldo Carvalho de Melo } 1690055c67edSArnaldo Carvalho de Melo 1691055c67edSArnaldo Carvalho de Melo int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, 1692055c67edSArnaldo Carvalho de Melo struct target *target, struct perf_thread_map *threads, 1693055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, bool data_mmap, 1694055c67edSArnaldo Carvalho de Melo unsigned int nr_threads_synthesize) 1695055c67edSArnaldo Carvalho de Melo { 1696055c67edSArnaldo Carvalho de Melo if (target__has_task(target)) 1697055c67edSArnaldo Carvalho de Melo return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap); 1698055c67edSArnaldo Carvalho de Melo else if (target__has_cpu(target)) 1699055c67edSArnaldo Carvalho de Melo return perf_event__synthesize_threads(tool, process, 1700055c67edSArnaldo Carvalho de Melo machine, data_mmap, 1701055c67edSArnaldo Carvalho de Melo nr_threads_synthesize); 1702055c67edSArnaldo Carvalho de Melo /* command specified */ 1703055c67edSArnaldo Carvalho de Melo return 0; 1704055c67edSArnaldo Carvalho de Melo } 1705055c67edSArnaldo Carvalho de Melo 1706055c67edSArnaldo Carvalho de Melo int machine__synthesize_threads(struct machine *machine, struct target *target, 1707055c67edSArnaldo Carvalho de Melo struct perf_thread_map *threads, bool data_mmap, 1708055c67edSArnaldo Carvalho de Melo unsigned int nr_threads_synthesize) 1709055c67edSArnaldo Carvalho de Melo { 1710055c67edSArnaldo Carvalho de Melo return __machine__synthesize_threads(machine, NULL, target, threads, 1711055c67edSArnaldo Carvalho de Melo perf_event__process, data_mmap, 1712055c67edSArnaldo Carvalho de Melo nr_threads_synthesize); 1713055c67edSArnaldo Carvalho de Melo } 1714055c67edSArnaldo Carvalho de Melo 1715055c67edSArnaldo Carvalho de Melo static struct perf_record_event_update *event_update_event__new(size_t size, u64 type, u64 id) 1716055c67edSArnaldo Carvalho de Melo { 1717055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1718055c67edSArnaldo Carvalho de Melo 1719055c67edSArnaldo Carvalho de Melo size += sizeof(*ev); 1720055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 1721055c67edSArnaldo Carvalho de Melo 1722055c67edSArnaldo Carvalho de Melo ev = zalloc(size); 1723055c67edSArnaldo Carvalho de Melo if (ev) { 1724055c67edSArnaldo Carvalho de Melo ev->header.type = PERF_RECORD_EVENT_UPDATE; 1725055c67edSArnaldo Carvalho de Melo ev->header.size = (u16)size; 1726055c67edSArnaldo Carvalho de Melo ev->type = type; 1727055c67edSArnaldo Carvalho de Melo ev->id = id; 1728055c67edSArnaldo Carvalho de Melo } 1729055c67edSArnaldo Carvalho de Melo return ev; 1730055c67edSArnaldo Carvalho de Melo } 1731055c67edSArnaldo Carvalho de Melo 1732055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_unit(struct perf_tool *tool, struct evsel *evsel, 1733055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1734055c67edSArnaldo Carvalho de Melo { 1735055c67edSArnaldo Carvalho de Melo size_t size = strlen(evsel->unit); 1736055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1737055c67edSArnaldo Carvalho de Melo int err; 1738055c67edSArnaldo Carvalho de Melo 1739deaf3219SJiri Olsa ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->core.id[0]); 1740055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1741055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1742055c67edSArnaldo Carvalho de Melo 1743055c67edSArnaldo Carvalho de Melo strlcpy(ev->data, evsel->unit, size + 1); 1744055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1745055c67edSArnaldo Carvalho de Melo free(ev); 1746055c67edSArnaldo Carvalho de Melo return err; 1747055c67edSArnaldo Carvalho de Melo } 1748055c67edSArnaldo Carvalho de Melo 1749055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_scale(struct perf_tool *tool, struct evsel *evsel, 1750055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1751055c67edSArnaldo Carvalho de Melo { 1752055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1753055c67edSArnaldo Carvalho de Melo struct perf_record_event_update_scale *ev_data; 1754055c67edSArnaldo Carvalho de Melo int err; 1755055c67edSArnaldo Carvalho de Melo 1756deaf3219SJiri Olsa ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->core.id[0]); 1757055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1758055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1759055c67edSArnaldo Carvalho de Melo 1760055c67edSArnaldo Carvalho de Melo ev_data = (struct perf_record_event_update_scale *)ev->data; 1761055c67edSArnaldo Carvalho de Melo ev_data->scale = evsel->scale; 1762055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1763055c67edSArnaldo Carvalho de Melo free(ev); 1764055c67edSArnaldo Carvalho de Melo return err; 1765055c67edSArnaldo Carvalho de Melo } 1766055c67edSArnaldo Carvalho de Melo 1767055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_name(struct perf_tool *tool, struct evsel *evsel, 1768055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1769055c67edSArnaldo Carvalho de Melo { 1770055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1771055c67edSArnaldo Carvalho de Melo size_t len = strlen(evsel->name); 1772055c67edSArnaldo Carvalho de Melo int err; 1773055c67edSArnaldo Carvalho de Melo 1774deaf3219SJiri Olsa ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->core.id[0]); 1775055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1776055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1777055c67edSArnaldo Carvalho de Melo 1778055c67edSArnaldo Carvalho de Melo strlcpy(ev->data, evsel->name, len + 1); 1779055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1780055c67edSArnaldo Carvalho de Melo free(ev); 1781055c67edSArnaldo Carvalho de Melo return err; 1782055c67edSArnaldo Carvalho de Melo } 1783055c67edSArnaldo Carvalho de Melo 1784055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, struct evsel *evsel, 1785055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1786055c67edSArnaldo Carvalho de Melo { 1787055c67edSArnaldo Carvalho de Melo size_t size = sizeof(struct perf_record_event_update); 1788055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1789055c67edSArnaldo Carvalho de Melo int max, err; 1790055c67edSArnaldo Carvalho de Melo u16 type; 1791055c67edSArnaldo Carvalho de Melo 1792055c67edSArnaldo Carvalho de Melo if (!evsel->core.own_cpus) 1793055c67edSArnaldo Carvalho de Melo return 0; 1794055c67edSArnaldo Carvalho de Melo 1795055c67edSArnaldo Carvalho de Melo ev = cpu_map_data__alloc(evsel->core.own_cpus, &size, &type, &max); 1796055c67edSArnaldo Carvalho de Melo if (!ev) 1797055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1798055c67edSArnaldo Carvalho de Melo 1799055c67edSArnaldo Carvalho de Melo ev->header.type = PERF_RECORD_EVENT_UPDATE; 1800055c67edSArnaldo Carvalho de Melo ev->header.size = (u16)size; 1801055c67edSArnaldo Carvalho de Melo ev->type = PERF_EVENT_UPDATE__CPUS; 1802deaf3219SJiri Olsa ev->id = evsel->core.id[0]; 1803055c67edSArnaldo Carvalho de Melo 1804055c67edSArnaldo Carvalho de Melo cpu_map_data__synthesize((struct perf_record_cpu_map_data *)ev->data, 1805055c67edSArnaldo Carvalho de Melo evsel->core.own_cpus, type, max); 1806055c67edSArnaldo Carvalho de Melo 1807055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1808055c67edSArnaldo Carvalho de Melo free(ev); 1809055c67edSArnaldo Carvalho de Melo return err; 1810055c67edSArnaldo Carvalho de Melo } 1811055c67edSArnaldo Carvalho de Melo 1812055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_attrs(struct perf_tool *tool, struct evlist *evlist, 1813055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1814055c67edSArnaldo Carvalho de Melo { 1815055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 1816055c67edSArnaldo Carvalho de Melo int err = 0; 1817055c67edSArnaldo Carvalho de Melo 1818055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) { 1819e7eb9002SJiri Olsa err = perf_event__synthesize_attr(tool, &evsel->core.attr, evsel->core.ids, 1820deaf3219SJiri Olsa evsel->core.id, process); 1821055c67edSArnaldo Carvalho de Melo if (err) { 1822055c67edSArnaldo Carvalho de Melo pr_debug("failed to create perf header attribute\n"); 1823055c67edSArnaldo Carvalho de Melo return err; 1824055c67edSArnaldo Carvalho de Melo } 1825055c67edSArnaldo Carvalho de Melo } 1826055c67edSArnaldo Carvalho de Melo 1827055c67edSArnaldo Carvalho de Melo return err; 1828055c67edSArnaldo Carvalho de Melo } 1829055c67edSArnaldo Carvalho de Melo 1830055c67edSArnaldo Carvalho de Melo static bool has_unit(struct evsel *evsel) 1831055c67edSArnaldo Carvalho de Melo { 1832055c67edSArnaldo Carvalho de Melo return evsel->unit && *evsel->unit; 1833055c67edSArnaldo Carvalho de Melo } 1834055c67edSArnaldo Carvalho de Melo 1835055c67edSArnaldo Carvalho de Melo static bool has_scale(struct evsel *evsel) 1836055c67edSArnaldo Carvalho de Melo { 1837055c67edSArnaldo Carvalho de Melo return evsel->scale != 1; 1838055c67edSArnaldo Carvalho de Melo } 1839055c67edSArnaldo Carvalho de Melo 1840055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_extra_attr(struct perf_tool *tool, struct evlist *evsel_list, 1841055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, bool is_pipe) 1842055c67edSArnaldo Carvalho de Melo { 1843055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 1844055c67edSArnaldo Carvalho de Melo int err; 1845055c67edSArnaldo Carvalho de Melo 1846055c67edSArnaldo Carvalho de Melo /* 1847055c67edSArnaldo Carvalho de Melo * Synthesize other events stuff not carried within 1848055c67edSArnaldo Carvalho de Melo * attr event - unit, scale, name 1849055c67edSArnaldo Carvalho de Melo */ 1850055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evsel_list, evsel) { 1851055c67edSArnaldo Carvalho de Melo if (!evsel->supported) 1852055c67edSArnaldo Carvalho de Melo continue; 1853055c67edSArnaldo Carvalho de Melo 1854055c67edSArnaldo Carvalho de Melo /* 1855055c67edSArnaldo Carvalho de Melo * Synthesize unit and scale only if it's defined. 1856055c67edSArnaldo Carvalho de Melo */ 1857055c67edSArnaldo Carvalho de Melo if (has_unit(evsel)) { 1858055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_unit(tool, evsel, process); 1859055c67edSArnaldo Carvalho de Melo if (err < 0) { 1860055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel unit.\n"); 1861055c67edSArnaldo Carvalho de Melo return err; 1862055c67edSArnaldo Carvalho de Melo } 1863055c67edSArnaldo Carvalho de Melo } 1864055c67edSArnaldo Carvalho de Melo 1865055c67edSArnaldo Carvalho de Melo if (has_scale(evsel)) { 1866055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_scale(tool, evsel, process); 1867055c67edSArnaldo Carvalho de Melo if (err < 0) { 1868055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel evsel.\n"); 1869055c67edSArnaldo Carvalho de Melo return err; 1870055c67edSArnaldo Carvalho de Melo } 1871055c67edSArnaldo Carvalho de Melo } 1872055c67edSArnaldo Carvalho de Melo 1873055c67edSArnaldo Carvalho de Melo if (evsel->core.own_cpus) { 1874055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_cpus(tool, evsel, process); 1875055c67edSArnaldo Carvalho de Melo if (err < 0) { 1876055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel cpus.\n"); 1877055c67edSArnaldo Carvalho de Melo return err; 1878055c67edSArnaldo Carvalho de Melo } 1879055c67edSArnaldo Carvalho de Melo } 1880055c67edSArnaldo Carvalho de Melo 1881055c67edSArnaldo Carvalho de Melo /* 1882055c67edSArnaldo Carvalho de Melo * Name is needed only for pipe output, 1883055c67edSArnaldo Carvalho de Melo * perf.data carries event names. 1884055c67edSArnaldo Carvalho de Melo */ 1885055c67edSArnaldo Carvalho de Melo if (is_pipe) { 1886055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_name(tool, evsel, process); 1887055c67edSArnaldo Carvalho de Melo if (err < 0) { 1888055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel name.\n"); 1889055c67edSArnaldo Carvalho de Melo return err; 1890055c67edSArnaldo Carvalho de Melo } 1891055c67edSArnaldo Carvalho de Melo } 1892055c67edSArnaldo Carvalho de Melo } 1893055c67edSArnaldo Carvalho de Melo return 0; 1894055c67edSArnaldo Carvalho de Melo } 1895055c67edSArnaldo Carvalho de Melo 1896055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, 1897055c67edSArnaldo Carvalho de Melo u32 ids, u64 *id, perf_event__handler_t process) 1898055c67edSArnaldo Carvalho de Melo { 1899055c67edSArnaldo Carvalho de Melo union perf_event *ev; 1900055c67edSArnaldo Carvalho de Melo size_t size; 1901055c67edSArnaldo Carvalho de Melo int err; 1902055c67edSArnaldo Carvalho de Melo 1903055c67edSArnaldo Carvalho de Melo size = sizeof(struct perf_event_attr); 1904055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 1905055c67edSArnaldo Carvalho de Melo size += sizeof(struct perf_event_header); 1906055c67edSArnaldo Carvalho de Melo size += ids * sizeof(u64); 1907055c67edSArnaldo Carvalho de Melo 1908055c67edSArnaldo Carvalho de Melo ev = zalloc(size); 1909055c67edSArnaldo Carvalho de Melo 1910055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1911055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1912055c67edSArnaldo Carvalho de Melo 1913055c67edSArnaldo Carvalho de Melo ev->attr.attr = *attr; 1914055c67edSArnaldo Carvalho de Melo memcpy(ev->attr.id, id, ids * sizeof(u64)); 1915055c67edSArnaldo Carvalho de Melo 1916055c67edSArnaldo Carvalho de Melo ev->attr.header.type = PERF_RECORD_HEADER_ATTR; 1917055c67edSArnaldo Carvalho de Melo ev->attr.header.size = (u16)size; 1918055c67edSArnaldo Carvalho de Melo 1919055c67edSArnaldo Carvalho de Melo if (ev->attr.header.size == size) 1920055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, NULL); 1921055c67edSArnaldo Carvalho de Melo else 1922055c67edSArnaldo Carvalho de Melo err = -E2BIG; 1923055c67edSArnaldo Carvalho de Melo 1924055c67edSArnaldo Carvalho de Melo free(ev); 1925055c67edSArnaldo Carvalho de Melo 1926055c67edSArnaldo Carvalho de Melo return err; 1927055c67edSArnaldo Carvalho de Melo } 1928055c67edSArnaldo Carvalho de Melo 1929055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct evlist *evlist, 1930055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1931055c67edSArnaldo Carvalho de Melo { 1932055c67edSArnaldo Carvalho de Melo union perf_event ev; 1933055c67edSArnaldo Carvalho de Melo struct tracing_data *tdata; 1934055c67edSArnaldo Carvalho de Melo ssize_t size = 0, aligned_size = 0, padding; 1935055c67edSArnaldo Carvalho de Melo struct feat_fd ff; 1936055c67edSArnaldo Carvalho de Melo 1937055c67edSArnaldo Carvalho de Melo /* 1938055c67edSArnaldo Carvalho de Melo * We are going to store the size of the data followed 1939055c67edSArnaldo Carvalho de Melo * by the data contents. Since the fd descriptor is a pipe, 1940055c67edSArnaldo Carvalho de Melo * we cannot seek back to store the size of the data once 1941055c67edSArnaldo Carvalho de Melo * we know it. Instead we: 1942055c67edSArnaldo Carvalho de Melo * 1943055c67edSArnaldo Carvalho de Melo * - write the tracing data to the temp file 1944055c67edSArnaldo Carvalho de Melo * - get/write the data size to pipe 1945055c67edSArnaldo Carvalho de Melo * - write the tracing data from the temp file 1946055c67edSArnaldo Carvalho de Melo * to the pipe 1947055c67edSArnaldo Carvalho de Melo */ 1948055c67edSArnaldo Carvalho de Melo tdata = tracing_data_get(&evlist->core.entries, fd, true); 1949055c67edSArnaldo Carvalho de Melo if (!tdata) 1950055c67edSArnaldo Carvalho de Melo return -1; 1951055c67edSArnaldo Carvalho de Melo 1952055c67edSArnaldo Carvalho de Melo memset(&ev, 0, sizeof(ev)); 1953055c67edSArnaldo Carvalho de Melo 1954055c67edSArnaldo Carvalho de Melo ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 1955055c67edSArnaldo Carvalho de Melo size = tdata->size; 1956055c67edSArnaldo Carvalho de Melo aligned_size = PERF_ALIGN(size, sizeof(u64)); 1957055c67edSArnaldo Carvalho de Melo padding = aligned_size - size; 1958055c67edSArnaldo Carvalho de Melo ev.tracing_data.header.size = sizeof(ev.tracing_data); 1959055c67edSArnaldo Carvalho de Melo ev.tracing_data.size = aligned_size; 1960055c67edSArnaldo Carvalho de Melo 1961055c67edSArnaldo Carvalho de Melo process(tool, &ev, NULL, NULL); 1962055c67edSArnaldo Carvalho de Melo 1963055c67edSArnaldo Carvalho de Melo /* 1964055c67edSArnaldo Carvalho de Melo * The put function will copy all the tracing data 1965055c67edSArnaldo Carvalho de Melo * stored in temp file to the pipe. 1966055c67edSArnaldo Carvalho de Melo */ 1967055c67edSArnaldo Carvalho de Melo tracing_data_put(tdata); 1968055c67edSArnaldo Carvalho de Melo 1969055c67edSArnaldo Carvalho de Melo ff = (struct feat_fd){ .fd = fd }; 1970055c67edSArnaldo Carvalho de Melo if (write_padded(&ff, NULL, 0, padding)) 1971055c67edSArnaldo Carvalho de Melo return -1; 1972055c67edSArnaldo Carvalho de Melo 1973055c67edSArnaldo Carvalho de Melo return aligned_size; 1974055c67edSArnaldo Carvalho de Melo } 1975055c67edSArnaldo Carvalho de Melo 1976055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_build_id(struct perf_tool *tool, struct dso *pos, u16 misc, 1977055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, struct machine *machine) 1978055c67edSArnaldo Carvalho de Melo { 1979055c67edSArnaldo Carvalho de Melo union perf_event ev; 1980055c67edSArnaldo Carvalho de Melo size_t len; 1981055c67edSArnaldo Carvalho de Melo 1982055c67edSArnaldo Carvalho de Melo if (!pos->hit) 1983055c67edSArnaldo Carvalho de Melo return 0; 1984055c67edSArnaldo Carvalho de Melo 1985055c67edSArnaldo Carvalho de Melo memset(&ev, 0, sizeof(ev)); 1986055c67edSArnaldo Carvalho de Melo 1987055c67edSArnaldo Carvalho de Melo len = pos->long_name_len + 1; 1988055c67edSArnaldo Carvalho de Melo len = PERF_ALIGN(len, NAME_ALIGN); 19890aba7f03SJiri Olsa memcpy(&ev.build_id.build_id, pos->bid.data, sizeof(pos->bid.data)); 1990055c67edSArnaldo Carvalho de Melo ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; 1991055c67edSArnaldo Carvalho de Melo ev.build_id.header.misc = misc; 1992055c67edSArnaldo Carvalho de Melo ev.build_id.pid = machine->pid; 1993055c67edSArnaldo Carvalho de Melo ev.build_id.header.size = sizeof(ev.build_id) + len; 1994055c67edSArnaldo Carvalho de Melo memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); 1995055c67edSArnaldo Carvalho de Melo 1996055c67edSArnaldo Carvalho de Melo return process(tool, &ev, NULL, machine); 1997055c67edSArnaldo Carvalho de Melo } 1998055c67edSArnaldo Carvalho de Melo 1999055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_events(struct perf_stat_config *config, struct perf_tool *tool, 2000055c67edSArnaldo Carvalho de Melo struct evlist *evlist, perf_event__handler_t process, bool attrs) 2001055c67edSArnaldo Carvalho de Melo { 2002055c67edSArnaldo Carvalho de Melo int err; 2003055c67edSArnaldo Carvalho de Melo 2004055c67edSArnaldo Carvalho de Melo if (attrs) { 2005055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_attrs(tool, evlist, process); 2006055c67edSArnaldo Carvalho de Melo if (err < 0) { 2007055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize attrs.\n"); 2008055c67edSArnaldo Carvalho de Melo return err; 2009055c67edSArnaldo Carvalho de Melo } 2010055c67edSArnaldo Carvalho de Melo } 2011055c67edSArnaldo Carvalho de Melo 2012055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_extra_attr(tool, evlist, process, attrs); 2013055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_thread_map2(tool, evlist->core.threads, process, NULL); 2014055c67edSArnaldo Carvalho de Melo if (err < 0) { 2015055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize thread map.\n"); 2016055c67edSArnaldo Carvalho de Melo return err; 2017055c67edSArnaldo Carvalho de Melo } 2018055c67edSArnaldo Carvalho de Melo 2019055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_cpu_map(tool, evlist->core.cpus, process, NULL); 2020055c67edSArnaldo Carvalho de Melo if (err < 0) { 2021055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize thread map.\n"); 2022055c67edSArnaldo Carvalho de Melo return err; 2023055c67edSArnaldo Carvalho de Melo } 2024055c67edSArnaldo Carvalho de Melo 2025055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_stat_config(tool, config, process, NULL); 2026055c67edSArnaldo Carvalho de Melo if (err < 0) { 2027055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize config.\n"); 2028055c67edSArnaldo Carvalho de Melo return err; 2029055c67edSArnaldo Carvalho de Melo } 2030055c67edSArnaldo Carvalho de Melo 2031055c67edSArnaldo Carvalho de Melo return 0; 2032055c67edSArnaldo Carvalho de Melo } 2033055c67edSArnaldo Carvalho de Melo 2034055c67edSArnaldo Carvalho de Melo extern const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE]; 2035055c67edSArnaldo Carvalho de Melo 2036055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, 2037055c67edSArnaldo Carvalho de Melo struct evlist *evlist, perf_event__handler_t process) 2038055c67edSArnaldo Carvalho de Melo { 2039055c67edSArnaldo Carvalho de Melo struct perf_header *header = &session->header; 2040055c67edSArnaldo Carvalho de Melo struct perf_record_header_feature *fe; 2041055c67edSArnaldo Carvalho de Melo struct feat_fd ff; 2042055c67edSArnaldo Carvalho de Melo size_t sz, sz_hdr; 2043055c67edSArnaldo Carvalho de Melo int feat, ret; 2044055c67edSArnaldo Carvalho de Melo 2045055c67edSArnaldo Carvalho de Melo sz_hdr = sizeof(fe->header); 2046055c67edSArnaldo Carvalho de Melo sz = sizeof(union perf_event); 2047055c67edSArnaldo Carvalho de Melo /* get a nice alignment */ 2048055c67edSArnaldo Carvalho de Melo sz = PERF_ALIGN(sz, page_size); 2049055c67edSArnaldo Carvalho de Melo 2050055c67edSArnaldo Carvalho de Melo memset(&ff, 0, sizeof(ff)); 2051055c67edSArnaldo Carvalho de Melo 2052055c67edSArnaldo Carvalho de Melo ff.buf = malloc(sz); 2053055c67edSArnaldo Carvalho de Melo if (!ff.buf) 2054055c67edSArnaldo Carvalho de Melo return -ENOMEM; 2055055c67edSArnaldo Carvalho de Melo 2056055c67edSArnaldo Carvalho de Melo ff.size = sz - sz_hdr; 2057055c67edSArnaldo Carvalho de Melo ff.ph = &session->header; 2058055c67edSArnaldo Carvalho de Melo 2059055c67edSArnaldo Carvalho de Melo for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { 2060055c67edSArnaldo Carvalho de Melo if (!feat_ops[feat].synthesize) { 2061055c67edSArnaldo Carvalho de Melo pr_debug("No record header feature for header :%d\n", feat); 2062055c67edSArnaldo Carvalho de Melo continue; 2063055c67edSArnaldo Carvalho de Melo } 2064055c67edSArnaldo Carvalho de Melo 2065055c67edSArnaldo Carvalho de Melo ff.offset = sizeof(*fe); 2066055c67edSArnaldo Carvalho de Melo 2067055c67edSArnaldo Carvalho de Melo ret = feat_ops[feat].write(&ff, evlist); 2068055c67edSArnaldo Carvalho de Melo if (ret || ff.offset <= (ssize_t)sizeof(*fe)) { 2069055c67edSArnaldo Carvalho de Melo pr_debug("Error writing feature\n"); 2070055c67edSArnaldo Carvalho de Melo continue; 2071055c67edSArnaldo Carvalho de Melo } 2072055c67edSArnaldo Carvalho de Melo /* ff.buf may have changed due to realloc in do_write() */ 2073055c67edSArnaldo Carvalho de Melo fe = ff.buf; 2074055c67edSArnaldo Carvalho de Melo memset(fe, 0, sizeof(*fe)); 2075055c67edSArnaldo Carvalho de Melo 2076055c67edSArnaldo Carvalho de Melo fe->feat_id = feat; 2077055c67edSArnaldo Carvalho de Melo fe->header.type = PERF_RECORD_HEADER_FEATURE; 2078055c67edSArnaldo Carvalho de Melo fe->header.size = ff.offset; 2079055c67edSArnaldo Carvalho de Melo 2080055c67edSArnaldo Carvalho de Melo ret = process(tool, ff.buf, NULL, NULL); 2081055c67edSArnaldo Carvalho de Melo if (ret) { 2082055c67edSArnaldo Carvalho de Melo free(ff.buf); 2083055c67edSArnaldo Carvalho de Melo return ret; 2084055c67edSArnaldo Carvalho de Melo } 2085055c67edSArnaldo Carvalho de Melo } 2086055c67edSArnaldo Carvalho de Melo 2087055c67edSArnaldo Carvalho de Melo /* Send HEADER_LAST_FEATURE mark. */ 2088055c67edSArnaldo Carvalho de Melo fe = ff.buf; 2089055c67edSArnaldo Carvalho de Melo fe->feat_id = HEADER_LAST_FEATURE; 2090055c67edSArnaldo Carvalho de Melo fe->header.type = PERF_RECORD_HEADER_FEATURE; 2091055c67edSArnaldo Carvalho de Melo fe->header.size = sizeof(*fe); 2092055c67edSArnaldo Carvalho de Melo 2093055c67edSArnaldo Carvalho de Melo ret = process(tool, ff.buf, NULL, NULL); 2094055c67edSArnaldo Carvalho de Melo 2095055c67edSArnaldo Carvalho de Melo free(ff.buf); 2096055c67edSArnaldo Carvalho de Melo return ret; 2097055c67edSArnaldo Carvalho de Melo } 2098