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 { 994055c67edSArnaldo Carvalho de Melo size_t size; 995055c67edSArnaldo Carvalho de Melo struct map *map = machine__kernel_map(machine); 996055c67edSArnaldo Carvalho de Melo struct kmap *kmap; 997055c67edSArnaldo Carvalho de Melo int err; 998055c67edSArnaldo Carvalho de Melo union perf_event *event; 999055c67edSArnaldo Carvalho de Melo 1000055c67edSArnaldo Carvalho de Melo if (map == NULL) 1001055c67edSArnaldo Carvalho de Melo return -1; 1002055c67edSArnaldo Carvalho de Melo 1003055c67edSArnaldo Carvalho de Melo kmap = map__kmap(map); 1004055c67edSArnaldo Carvalho de Melo if (!kmap->ref_reloc_sym) 1005055c67edSArnaldo Carvalho de Melo return -1; 1006055c67edSArnaldo Carvalho de Melo 1007055c67edSArnaldo Carvalho de Melo /* 1008055c67edSArnaldo Carvalho de Melo * We should get this from /sys/kernel/sections/.text, but till that is 1009055c67edSArnaldo Carvalho de Melo * available use this, and after it is use this as a fallback for older 1010055c67edSArnaldo Carvalho de Melo * kernels. 1011055c67edSArnaldo Carvalho de Melo */ 1012055c67edSArnaldo Carvalho de Melo event = zalloc((sizeof(event->mmap) + machine->id_hdr_size)); 1013055c67edSArnaldo Carvalho de Melo if (event == NULL) { 1014055c67edSArnaldo Carvalho de Melo pr_debug("Not enough memory synthesizing mmap event " 1015055c67edSArnaldo Carvalho de Melo "for kernel modules\n"); 1016055c67edSArnaldo Carvalho de Melo return -1; 1017055c67edSArnaldo Carvalho de Melo } 1018055c67edSArnaldo Carvalho de Melo 1019055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) { 1020055c67edSArnaldo Carvalho de Melo /* 1021055c67edSArnaldo Carvalho de Melo * kernel uses PERF_RECORD_MISC_USER for user space maps, 1022055c67edSArnaldo Carvalho de Melo * see kernel/perf_event.c __perf_event_mmap 1023055c67edSArnaldo Carvalho de Melo */ 1024055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_KERNEL; 1025055c67edSArnaldo Carvalho de Melo } else { 1026055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 1027055c67edSArnaldo Carvalho de Melo } 1028055c67edSArnaldo Carvalho de Melo 1029055c67edSArnaldo Carvalho de Melo size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 1030055c67edSArnaldo Carvalho de Melo "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1; 1031055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 1032055c67edSArnaldo Carvalho de Melo event->mmap.header.type = PERF_RECORD_MMAP; 1033055c67edSArnaldo Carvalho de Melo event->mmap.header.size = (sizeof(event->mmap) - 1034055c67edSArnaldo Carvalho de Melo (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); 1035055c67edSArnaldo Carvalho de Melo event->mmap.pgoff = kmap->ref_reloc_sym->addr; 1036055c67edSArnaldo Carvalho de Melo event->mmap.start = map->start; 1037055c67edSArnaldo Carvalho de Melo event->mmap.len = map->end - event->mmap.start; 1038055c67edSArnaldo Carvalho de Melo event->mmap.pid = machine->pid; 1039055c67edSArnaldo Carvalho de Melo 1040055c67edSArnaldo Carvalho de Melo err = perf_tool__process_synth_event(tool, event, machine, process); 1041055c67edSArnaldo Carvalho de Melo free(event); 1042055c67edSArnaldo Carvalho de Melo 1043055c67edSArnaldo Carvalho de Melo return err; 1044055c67edSArnaldo Carvalho de Melo } 1045055c67edSArnaldo Carvalho de Melo 1046055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 1047055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1048055c67edSArnaldo Carvalho de Melo struct machine *machine) 1049055c67edSArnaldo Carvalho de Melo { 1050055c67edSArnaldo Carvalho de Melo int err; 1051055c67edSArnaldo Carvalho de Melo 1052055c67edSArnaldo Carvalho de Melo err = __perf_event__synthesize_kernel_mmap(tool, process, machine); 1053055c67edSArnaldo Carvalho de Melo if (err < 0) 1054055c67edSArnaldo Carvalho de Melo return err; 1055055c67edSArnaldo Carvalho de Melo 1056055c67edSArnaldo Carvalho de Melo return perf_event__synthesize_extra_kmaps(tool, process, machine); 1057055c67edSArnaldo Carvalho de Melo } 1058055c67edSArnaldo Carvalho de Melo 1059055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_thread_map2(struct perf_tool *tool, 1060055c67edSArnaldo Carvalho de Melo struct perf_thread_map *threads, 1061055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1062055c67edSArnaldo Carvalho de Melo struct machine *machine) 1063055c67edSArnaldo Carvalho de Melo { 1064055c67edSArnaldo Carvalho de Melo union perf_event *event; 1065055c67edSArnaldo Carvalho de Melo int i, err, size; 1066055c67edSArnaldo Carvalho de Melo 1067055c67edSArnaldo Carvalho de Melo size = sizeof(event->thread_map); 1068055c67edSArnaldo Carvalho de Melo size += threads->nr * sizeof(event->thread_map.entries[0]); 1069055c67edSArnaldo Carvalho de Melo 1070055c67edSArnaldo Carvalho de Melo event = zalloc(size); 1071055c67edSArnaldo Carvalho de Melo if (!event) 1072055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1073055c67edSArnaldo Carvalho de Melo 1074055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_THREAD_MAP; 1075055c67edSArnaldo Carvalho de Melo event->header.size = size; 1076055c67edSArnaldo Carvalho de Melo event->thread_map.nr = threads->nr; 1077055c67edSArnaldo Carvalho de Melo 1078055c67edSArnaldo Carvalho de Melo for (i = 0; i < threads->nr; i++) { 1079055c67edSArnaldo Carvalho de Melo struct perf_record_thread_map_entry *entry = &event->thread_map.entries[i]; 1080055c67edSArnaldo Carvalho de Melo char *comm = perf_thread_map__comm(threads, i); 1081055c67edSArnaldo Carvalho de Melo 1082055c67edSArnaldo Carvalho de Melo if (!comm) 1083055c67edSArnaldo Carvalho de Melo comm = (char *) ""; 1084055c67edSArnaldo Carvalho de Melo 1085055c67edSArnaldo Carvalho de Melo entry->pid = perf_thread_map__pid(threads, i); 1086055c67edSArnaldo Carvalho de Melo strncpy((char *) &entry->comm, comm, sizeof(entry->comm)); 1087055c67edSArnaldo Carvalho de Melo } 1088055c67edSArnaldo Carvalho de Melo 1089055c67edSArnaldo Carvalho de Melo err = process(tool, event, NULL, machine); 1090055c67edSArnaldo Carvalho de Melo 1091055c67edSArnaldo Carvalho de Melo free(event); 1092055c67edSArnaldo Carvalho de Melo return err; 1093055c67edSArnaldo Carvalho de Melo } 1094055c67edSArnaldo Carvalho de Melo 1095055c67edSArnaldo Carvalho de Melo static void synthesize_cpus(struct cpu_map_entries *cpus, 1096055c67edSArnaldo Carvalho de Melo struct perf_cpu_map *map) 1097055c67edSArnaldo Carvalho de Melo { 1098055c67edSArnaldo Carvalho de Melo int i; 1099055c67edSArnaldo Carvalho de Melo 1100055c67edSArnaldo Carvalho de Melo cpus->nr = map->nr; 1101055c67edSArnaldo Carvalho de Melo 1102055c67edSArnaldo Carvalho de Melo for (i = 0; i < map->nr; i++) 1103055c67edSArnaldo Carvalho de Melo cpus->cpu[i] = map->map[i]; 1104055c67edSArnaldo Carvalho de Melo } 1105055c67edSArnaldo Carvalho de Melo 1106055c67edSArnaldo Carvalho de Melo static void synthesize_mask(struct perf_record_record_cpu_map *mask, 1107055c67edSArnaldo Carvalho de Melo struct perf_cpu_map *map, int max) 1108055c67edSArnaldo Carvalho de Melo { 1109055c67edSArnaldo Carvalho de Melo int i; 1110055c67edSArnaldo Carvalho de Melo 1111055c67edSArnaldo Carvalho de Melo mask->nr = BITS_TO_LONGS(max); 1112055c67edSArnaldo Carvalho de Melo mask->long_size = sizeof(long); 1113055c67edSArnaldo Carvalho de Melo 1114055c67edSArnaldo Carvalho de Melo for (i = 0; i < map->nr; i++) 1115055c67edSArnaldo Carvalho de Melo set_bit(map->map[i], mask->mask); 1116055c67edSArnaldo Carvalho de Melo } 1117055c67edSArnaldo Carvalho de Melo 1118055c67edSArnaldo Carvalho de Melo static size_t cpus_size(struct perf_cpu_map *map) 1119055c67edSArnaldo Carvalho de Melo { 1120055c67edSArnaldo Carvalho de Melo return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16); 1121055c67edSArnaldo Carvalho de Melo } 1122055c67edSArnaldo Carvalho de Melo 1123055c67edSArnaldo Carvalho de Melo static size_t mask_size(struct perf_cpu_map *map, int *max) 1124055c67edSArnaldo Carvalho de Melo { 1125055c67edSArnaldo Carvalho de Melo int i; 1126055c67edSArnaldo Carvalho de Melo 1127055c67edSArnaldo Carvalho de Melo *max = 0; 1128055c67edSArnaldo Carvalho de Melo 1129055c67edSArnaldo Carvalho de Melo for (i = 0; i < map->nr; i++) { 1130055c67edSArnaldo Carvalho de Melo /* bit possition of the cpu is + 1 */ 1131055c67edSArnaldo Carvalho de Melo int bit = map->map[i] + 1; 1132055c67edSArnaldo Carvalho de Melo 1133055c67edSArnaldo Carvalho de Melo if (bit > *max) 1134055c67edSArnaldo Carvalho de Melo *max = bit; 1135055c67edSArnaldo Carvalho de Melo } 1136055c67edSArnaldo Carvalho de Melo 1137055c67edSArnaldo Carvalho de Melo return sizeof(struct perf_record_record_cpu_map) + BITS_TO_LONGS(*max) * sizeof(long); 1138055c67edSArnaldo Carvalho de Melo } 1139055c67edSArnaldo Carvalho de Melo 1140055c67edSArnaldo Carvalho de Melo void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max) 1141055c67edSArnaldo Carvalho de Melo { 1142055c67edSArnaldo Carvalho de Melo size_t size_cpus, size_mask; 1143055c67edSArnaldo Carvalho de Melo bool is_dummy = perf_cpu_map__empty(map); 1144055c67edSArnaldo Carvalho de Melo 1145055c67edSArnaldo Carvalho de Melo /* 1146055c67edSArnaldo Carvalho de Melo * Both array and mask data have variable size based 1147055c67edSArnaldo Carvalho de Melo * on the number of cpus and their actual values. 1148055c67edSArnaldo Carvalho de Melo * The size of the 'struct perf_record_cpu_map_data' is: 1149055c67edSArnaldo Carvalho de Melo * 1150055c67edSArnaldo Carvalho de Melo * array = size of 'struct cpu_map_entries' + 1151055c67edSArnaldo Carvalho de Melo * number of cpus * sizeof(u64) 1152055c67edSArnaldo Carvalho de Melo * 1153055c67edSArnaldo Carvalho de Melo * mask = size of 'struct perf_record_record_cpu_map' + 1154055c67edSArnaldo Carvalho de Melo * maximum cpu bit converted to size of longs 1155055c67edSArnaldo Carvalho de Melo * 1156055c67edSArnaldo Carvalho de Melo * and finaly + the size of 'struct perf_record_cpu_map_data'. 1157055c67edSArnaldo Carvalho de Melo */ 1158055c67edSArnaldo Carvalho de Melo size_cpus = cpus_size(map); 1159055c67edSArnaldo Carvalho de Melo size_mask = mask_size(map, max); 1160055c67edSArnaldo Carvalho de Melo 1161055c67edSArnaldo Carvalho de Melo if (is_dummy || (size_cpus < size_mask)) { 1162055c67edSArnaldo Carvalho de Melo *size += size_cpus; 1163055c67edSArnaldo Carvalho de Melo *type = PERF_CPU_MAP__CPUS; 1164055c67edSArnaldo Carvalho de Melo } else { 1165055c67edSArnaldo Carvalho de Melo *size += size_mask; 1166055c67edSArnaldo Carvalho de Melo *type = PERF_CPU_MAP__MASK; 1167055c67edSArnaldo Carvalho de Melo } 1168055c67edSArnaldo Carvalho de Melo 1169055c67edSArnaldo Carvalho de Melo *size += sizeof(struct perf_record_cpu_map_data); 1170055c67edSArnaldo Carvalho de Melo *size = PERF_ALIGN(*size, sizeof(u64)); 1171055c67edSArnaldo Carvalho de Melo return zalloc(*size); 1172055c67edSArnaldo Carvalho de Melo } 1173055c67edSArnaldo Carvalho de Melo 1174055c67edSArnaldo Carvalho de Melo void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map, 1175055c67edSArnaldo Carvalho de Melo u16 type, int max) 1176055c67edSArnaldo Carvalho de Melo { 1177055c67edSArnaldo Carvalho de Melo data->type = type; 1178055c67edSArnaldo Carvalho de Melo 1179055c67edSArnaldo Carvalho de Melo switch (type) { 1180055c67edSArnaldo Carvalho de Melo case PERF_CPU_MAP__CPUS: 1181055c67edSArnaldo Carvalho de Melo synthesize_cpus((struct cpu_map_entries *) data->data, map); 1182055c67edSArnaldo Carvalho de Melo break; 1183055c67edSArnaldo Carvalho de Melo case PERF_CPU_MAP__MASK: 1184055c67edSArnaldo Carvalho de Melo synthesize_mask((struct perf_record_record_cpu_map *)data->data, map, max); 1185055c67edSArnaldo Carvalho de Melo default: 1186055c67edSArnaldo Carvalho de Melo break; 11878284bbeaSZou Wei } 1188055c67edSArnaldo Carvalho de Melo } 1189055c67edSArnaldo Carvalho de Melo 1190055c67edSArnaldo Carvalho de Melo static struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map) 1191055c67edSArnaldo Carvalho de Melo { 1192055c67edSArnaldo Carvalho de Melo size_t size = sizeof(struct perf_record_cpu_map); 1193055c67edSArnaldo Carvalho de Melo struct perf_record_cpu_map *event; 1194055c67edSArnaldo Carvalho de Melo int max; 1195055c67edSArnaldo Carvalho de Melo u16 type; 1196055c67edSArnaldo Carvalho de Melo 1197055c67edSArnaldo Carvalho de Melo event = cpu_map_data__alloc(map, &size, &type, &max); 1198055c67edSArnaldo Carvalho de Melo if (!event) 1199055c67edSArnaldo Carvalho de Melo return NULL; 1200055c67edSArnaldo Carvalho de Melo 1201055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_CPU_MAP; 1202055c67edSArnaldo Carvalho de Melo event->header.size = size; 1203055c67edSArnaldo Carvalho de Melo event->data.type = type; 1204055c67edSArnaldo Carvalho de Melo 1205055c67edSArnaldo Carvalho de Melo cpu_map_data__synthesize(&event->data, map, type, max); 1206055c67edSArnaldo Carvalho de Melo return event; 1207055c67edSArnaldo Carvalho de Melo } 1208055c67edSArnaldo Carvalho de Melo 1209055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_cpu_map(struct perf_tool *tool, 1210055c67edSArnaldo Carvalho de Melo struct perf_cpu_map *map, 1211055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1212055c67edSArnaldo Carvalho de Melo struct machine *machine) 1213055c67edSArnaldo Carvalho de Melo { 1214055c67edSArnaldo Carvalho de Melo struct perf_record_cpu_map *event; 1215055c67edSArnaldo Carvalho de Melo int err; 1216055c67edSArnaldo Carvalho de Melo 1217055c67edSArnaldo Carvalho de Melo event = cpu_map_event__new(map); 1218055c67edSArnaldo Carvalho de Melo if (!event) 1219055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1220055c67edSArnaldo Carvalho de Melo 1221055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *) event, NULL, machine); 1222055c67edSArnaldo Carvalho de Melo 1223055c67edSArnaldo Carvalho de Melo free(event); 1224055c67edSArnaldo Carvalho de Melo return err; 1225055c67edSArnaldo Carvalho de Melo } 1226055c67edSArnaldo Carvalho de Melo 1227055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_config(struct perf_tool *tool, 1228055c67edSArnaldo Carvalho de Melo struct perf_stat_config *config, 1229055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1230055c67edSArnaldo Carvalho de Melo struct machine *machine) 1231055c67edSArnaldo Carvalho de Melo { 1232055c67edSArnaldo Carvalho de Melo struct perf_record_stat_config *event; 1233055c67edSArnaldo Carvalho de Melo int size, i = 0, err; 1234055c67edSArnaldo Carvalho de Melo 1235055c67edSArnaldo Carvalho de Melo size = sizeof(*event); 1236055c67edSArnaldo Carvalho de Melo size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0])); 1237055c67edSArnaldo Carvalho de Melo 1238055c67edSArnaldo Carvalho de Melo event = zalloc(size); 1239055c67edSArnaldo Carvalho de Melo if (!event) 1240055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1241055c67edSArnaldo Carvalho de Melo 1242055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_STAT_CONFIG; 1243055c67edSArnaldo Carvalho de Melo event->header.size = size; 1244055c67edSArnaldo Carvalho de Melo event->nr = PERF_STAT_CONFIG_TERM__MAX; 1245055c67edSArnaldo Carvalho de Melo 1246055c67edSArnaldo Carvalho de Melo #define ADD(__term, __val) \ 1247055c67edSArnaldo Carvalho de Melo event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term; \ 1248055c67edSArnaldo Carvalho de Melo event->data[i].val = __val; \ 1249055c67edSArnaldo Carvalho de Melo i++; 1250055c67edSArnaldo Carvalho de Melo 1251055c67edSArnaldo Carvalho de Melo ADD(AGGR_MODE, config->aggr_mode) 1252055c67edSArnaldo Carvalho de Melo ADD(INTERVAL, config->interval) 1253055c67edSArnaldo Carvalho de Melo ADD(SCALE, config->scale) 1254055c67edSArnaldo Carvalho de Melo 1255055c67edSArnaldo Carvalho de Melo WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX, 1256055c67edSArnaldo Carvalho de Melo "stat config terms unbalanced\n"); 1257055c67edSArnaldo Carvalho de Melo #undef ADD 1258055c67edSArnaldo Carvalho de Melo 1259055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *) event, NULL, machine); 1260055c67edSArnaldo Carvalho de Melo 1261055c67edSArnaldo Carvalho de Melo free(event); 1262055c67edSArnaldo Carvalho de Melo return err; 1263055c67edSArnaldo Carvalho de Melo } 1264055c67edSArnaldo Carvalho de Melo 1265055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat(struct perf_tool *tool, 1266055c67edSArnaldo Carvalho de Melo u32 cpu, u32 thread, u64 id, 1267055c67edSArnaldo Carvalho de Melo struct perf_counts_values *count, 1268055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1269055c67edSArnaldo Carvalho de Melo struct machine *machine) 1270055c67edSArnaldo Carvalho de Melo { 1271055c67edSArnaldo Carvalho de Melo struct perf_record_stat event; 1272055c67edSArnaldo Carvalho de Melo 1273055c67edSArnaldo Carvalho de Melo event.header.type = PERF_RECORD_STAT; 1274055c67edSArnaldo Carvalho de Melo event.header.size = sizeof(event); 1275055c67edSArnaldo Carvalho de Melo event.header.misc = 0; 1276055c67edSArnaldo Carvalho de Melo 1277055c67edSArnaldo Carvalho de Melo event.id = id; 1278055c67edSArnaldo Carvalho de Melo event.cpu = cpu; 1279055c67edSArnaldo Carvalho de Melo event.thread = thread; 1280055c67edSArnaldo Carvalho de Melo event.val = count->val; 1281055c67edSArnaldo Carvalho de Melo event.ena = count->ena; 1282055c67edSArnaldo Carvalho de Melo event.run = count->run; 1283055c67edSArnaldo Carvalho de Melo 1284055c67edSArnaldo Carvalho de Melo return process(tool, (union perf_event *) &event, NULL, machine); 1285055c67edSArnaldo Carvalho de Melo } 1286055c67edSArnaldo Carvalho de Melo 1287055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_round(struct perf_tool *tool, 1288055c67edSArnaldo Carvalho de Melo u64 evtime, u64 type, 1289055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1290055c67edSArnaldo Carvalho de Melo struct machine *machine) 1291055c67edSArnaldo Carvalho de Melo { 1292055c67edSArnaldo Carvalho de Melo struct perf_record_stat_round event; 1293055c67edSArnaldo Carvalho de Melo 1294055c67edSArnaldo Carvalho de Melo event.header.type = PERF_RECORD_STAT_ROUND; 1295055c67edSArnaldo Carvalho de Melo event.header.size = sizeof(event); 1296055c67edSArnaldo Carvalho de Melo event.header.misc = 0; 1297055c67edSArnaldo Carvalho de Melo 1298055c67edSArnaldo Carvalho de Melo event.time = evtime; 1299055c67edSArnaldo Carvalho de Melo event.type = type; 1300055c67edSArnaldo Carvalho de Melo 1301055c67edSArnaldo Carvalho de Melo return process(tool, (union perf_event *) &event, NULL, machine); 1302055c67edSArnaldo Carvalho de Melo } 1303055c67edSArnaldo Carvalho de Melo 1304055c67edSArnaldo Carvalho de Melo size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format) 1305055c67edSArnaldo Carvalho de Melo { 1306055c67edSArnaldo Carvalho de Melo size_t sz, result = sizeof(struct perf_record_sample); 1307055c67edSArnaldo Carvalho de Melo 1308055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IDENTIFIER) 1309055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1310055c67edSArnaldo Carvalho de Melo 1311055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IP) 1312055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1313055c67edSArnaldo Carvalho de Melo 1314055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TID) 1315055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1316055c67edSArnaldo Carvalho de Melo 1317055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TIME) 1318055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1319055c67edSArnaldo Carvalho de Melo 1320055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ADDR) 1321055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1322055c67edSArnaldo Carvalho de Melo 1323055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ID) 1324055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1325055c67edSArnaldo Carvalho de Melo 1326055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STREAM_ID) 1327055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1328055c67edSArnaldo Carvalho de Melo 1329055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CPU) 1330055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1331055c67edSArnaldo Carvalho de Melo 1332055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PERIOD) 1333055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1334055c67edSArnaldo Carvalho de Melo 1335055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_READ) { 1336055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1337055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 1338055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1339055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 1340055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1341055c67edSArnaldo Carvalho de Melo /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 1342055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) { 1343055c67edSArnaldo Carvalho de Melo sz = sample->read.group.nr * 1344055c67edSArnaldo Carvalho de Melo sizeof(struct sample_read_value); 1345055c67edSArnaldo Carvalho de Melo result += sz; 1346055c67edSArnaldo Carvalho de Melo } else { 1347055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1348055c67edSArnaldo Carvalho de Melo } 1349055c67edSArnaldo Carvalho de Melo } 1350055c67edSArnaldo Carvalho de Melo 1351055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CALLCHAIN) { 1352055c67edSArnaldo Carvalho de Melo sz = (sample->callchain->nr + 1) * sizeof(u64); 1353055c67edSArnaldo Carvalho de Melo result += sz; 1354055c67edSArnaldo Carvalho de Melo } 1355055c67edSArnaldo Carvalho de Melo 1356055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_RAW) { 1357055c67edSArnaldo Carvalho de Melo result += sizeof(u32); 1358055c67edSArnaldo Carvalho de Melo result += sample->raw_size; 1359055c67edSArnaldo Carvalho de Melo } 1360055c67edSArnaldo Carvalho de Melo 1361055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_BRANCH_STACK) { 1362055c67edSArnaldo Carvalho de Melo sz = sample->branch_stack->nr * sizeof(struct branch_entry); 136342bbabedSKan Liang /* nr, hw_idx */ 136442bbabedSKan Liang sz += 2 * sizeof(u64); 1365055c67edSArnaldo Carvalho de Melo result += sz; 1366055c67edSArnaldo Carvalho de Melo } 1367055c67edSArnaldo Carvalho de Melo 1368055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_USER) { 1369055c67edSArnaldo Carvalho de Melo if (sample->user_regs.abi) { 1370055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1371055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->user_regs.mask) * sizeof(u64); 1372055c67edSArnaldo Carvalho de Melo result += sz; 1373055c67edSArnaldo Carvalho de Melo } else { 1374055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1375055c67edSArnaldo Carvalho de Melo } 1376055c67edSArnaldo Carvalho de Melo } 1377055c67edSArnaldo Carvalho de Melo 1378055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STACK_USER) { 1379055c67edSArnaldo Carvalho de Melo sz = sample->user_stack.size; 1380055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1381055c67edSArnaldo Carvalho de Melo if (sz) { 1382055c67edSArnaldo Carvalho de Melo result += sz; 1383055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1384055c67edSArnaldo Carvalho de Melo } 1385055c67edSArnaldo Carvalho de Melo } 1386055c67edSArnaldo Carvalho de Melo 1387055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_WEIGHT) 1388055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1389055c67edSArnaldo Carvalho de Melo 1390055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_DATA_SRC) 1391055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1392055c67edSArnaldo Carvalho de Melo 1393055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TRANSACTION) 1394055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1395055c67edSArnaldo Carvalho de Melo 1396055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_INTR) { 1397055c67edSArnaldo Carvalho de Melo if (sample->intr_regs.abi) { 1398055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1399055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 1400055c67edSArnaldo Carvalho de Melo result += sz; 1401055c67edSArnaldo Carvalho de Melo } else { 1402055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1403055c67edSArnaldo Carvalho de Melo } 1404055c67edSArnaldo Carvalho de Melo } 1405055c67edSArnaldo Carvalho de Melo 1406055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PHYS_ADDR) 1407055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1408055c67edSArnaldo Carvalho de Melo 1409ba78c1c5SNamhyung Kim if (type & PERF_SAMPLE_CGROUP) 1410ba78c1c5SNamhyung Kim result += sizeof(u64); 1411ba78c1c5SNamhyung Kim 1412*542b88fdSKan Liang if (type & PERF_SAMPLE_DATA_PAGE_SIZE) 1413*542b88fdSKan Liang result += sizeof(u64); 1414*542b88fdSKan Liang 141598dcf14dSAdrian Hunter if (type & PERF_SAMPLE_AUX) { 141698dcf14dSAdrian Hunter result += sizeof(u64); 141798dcf14dSAdrian Hunter result += sample->aux_sample.size; 141898dcf14dSAdrian Hunter } 141998dcf14dSAdrian Hunter 1420055c67edSArnaldo Carvalho de Melo return result; 1421055c67edSArnaldo Carvalho de Melo } 1422055c67edSArnaldo Carvalho de Melo 1423055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format, 1424055c67edSArnaldo Carvalho de Melo const struct perf_sample *sample) 1425055c67edSArnaldo Carvalho de Melo { 1426055c67edSArnaldo Carvalho de Melo __u64 *array; 1427055c67edSArnaldo Carvalho de Melo size_t sz; 1428055c67edSArnaldo Carvalho de Melo /* 1429055c67edSArnaldo Carvalho de Melo * used for cross-endian analysis. See git commit 65014ab3 1430055c67edSArnaldo Carvalho de Melo * for why this goofiness is needed. 1431055c67edSArnaldo Carvalho de Melo */ 1432055c67edSArnaldo Carvalho de Melo union u64_swap u; 1433055c67edSArnaldo Carvalho de Melo 1434055c67edSArnaldo Carvalho de Melo array = event->sample.array; 1435055c67edSArnaldo Carvalho de Melo 1436055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IDENTIFIER) { 1437055c67edSArnaldo Carvalho de Melo *array = sample->id; 1438055c67edSArnaldo Carvalho de Melo array++; 1439055c67edSArnaldo Carvalho de Melo } 1440055c67edSArnaldo Carvalho de Melo 1441055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IP) { 1442055c67edSArnaldo Carvalho de Melo *array = sample->ip; 1443055c67edSArnaldo Carvalho de Melo array++; 1444055c67edSArnaldo Carvalho de Melo } 1445055c67edSArnaldo Carvalho de Melo 1446055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TID) { 1447055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->pid; 1448055c67edSArnaldo Carvalho de Melo u.val32[1] = sample->tid; 1449055c67edSArnaldo Carvalho de Melo *array = u.val64; 1450055c67edSArnaldo Carvalho de Melo array++; 1451055c67edSArnaldo Carvalho de Melo } 1452055c67edSArnaldo Carvalho de Melo 1453055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TIME) { 1454055c67edSArnaldo Carvalho de Melo *array = sample->time; 1455055c67edSArnaldo Carvalho de Melo array++; 1456055c67edSArnaldo Carvalho de Melo } 1457055c67edSArnaldo Carvalho de Melo 1458055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ADDR) { 1459055c67edSArnaldo Carvalho de Melo *array = sample->addr; 1460055c67edSArnaldo Carvalho de Melo array++; 1461055c67edSArnaldo Carvalho de Melo } 1462055c67edSArnaldo Carvalho de Melo 1463055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ID) { 1464055c67edSArnaldo Carvalho de Melo *array = sample->id; 1465055c67edSArnaldo Carvalho de Melo array++; 1466055c67edSArnaldo Carvalho de Melo } 1467055c67edSArnaldo Carvalho de Melo 1468055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STREAM_ID) { 1469055c67edSArnaldo Carvalho de Melo *array = sample->stream_id; 1470055c67edSArnaldo Carvalho de Melo array++; 1471055c67edSArnaldo Carvalho de Melo } 1472055c67edSArnaldo Carvalho de Melo 1473055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CPU) { 1474055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->cpu; 1475055c67edSArnaldo Carvalho de Melo u.val32[1] = 0; 1476055c67edSArnaldo Carvalho de Melo *array = u.val64; 1477055c67edSArnaldo Carvalho de Melo array++; 1478055c67edSArnaldo Carvalho de Melo } 1479055c67edSArnaldo Carvalho de Melo 1480055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PERIOD) { 1481055c67edSArnaldo Carvalho de Melo *array = sample->period; 1482055c67edSArnaldo Carvalho de Melo array++; 1483055c67edSArnaldo Carvalho de Melo } 1484055c67edSArnaldo Carvalho de Melo 1485055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_READ) { 1486055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) 1487055c67edSArnaldo Carvalho de Melo *array = sample->read.group.nr; 1488055c67edSArnaldo Carvalho de Melo else 1489055c67edSArnaldo Carvalho de Melo *array = sample->read.one.value; 1490055c67edSArnaldo Carvalho de Melo array++; 1491055c67edSArnaldo Carvalho de Melo 1492055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { 1493055c67edSArnaldo Carvalho de Melo *array = sample->read.time_enabled; 1494055c67edSArnaldo Carvalho de Melo array++; 1495055c67edSArnaldo Carvalho de Melo } 1496055c67edSArnaldo Carvalho de Melo 1497055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { 1498055c67edSArnaldo Carvalho de Melo *array = sample->read.time_running; 1499055c67edSArnaldo Carvalho de Melo array++; 1500055c67edSArnaldo Carvalho de Melo } 1501055c67edSArnaldo Carvalho de Melo 1502055c67edSArnaldo Carvalho de Melo /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 1503055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) { 1504055c67edSArnaldo Carvalho de Melo sz = sample->read.group.nr * 1505055c67edSArnaldo Carvalho de Melo sizeof(struct sample_read_value); 1506055c67edSArnaldo Carvalho de Melo memcpy(array, sample->read.group.values, sz); 1507055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1508055c67edSArnaldo Carvalho de Melo } else { 1509055c67edSArnaldo Carvalho de Melo *array = sample->read.one.id; 1510055c67edSArnaldo Carvalho de Melo array++; 1511055c67edSArnaldo Carvalho de Melo } 1512055c67edSArnaldo Carvalho de Melo } 1513055c67edSArnaldo Carvalho de Melo 1514055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CALLCHAIN) { 1515055c67edSArnaldo Carvalho de Melo sz = (sample->callchain->nr + 1) * sizeof(u64); 1516055c67edSArnaldo Carvalho de Melo memcpy(array, sample->callchain, sz); 1517055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1518055c67edSArnaldo Carvalho de Melo } 1519055c67edSArnaldo Carvalho de Melo 1520055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_RAW) { 1521055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->raw_size; 1522055c67edSArnaldo Carvalho de Melo *array = u.val64; 1523055c67edSArnaldo Carvalho de Melo array = (void *)array + sizeof(u32); 1524055c67edSArnaldo Carvalho de Melo 1525055c67edSArnaldo Carvalho de Melo memcpy(array, sample->raw_data, sample->raw_size); 1526055c67edSArnaldo Carvalho de Melo array = (void *)array + sample->raw_size; 1527055c67edSArnaldo Carvalho de Melo } 1528055c67edSArnaldo Carvalho de Melo 1529055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_BRANCH_STACK) { 1530055c67edSArnaldo Carvalho de Melo sz = sample->branch_stack->nr * sizeof(struct branch_entry); 153142bbabedSKan Liang /* nr, hw_idx */ 153242bbabedSKan Liang sz += 2 * sizeof(u64); 1533055c67edSArnaldo Carvalho de Melo memcpy(array, sample->branch_stack, sz); 1534055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1535055c67edSArnaldo Carvalho de Melo } 1536055c67edSArnaldo Carvalho de Melo 1537055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_USER) { 1538055c67edSArnaldo Carvalho de Melo if (sample->user_regs.abi) { 1539055c67edSArnaldo Carvalho de Melo *array++ = sample->user_regs.abi; 1540055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->user_regs.mask) * sizeof(u64); 1541055c67edSArnaldo Carvalho de Melo memcpy(array, sample->user_regs.regs, sz); 1542055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1543055c67edSArnaldo Carvalho de Melo } else { 1544055c67edSArnaldo Carvalho de Melo *array++ = 0; 1545055c67edSArnaldo Carvalho de Melo } 1546055c67edSArnaldo Carvalho de Melo } 1547055c67edSArnaldo Carvalho de Melo 1548055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STACK_USER) { 1549055c67edSArnaldo Carvalho de Melo sz = sample->user_stack.size; 1550055c67edSArnaldo Carvalho de Melo *array++ = sz; 1551055c67edSArnaldo Carvalho de Melo if (sz) { 1552055c67edSArnaldo Carvalho de Melo memcpy(array, sample->user_stack.data, sz); 1553055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1554055c67edSArnaldo Carvalho de Melo *array++ = sz; 1555055c67edSArnaldo Carvalho de Melo } 1556055c67edSArnaldo Carvalho de Melo } 1557055c67edSArnaldo Carvalho de Melo 1558055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_WEIGHT) { 1559055c67edSArnaldo Carvalho de Melo *array = sample->weight; 1560055c67edSArnaldo Carvalho de Melo array++; 1561055c67edSArnaldo Carvalho de Melo } 1562055c67edSArnaldo Carvalho de Melo 1563055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_DATA_SRC) { 1564055c67edSArnaldo Carvalho de Melo *array = sample->data_src; 1565055c67edSArnaldo Carvalho de Melo array++; 1566055c67edSArnaldo Carvalho de Melo } 1567055c67edSArnaldo Carvalho de Melo 1568055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TRANSACTION) { 1569055c67edSArnaldo Carvalho de Melo *array = sample->transaction; 1570055c67edSArnaldo Carvalho de Melo array++; 1571055c67edSArnaldo Carvalho de Melo } 1572055c67edSArnaldo Carvalho de Melo 1573055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_INTR) { 1574055c67edSArnaldo Carvalho de Melo if (sample->intr_regs.abi) { 1575055c67edSArnaldo Carvalho de Melo *array++ = sample->intr_regs.abi; 1576055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 1577055c67edSArnaldo Carvalho de Melo memcpy(array, sample->intr_regs.regs, sz); 1578055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1579055c67edSArnaldo Carvalho de Melo } else { 1580055c67edSArnaldo Carvalho de Melo *array++ = 0; 1581055c67edSArnaldo Carvalho de Melo } 1582055c67edSArnaldo Carvalho de Melo } 1583055c67edSArnaldo Carvalho de Melo 1584055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PHYS_ADDR) { 1585055c67edSArnaldo Carvalho de Melo *array = sample->phys_addr; 1586055c67edSArnaldo Carvalho de Melo array++; 1587055c67edSArnaldo Carvalho de Melo } 1588055c67edSArnaldo Carvalho de Melo 1589ba78c1c5SNamhyung Kim if (type & PERF_SAMPLE_CGROUP) { 1590ba78c1c5SNamhyung Kim *array = sample->cgroup; 1591ba78c1c5SNamhyung Kim array++; 1592ba78c1c5SNamhyung Kim } 1593ba78c1c5SNamhyung Kim 1594*542b88fdSKan Liang if (type & PERF_SAMPLE_DATA_PAGE_SIZE) { 1595*542b88fdSKan Liang *array = sample->data_page_size; 1596*542b88fdSKan Liang array++; 1597*542b88fdSKan Liang } 1598*542b88fdSKan Liang 159998dcf14dSAdrian Hunter if (type & PERF_SAMPLE_AUX) { 160098dcf14dSAdrian Hunter sz = sample->aux_sample.size; 160198dcf14dSAdrian Hunter *array++ = sz; 160298dcf14dSAdrian Hunter memcpy(array, sample->aux_sample.data, sz); 160398dcf14dSAdrian Hunter array = (void *)array + sz; 160498dcf14dSAdrian Hunter } 160598dcf14dSAdrian Hunter 1606055c67edSArnaldo Carvalho de Melo return 0; 1607055c67edSArnaldo Carvalho de Melo } 1608055c67edSArnaldo Carvalho de Melo 1609055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, 1610055c67edSArnaldo Carvalho de Melo struct evlist *evlist, struct machine *machine) 1611055c67edSArnaldo Carvalho de Melo { 1612055c67edSArnaldo Carvalho de Melo union perf_event *ev; 1613055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 1614055c67edSArnaldo Carvalho de Melo size_t nr = 0, i = 0, sz, max_nr, n; 1615055c67edSArnaldo Carvalho de Melo int err; 1616055c67edSArnaldo Carvalho de Melo 1617055c67edSArnaldo Carvalho de Melo pr_debug2("Synthesizing id index\n"); 1618055c67edSArnaldo Carvalho de Melo 1619055c67edSArnaldo Carvalho de Melo max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / 1620055c67edSArnaldo Carvalho de Melo sizeof(struct id_index_entry); 1621055c67edSArnaldo Carvalho de Melo 1622055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) 1623e7eb9002SJiri Olsa nr += evsel->core.ids; 1624055c67edSArnaldo Carvalho de Melo 1625055c67edSArnaldo Carvalho de Melo n = nr > max_nr ? max_nr : nr; 1626055c67edSArnaldo Carvalho de Melo sz = sizeof(struct perf_record_id_index) + n * sizeof(struct id_index_entry); 1627055c67edSArnaldo Carvalho de Melo ev = zalloc(sz); 1628055c67edSArnaldo Carvalho de Melo if (!ev) 1629055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1630055c67edSArnaldo Carvalho de Melo 1631055c67edSArnaldo Carvalho de Melo ev->id_index.header.type = PERF_RECORD_ID_INDEX; 1632055c67edSArnaldo Carvalho de Melo ev->id_index.header.size = sz; 1633055c67edSArnaldo Carvalho de Melo ev->id_index.nr = n; 1634055c67edSArnaldo Carvalho de Melo 1635055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) { 1636055c67edSArnaldo Carvalho de Melo u32 j; 1637055c67edSArnaldo Carvalho de Melo 1638e7eb9002SJiri Olsa for (j = 0; j < evsel->core.ids; j++) { 1639055c67edSArnaldo Carvalho de Melo struct id_index_entry *e; 1640055c67edSArnaldo Carvalho de Melo struct perf_sample_id *sid; 1641055c67edSArnaldo Carvalho de Melo 1642055c67edSArnaldo Carvalho de Melo if (i >= n) { 1643055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, machine); 1644055c67edSArnaldo Carvalho de Melo if (err) 1645055c67edSArnaldo Carvalho de Melo goto out_err; 1646055c67edSArnaldo Carvalho de Melo nr -= n; 1647055c67edSArnaldo Carvalho de Melo i = 0; 1648055c67edSArnaldo Carvalho de Melo } 1649055c67edSArnaldo Carvalho de Melo 1650055c67edSArnaldo Carvalho de Melo e = &ev->id_index.entries[i++]; 1651055c67edSArnaldo Carvalho de Melo 1652deaf3219SJiri Olsa e->id = evsel->core.id[j]; 1653055c67edSArnaldo Carvalho de Melo 16543ccf8a7bSArnaldo Carvalho de Melo sid = evlist__id2sid(evlist, e->id); 1655055c67edSArnaldo Carvalho de Melo if (!sid) { 1656055c67edSArnaldo Carvalho de Melo free(ev); 1657055c67edSArnaldo Carvalho de Melo return -ENOENT; 1658055c67edSArnaldo Carvalho de Melo } 1659055c67edSArnaldo Carvalho de Melo 1660055c67edSArnaldo Carvalho de Melo e->idx = sid->idx; 1661055c67edSArnaldo Carvalho de Melo e->cpu = sid->cpu; 1662055c67edSArnaldo Carvalho de Melo e->tid = sid->tid; 1663055c67edSArnaldo Carvalho de Melo } 1664055c67edSArnaldo Carvalho de Melo } 1665055c67edSArnaldo Carvalho de Melo 1666055c67edSArnaldo Carvalho de Melo sz = sizeof(struct perf_record_id_index) + nr * sizeof(struct id_index_entry); 1667055c67edSArnaldo Carvalho de Melo ev->id_index.header.size = sz; 1668055c67edSArnaldo Carvalho de Melo ev->id_index.nr = nr; 1669055c67edSArnaldo Carvalho de Melo 1670055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, machine); 1671055c67edSArnaldo Carvalho de Melo out_err: 1672055c67edSArnaldo Carvalho de Melo free(ev); 1673055c67edSArnaldo Carvalho de Melo 1674055c67edSArnaldo Carvalho de Melo return err; 1675055c67edSArnaldo Carvalho de Melo } 1676055c67edSArnaldo Carvalho de Melo 1677055c67edSArnaldo Carvalho de Melo int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, 1678055c67edSArnaldo Carvalho de Melo struct target *target, struct perf_thread_map *threads, 1679055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, bool data_mmap, 1680055c67edSArnaldo Carvalho de Melo unsigned int nr_threads_synthesize) 1681055c67edSArnaldo Carvalho de Melo { 1682055c67edSArnaldo Carvalho de Melo if (target__has_task(target)) 1683055c67edSArnaldo Carvalho de Melo return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap); 1684055c67edSArnaldo Carvalho de Melo else if (target__has_cpu(target)) 1685055c67edSArnaldo Carvalho de Melo return perf_event__synthesize_threads(tool, process, 1686055c67edSArnaldo Carvalho de Melo machine, data_mmap, 1687055c67edSArnaldo Carvalho de Melo nr_threads_synthesize); 1688055c67edSArnaldo Carvalho de Melo /* command specified */ 1689055c67edSArnaldo Carvalho de Melo return 0; 1690055c67edSArnaldo Carvalho de Melo } 1691055c67edSArnaldo Carvalho de Melo 1692055c67edSArnaldo Carvalho de Melo int machine__synthesize_threads(struct machine *machine, struct target *target, 1693055c67edSArnaldo Carvalho de Melo struct perf_thread_map *threads, bool data_mmap, 1694055c67edSArnaldo Carvalho de Melo unsigned int nr_threads_synthesize) 1695055c67edSArnaldo Carvalho de Melo { 1696055c67edSArnaldo Carvalho de Melo return __machine__synthesize_threads(machine, NULL, target, threads, 1697055c67edSArnaldo Carvalho de Melo perf_event__process, data_mmap, 1698055c67edSArnaldo Carvalho de Melo nr_threads_synthesize); 1699055c67edSArnaldo Carvalho de Melo } 1700055c67edSArnaldo Carvalho de Melo 1701055c67edSArnaldo Carvalho de Melo static struct perf_record_event_update *event_update_event__new(size_t size, u64 type, u64 id) 1702055c67edSArnaldo Carvalho de Melo { 1703055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1704055c67edSArnaldo Carvalho de Melo 1705055c67edSArnaldo Carvalho de Melo size += sizeof(*ev); 1706055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 1707055c67edSArnaldo Carvalho de Melo 1708055c67edSArnaldo Carvalho de Melo ev = zalloc(size); 1709055c67edSArnaldo Carvalho de Melo if (ev) { 1710055c67edSArnaldo Carvalho de Melo ev->header.type = PERF_RECORD_EVENT_UPDATE; 1711055c67edSArnaldo Carvalho de Melo ev->header.size = (u16)size; 1712055c67edSArnaldo Carvalho de Melo ev->type = type; 1713055c67edSArnaldo Carvalho de Melo ev->id = id; 1714055c67edSArnaldo Carvalho de Melo } 1715055c67edSArnaldo Carvalho de Melo return ev; 1716055c67edSArnaldo Carvalho de Melo } 1717055c67edSArnaldo Carvalho de Melo 1718055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_unit(struct perf_tool *tool, struct evsel *evsel, 1719055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1720055c67edSArnaldo Carvalho de Melo { 1721055c67edSArnaldo Carvalho de Melo size_t size = strlen(evsel->unit); 1722055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1723055c67edSArnaldo Carvalho de Melo int err; 1724055c67edSArnaldo Carvalho de Melo 1725deaf3219SJiri Olsa ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->core.id[0]); 1726055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1727055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1728055c67edSArnaldo Carvalho de Melo 1729055c67edSArnaldo Carvalho de Melo strlcpy(ev->data, evsel->unit, size + 1); 1730055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1731055c67edSArnaldo Carvalho de Melo free(ev); 1732055c67edSArnaldo Carvalho de Melo return err; 1733055c67edSArnaldo Carvalho de Melo } 1734055c67edSArnaldo Carvalho de Melo 1735055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_scale(struct perf_tool *tool, struct evsel *evsel, 1736055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1737055c67edSArnaldo Carvalho de Melo { 1738055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1739055c67edSArnaldo Carvalho de Melo struct perf_record_event_update_scale *ev_data; 1740055c67edSArnaldo Carvalho de Melo int err; 1741055c67edSArnaldo Carvalho de Melo 1742deaf3219SJiri Olsa ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->core.id[0]); 1743055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1744055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1745055c67edSArnaldo Carvalho de Melo 1746055c67edSArnaldo Carvalho de Melo ev_data = (struct perf_record_event_update_scale *)ev->data; 1747055c67edSArnaldo Carvalho de Melo ev_data->scale = evsel->scale; 1748055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1749055c67edSArnaldo Carvalho de Melo free(ev); 1750055c67edSArnaldo Carvalho de Melo return err; 1751055c67edSArnaldo Carvalho de Melo } 1752055c67edSArnaldo Carvalho de Melo 1753055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_name(struct perf_tool *tool, struct evsel *evsel, 1754055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1755055c67edSArnaldo Carvalho de Melo { 1756055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1757055c67edSArnaldo Carvalho de Melo size_t len = strlen(evsel->name); 1758055c67edSArnaldo Carvalho de Melo int err; 1759055c67edSArnaldo Carvalho de Melo 1760deaf3219SJiri Olsa ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->core.id[0]); 1761055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1762055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1763055c67edSArnaldo Carvalho de Melo 1764055c67edSArnaldo Carvalho de Melo strlcpy(ev->data, evsel->name, len + 1); 1765055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1766055c67edSArnaldo Carvalho de Melo free(ev); 1767055c67edSArnaldo Carvalho de Melo return err; 1768055c67edSArnaldo Carvalho de Melo } 1769055c67edSArnaldo Carvalho de Melo 1770055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, struct evsel *evsel, 1771055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1772055c67edSArnaldo Carvalho de Melo { 1773055c67edSArnaldo Carvalho de Melo size_t size = sizeof(struct perf_record_event_update); 1774055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1775055c67edSArnaldo Carvalho de Melo int max, err; 1776055c67edSArnaldo Carvalho de Melo u16 type; 1777055c67edSArnaldo Carvalho de Melo 1778055c67edSArnaldo Carvalho de Melo if (!evsel->core.own_cpus) 1779055c67edSArnaldo Carvalho de Melo return 0; 1780055c67edSArnaldo Carvalho de Melo 1781055c67edSArnaldo Carvalho de Melo ev = cpu_map_data__alloc(evsel->core.own_cpus, &size, &type, &max); 1782055c67edSArnaldo Carvalho de Melo if (!ev) 1783055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1784055c67edSArnaldo Carvalho de Melo 1785055c67edSArnaldo Carvalho de Melo ev->header.type = PERF_RECORD_EVENT_UPDATE; 1786055c67edSArnaldo Carvalho de Melo ev->header.size = (u16)size; 1787055c67edSArnaldo Carvalho de Melo ev->type = PERF_EVENT_UPDATE__CPUS; 1788deaf3219SJiri Olsa ev->id = evsel->core.id[0]; 1789055c67edSArnaldo Carvalho de Melo 1790055c67edSArnaldo Carvalho de Melo cpu_map_data__synthesize((struct perf_record_cpu_map_data *)ev->data, 1791055c67edSArnaldo Carvalho de Melo evsel->core.own_cpus, type, max); 1792055c67edSArnaldo Carvalho de Melo 1793055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1794055c67edSArnaldo Carvalho de Melo free(ev); 1795055c67edSArnaldo Carvalho de Melo return err; 1796055c67edSArnaldo Carvalho de Melo } 1797055c67edSArnaldo Carvalho de Melo 1798055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_attrs(struct perf_tool *tool, struct evlist *evlist, 1799055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1800055c67edSArnaldo Carvalho de Melo { 1801055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 1802055c67edSArnaldo Carvalho de Melo int err = 0; 1803055c67edSArnaldo Carvalho de Melo 1804055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) { 1805e7eb9002SJiri Olsa err = perf_event__synthesize_attr(tool, &evsel->core.attr, evsel->core.ids, 1806deaf3219SJiri Olsa evsel->core.id, process); 1807055c67edSArnaldo Carvalho de Melo if (err) { 1808055c67edSArnaldo Carvalho de Melo pr_debug("failed to create perf header attribute\n"); 1809055c67edSArnaldo Carvalho de Melo return err; 1810055c67edSArnaldo Carvalho de Melo } 1811055c67edSArnaldo Carvalho de Melo } 1812055c67edSArnaldo Carvalho de Melo 1813055c67edSArnaldo Carvalho de Melo return err; 1814055c67edSArnaldo Carvalho de Melo } 1815055c67edSArnaldo Carvalho de Melo 1816055c67edSArnaldo Carvalho de Melo static bool has_unit(struct evsel *evsel) 1817055c67edSArnaldo Carvalho de Melo { 1818055c67edSArnaldo Carvalho de Melo return evsel->unit && *evsel->unit; 1819055c67edSArnaldo Carvalho de Melo } 1820055c67edSArnaldo Carvalho de Melo 1821055c67edSArnaldo Carvalho de Melo static bool has_scale(struct evsel *evsel) 1822055c67edSArnaldo Carvalho de Melo { 1823055c67edSArnaldo Carvalho de Melo return evsel->scale != 1; 1824055c67edSArnaldo Carvalho de Melo } 1825055c67edSArnaldo Carvalho de Melo 1826055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_extra_attr(struct perf_tool *tool, struct evlist *evsel_list, 1827055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, bool is_pipe) 1828055c67edSArnaldo Carvalho de Melo { 1829055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 1830055c67edSArnaldo Carvalho de Melo int err; 1831055c67edSArnaldo Carvalho de Melo 1832055c67edSArnaldo Carvalho de Melo /* 1833055c67edSArnaldo Carvalho de Melo * Synthesize other events stuff not carried within 1834055c67edSArnaldo Carvalho de Melo * attr event - unit, scale, name 1835055c67edSArnaldo Carvalho de Melo */ 1836055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evsel_list, evsel) { 1837055c67edSArnaldo Carvalho de Melo if (!evsel->supported) 1838055c67edSArnaldo Carvalho de Melo continue; 1839055c67edSArnaldo Carvalho de Melo 1840055c67edSArnaldo Carvalho de Melo /* 1841055c67edSArnaldo Carvalho de Melo * Synthesize unit and scale only if it's defined. 1842055c67edSArnaldo Carvalho de Melo */ 1843055c67edSArnaldo Carvalho de Melo if (has_unit(evsel)) { 1844055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_unit(tool, evsel, process); 1845055c67edSArnaldo Carvalho de Melo if (err < 0) { 1846055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel unit.\n"); 1847055c67edSArnaldo Carvalho de Melo return err; 1848055c67edSArnaldo Carvalho de Melo } 1849055c67edSArnaldo Carvalho de Melo } 1850055c67edSArnaldo Carvalho de Melo 1851055c67edSArnaldo Carvalho de Melo if (has_scale(evsel)) { 1852055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_scale(tool, evsel, process); 1853055c67edSArnaldo Carvalho de Melo if (err < 0) { 1854055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel evsel.\n"); 1855055c67edSArnaldo Carvalho de Melo return err; 1856055c67edSArnaldo Carvalho de Melo } 1857055c67edSArnaldo Carvalho de Melo } 1858055c67edSArnaldo Carvalho de Melo 1859055c67edSArnaldo Carvalho de Melo if (evsel->core.own_cpus) { 1860055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_cpus(tool, evsel, process); 1861055c67edSArnaldo Carvalho de Melo if (err < 0) { 1862055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel cpus.\n"); 1863055c67edSArnaldo Carvalho de Melo return err; 1864055c67edSArnaldo Carvalho de Melo } 1865055c67edSArnaldo Carvalho de Melo } 1866055c67edSArnaldo Carvalho de Melo 1867055c67edSArnaldo Carvalho de Melo /* 1868055c67edSArnaldo Carvalho de Melo * Name is needed only for pipe output, 1869055c67edSArnaldo Carvalho de Melo * perf.data carries event names. 1870055c67edSArnaldo Carvalho de Melo */ 1871055c67edSArnaldo Carvalho de Melo if (is_pipe) { 1872055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_name(tool, evsel, process); 1873055c67edSArnaldo Carvalho de Melo if (err < 0) { 1874055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel name.\n"); 1875055c67edSArnaldo Carvalho de Melo return err; 1876055c67edSArnaldo Carvalho de Melo } 1877055c67edSArnaldo Carvalho de Melo } 1878055c67edSArnaldo Carvalho de Melo } 1879055c67edSArnaldo Carvalho de Melo return 0; 1880055c67edSArnaldo Carvalho de Melo } 1881055c67edSArnaldo Carvalho de Melo 1882055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, 1883055c67edSArnaldo Carvalho de Melo u32 ids, u64 *id, perf_event__handler_t process) 1884055c67edSArnaldo Carvalho de Melo { 1885055c67edSArnaldo Carvalho de Melo union perf_event *ev; 1886055c67edSArnaldo Carvalho de Melo size_t size; 1887055c67edSArnaldo Carvalho de Melo int err; 1888055c67edSArnaldo Carvalho de Melo 1889055c67edSArnaldo Carvalho de Melo size = sizeof(struct perf_event_attr); 1890055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 1891055c67edSArnaldo Carvalho de Melo size += sizeof(struct perf_event_header); 1892055c67edSArnaldo Carvalho de Melo size += ids * sizeof(u64); 1893055c67edSArnaldo Carvalho de Melo 1894055c67edSArnaldo Carvalho de Melo ev = zalloc(size); 1895055c67edSArnaldo Carvalho de Melo 1896055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1897055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1898055c67edSArnaldo Carvalho de Melo 1899055c67edSArnaldo Carvalho de Melo ev->attr.attr = *attr; 1900055c67edSArnaldo Carvalho de Melo memcpy(ev->attr.id, id, ids * sizeof(u64)); 1901055c67edSArnaldo Carvalho de Melo 1902055c67edSArnaldo Carvalho de Melo ev->attr.header.type = PERF_RECORD_HEADER_ATTR; 1903055c67edSArnaldo Carvalho de Melo ev->attr.header.size = (u16)size; 1904055c67edSArnaldo Carvalho de Melo 1905055c67edSArnaldo Carvalho de Melo if (ev->attr.header.size == size) 1906055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, NULL); 1907055c67edSArnaldo Carvalho de Melo else 1908055c67edSArnaldo Carvalho de Melo err = -E2BIG; 1909055c67edSArnaldo Carvalho de Melo 1910055c67edSArnaldo Carvalho de Melo free(ev); 1911055c67edSArnaldo Carvalho de Melo 1912055c67edSArnaldo Carvalho de Melo return err; 1913055c67edSArnaldo Carvalho de Melo } 1914055c67edSArnaldo Carvalho de Melo 1915055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct evlist *evlist, 1916055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1917055c67edSArnaldo Carvalho de Melo { 1918055c67edSArnaldo Carvalho de Melo union perf_event ev; 1919055c67edSArnaldo Carvalho de Melo struct tracing_data *tdata; 1920055c67edSArnaldo Carvalho de Melo ssize_t size = 0, aligned_size = 0, padding; 1921055c67edSArnaldo Carvalho de Melo struct feat_fd ff; 1922055c67edSArnaldo Carvalho de Melo 1923055c67edSArnaldo Carvalho de Melo /* 1924055c67edSArnaldo Carvalho de Melo * We are going to store the size of the data followed 1925055c67edSArnaldo Carvalho de Melo * by the data contents. Since the fd descriptor is a pipe, 1926055c67edSArnaldo Carvalho de Melo * we cannot seek back to store the size of the data once 1927055c67edSArnaldo Carvalho de Melo * we know it. Instead we: 1928055c67edSArnaldo Carvalho de Melo * 1929055c67edSArnaldo Carvalho de Melo * - write the tracing data to the temp file 1930055c67edSArnaldo Carvalho de Melo * - get/write the data size to pipe 1931055c67edSArnaldo Carvalho de Melo * - write the tracing data from the temp file 1932055c67edSArnaldo Carvalho de Melo * to the pipe 1933055c67edSArnaldo Carvalho de Melo */ 1934055c67edSArnaldo Carvalho de Melo tdata = tracing_data_get(&evlist->core.entries, fd, true); 1935055c67edSArnaldo Carvalho de Melo if (!tdata) 1936055c67edSArnaldo Carvalho de Melo return -1; 1937055c67edSArnaldo Carvalho de Melo 1938055c67edSArnaldo Carvalho de Melo memset(&ev, 0, sizeof(ev)); 1939055c67edSArnaldo Carvalho de Melo 1940055c67edSArnaldo Carvalho de Melo ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 1941055c67edSArnaldo Carvalho de Melo size = tdata->size; 1942055c67edSArnaldo Carvalho de Melo aligned_size = PERF_ALIGN(size, sizeof(u64)); 1943055c67edSArnaldo Carvalho de Melo padding = aligned_size - size; 1944055c67edSArnaldo Carvalho de Melo ev.tracing_data.header.size = sizeof(ev.tracing_data); 1945055c67edSArnaldo Carvalho de Melo ev.tracing_data.size = aligned_size; 1946055c67edSArnaldo Carvalho de Melo 1947055c67edSArnaldo Carvalho de Melo process(tool, &ev, NULL, NULL); 1948055c67edSArnaldo Carvalho de Melo 1949055c67edSArnaldo Carvalho de Melo /* 1950055c67edSArnaldo Carvalho de Melo * The put function will copy all the tracing data 1951055c67edSArnaldo Carvalho de Melo * stored in temp file to the pipe. 1952055c67edSArnaldo Carvalho de Melo */ 1953055c67edSArnaldo Carvalho de Melo tracing_data_put(tdata); 1954055c67edSArnaldo Carvalho de Melo 1955055c67edSArnaldo Carvalho de Melo ff = (struct feat_fd){ .fd = fd }; 1956055c67edSArnaldo Carvalho de Melo if (write_padded(&ff, NULL, 0, padding)) 1957055c67edSArnaldo Carvalho de Melo return -1; 1958055c67edSArnaldo Carvalho de Melo 1959055c67edSArnaldo Carvalho de Melo return aligned_size; 1960055c67edSArnaldo Carvalho de Melo } 1961055c67edSArnaldo Carvalho de Melo 1962055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_build_id(struct perf_tool *tool, struct dso *pos, u16 misc, 1963055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, struct machine *machine) 1964055c67edSArnaldo Carvalho de Melo { 1965055c67edSArnaldo Carvalho de Melo union perf_event ev; 1966055c67edSArnaldo Carvalho de Melo size_t len; 1967055c67edSArnaldo Carvalho de Melo 1968055c67edSArnaldo Carvalho de Melo if (!pos->hit) 1969055c67edSArnaldo Carvalho de Melo return 0; 1970055c67edSArnaldo Carvalho de Melo 1971055c67edSArnaldo Carvalho de Melo memset(&ev, 0, sizeof(ev)); 1972055c67edSArnaldo Carvalho de Melo 1973055c67edSArnaldo Carvalho de Melo len = pos->long_name_len + 1; 1974055c67edSArnaldo Carvalho de Melo len = PERF_ALIGN(len, NAME_ALIGN); 19750aba7f03SJiri Olsa memcpy(&ev.build_id.build_id, pos->bid.data, sizeof(pos->bid.data)); 1976055c67edSArnaldo Carvalho de Melo ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; 1977055c67edSArnaldo Carvalho de Melo ev.build_id.header.misc = misc; 1978055c67edSArnaldo Carvalho de Melo ev.build_id.pid = machine->pid; 1979055c67edSArnaldo Carvalho de Melo ev.build_id.header.size = sizeof(ev.build_id) + len; 1980055c67edSArnaldo Carvalho de Melo memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); 1981055c67edSArnaldo Carvalho de Melo 1982055c67edSArnaldo Carvalho de Melo return process(tool, &ev, NULL, machine); 1983055c67edSArnaldo Carvalho de Melo } 1984055c67edSArnaldo Carvalho de Melo 1985055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_events(struct perf_stat_config *config, struct perf_tool *tool, 1986055c67edSArnaldo Carvalho de Melo struct evlist *evlist, perf_event__handler_t process, bool attrs) 1987055c67edSArnaldo Carvalho de Melo { 1988055c67edSArnaldo Carvalho de Melo int err; 1989055c67edSArnaldo Carvalho de Melo 1990055c67edSArnaldo Carvalho de Melo if (attrs) { 1991055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_attrs(tool, evlist, process); 1992055c67edSArnaldo Carvalho de Melo if (err < 0) { 1993055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize attrs.\n"); 1994055c67edSArnaldo Carvalho de Melo return err; 1995055c67edSArnaldo Carvalho de Melo } 1996055c67edSArnaldo Carvalho de Melo } 1997055c67edSArnaldo Carvalho de Melo 1998055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_extra_attr(tool, evlist, process, attrs); 1999055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_thread_map2(tool, evlist->core.threads, process, NULL); 2000055c67edSArnaldo Carvalho de Melo if (err < 0) { 2001055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize thread map.\n"); 2002055c67edSArnaldo Carvalho de Melo return err; 2003055c67edSArnaldo Carvalho de Melo } 2004055c67edSArnaldo Carvalho de Melo 2005055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_cpu_map(tool, evlist->core.cpus, process, NULL); 2006055c67edSArnaldo Carvalho de Melo if (err < 0) { 2007055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize thread map.\n"); 2008055c67edSArnaldo Carvalho de Melo return err; 2009055c67edSArnaldo Carvalho de Melo } 2010055c67edSArnaldo Carvalho de Melo 2011055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_stat_config(tool, config, process, NULL); 2012055c67edSArnaldo Carvalho de Melo if (err < 0) { 2013055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize config.\n"); 2014055c67edSArnaldo Carvalho de Melo return err; 2015055c67edSArnaldo Carvalho de Melo } 2016055c67edSArnaldo Carvalho de Melo 2017055c67edSArnaldo Carvalho de Melo return 0; 2018055c67edSArnaldo Carvalho de Melo } 2019055c67edSArnaldo Carvalho de Melo 2020055c67edSArnaldo Carvalho de Melo extern const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE]; 2021055c67edSArnaldo Carvalho de Melo 2022055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, 2023055c67edSArnaldo Carvalho de Melo struct evlist *evlist, perf_event__handler_t process) 2024055c67edSArnaldo Carvalho de Melo { 2025055c67edSArnaldo Carvalho de Melo struct perf_header *header = &session->header; 2026055c67edSArnaldo Carvalho de Melo struct perf_record_header_feature *fe; 2027055c67edSArnaldo Carvalho de Melo struct feat_fd ff; 2028055c67edSArnaldo Carvalho de Melo size_t sz, sz_hdr; 2029055c67edSArnaldo Carvalho de Melo int feat, ret; 2030055c67edSArnaldo Carvalho de Melo 2031055c67edSArnaldo Carvalho de Melo sz_hdr = sizeof(fe->header); 2032055c67edSArnaldo Carvalho de Melo sz = sizeof(union perf_event); 2033055c67edSArnaldo Carvalho de Melo /* get a nice alignment */ 2034055c67edSArnaldo Carvalho de Melo sz = PERF_ALIGN(sz, page_size); 2035055c67edSArnaldo Carvalho de Melo 2036055c67edSArnaldo Carvalho de Melo memset(&ff, 0, sizeof(ff)); 2037055c67edSArnaldo Carvalho de Melo 2038055c67edSArnaldo Carvalho de Melo ff.buf = malloc(sz); 2039055c67edSArnaldo Carvalho de Melo if (!ff.buf) 2040055c67edSArnaldo Carvalho de Melo return -ENOMEM; 2041055c67edSArnaldo Carvalho de Melo 2042055c67edSArnaldo Carvalho de Melo ff.size = sz - sz_hdr; 2043055c67edSArnaldo Carvalho de Melo ff.ph = &session->header; 2044055c67edSArnaldo Carvalho de Melo 2045055c67edSArnaldo Carvalho de Melo for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { 2046055c67edSArnaldo Carvalho de Melo if (!feat_ops[feat].synthesize) { 2047055c67edSArnaldo Carvalho de Melo pr_debug("No record header feature for header :%d\n", feat); 2048055c67edSArnaldo Carvalho de Melo continue; 2049055c67edSArnaldo Carvalho de Melo } 2050055c67edSArnaldo Carvalho de Melo 2051055c67edSArnaldo Carvalho de Melo ff.offset = sizeof(*fe); 2052055c67edSArnaldo Carvalho de Melo 2053055c67edSArnaldo Carvalho de Melo ret = feat_ops[feat].write(&ff, evlist); 2054055c67edSArnaldo Carvalho de Melo if (ret || ff.offset <= (ssize_t)sizeof(*fe)) { 2055055c67edSArnaldo Carvalho de Melo pr_debug("Error writing feature\n"); 2056055c67edSArnaldo Carvalho de Melo continue; 2057055c67edSArnaldo Carvalho de Melo } 2058055c67edSArnaldo Carvalho de Melo /* ff.buf may have changed due to realloc in do_write() */ 2059055c67edSArnaldo Carvalho de Melo fe = ff.buf; 2060055c67edSArnaldo Carvalho de Melo memset(fe, 0, sizeof(*fe)); 2061055c67edSArnaldo Carvalho de Melo 2062055c67edSArnaldo Carvalho de Melo fe->feat_id = feat; 2063055c67edSArnaldo Carvalho de Melo fe->header.type = PERF_RECORD_HEADER_FEATURE; 2064055c67edSArnaldo Carvalho de Melo fe->header.size = ff.offset; 2065055c67edSArnaldo Carvalho de Melo 2066055c67edSArnaldo Carvalho de Melo ret = process(tool, ff.buf, NULL, NULL); 2067055c67edSArnaldo Carvalho de Melo if (ret) { 2068055c67edSArnaldo Carvalho de Melo free(ff.buf); 2069055c67edSArnaldo Carvalho de Melo return ret; 2070055c67edSArnaldo Carvalho de Melo } 2071055c67edSArnaldo Carvalho de Melo } 2072055c67edSArnaldo Carvalho de Melo 2073055c67edSArnaldo Carvalho de Melo /* Send HEADER_LAST_FEATURE mark. */ 2074055c67edSArnaldo Carvalho de Melo fe = ff.buf; 2075055c67edSArnaldo Carvalho de Melo fe->feat_id = HEADER_LAST_FEATURE; 2076055c67edSArnaldo Carvalho de Melo fe->header.type = PERF_RECORD_HEADER_FEATURE; 2077055c67edSArnaldo Carvalho de Melo fe->header.size = sizeof(*fe); 2078055c67edSArnaldo Carvalho de Melo 2079055c67edSArnaldo Carvalho de Melo ret = process(tool, ff.buf, NULL, NULL); 2080055c67edSArnaldo Carvalho de Melo 2081055c67edSArnaldo Carvalho de Melo free(ff.buf); 2082055c67edSArnaldo Carvalho de Melo return ret; 2083055c67edSArnaldo Carvalho de Melo } 2084