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" 19055c67edSArnaldo Carvalho de Melo #include <linux/bitops.h> 20055c67edSArnaldo Carvalho de Melo #include <linux/kernel.h> 21055c67edSArnaldo Carvalho de Melo #include <linux/string.h> 22055c67edSArnaldo Carvalho de Melo #include <linux/zalloc.h> 23055c67edSArnaldo Carvalho de Melo #include <linux/perf_event.h> 24055c67edSArnaldo Carvalho de Melo #include <asm/bug.h> 25055c67edSArnaldo Carvalho de Melo #include <perf/evsel.h> 26055c67edSArnaldo Carvalho de Melo #include <internal/cpumap.h> 27055c67edSArnaldo Carvalho de Melo #include <perf/cpumap.h> 2820f2be1dSJiri Olsa #include <internal/lib.h> // page_size 29055c67edSArnaldo Carvalho de Melo #include <internal/threadmap.h> 30055c67edSArnaldo Carvalho de Melo #include <perf/threadmap.h> 31055c67edSArnaldo Carvalho de Melo #include <symbol/kallsyms.h> 32055c67edSArnaldo Carvalho de Melo #include <dirent.h> 33055c67edSArnaldo Carvalho de Melo #include <errno.h> 34055c67edSArnaldo Carvalho de Melo #include <inttypes.h> 35055c67edSArnaldo Carvalho de Melo #include <stdio.h> 36055c67edSArnaldo Carvalho de Melo #include <string.h> 37055c67edSArnaldo Carvalho de Melo #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ 38055c67edSArnaldo Carvalho de Melo #include <api/fs/fs.h> 39055c67edSArnaldo Carvalho de Melo #include <sys/types.h> 40055c67edSArnaldo Carvalho de Melo #include <sys/stat.h> 41055c67edSArnaldo Carvalho de Melo #include <fcntl.h> 42055c67edSArnaldo Carvalho de Melo #include <unistd.h> 43055c67edSArnaldo Carvalho de Melo 44055c67edSArnaldo Carvalho de Melo #define DEFAULT_PROC_MAP_PARSE_TIMEOUT 500 45055c67edSArnaldo Carvalho de Melo 46055c67edSArnaldo Carvalho de Melo unsigned int proc_map_timeout = DEFAULT_PROC_MAP_PARSE_TIMEOUT; 47055c67edSArnaldo Carvalho de Melo 48055c67edSArnaldo Carvalho de Melo int perf_tool__process_synth_event(struct perf_tool *tool, 49055c67edSArnaldo Carvalho de Melo union perf_event *event, 50055c67edSArnaldo Carvalho de Melo struct machine *machine, 51055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 52055c67edSArnaldo Carvalho de Melo { 53055c67edSArnaldo Carvalho de Melo struct perf_sample synth_sample = { 54055c67edSArnaldo Carvalho de Melo .pid = -1, 55055c67edSArnaldo Carvalho de Melo .tid = -1, 56055c67edSArnaldo Carvalho de Melo .time = -1, 57055c67edSArnaldo Carvalho de Melo .stream_id = -1, 58055c67edSArnaldo Carvalho de Melo .cpu = -1, 59055c67edSArnaldo Carvalho de Melo .period = 1, 60055c67edSArnaldo Carvalho de Melo .cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK, 61055c67edSArnaldo Carvalho de Melo }; 62055c67edSArnaldo Carvalho de Melo 63055c67edSArnaldo Carvalho de Melo return process(tool, event, &synth_sample, machine); 64055c67edSArnaldo Carvalho de Melo }; 65055c67edSArnaldo Carvalho de Melo 66055c67edSArnaldo Carvalho de Melo /* 67055c67edSArnaldo Carvalho de Melo * Assumes that the first 4095 bytes of /proc/pid/stat contains 68055c67edSArnaldo Carvalho de Melo * the comm, tgid and ppid. 69055c67edSArnaldo Carvalho de Melo */ 70055c67edSArnaldo Carvalho de Melo static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len, 71055c67edSArnaldo Carvalho de Melo pid_t *tgid, pid_t *ppid) 72055c67edSArnaldo Carvalho de Melo { 73055c67edSArnaldo Carvalho de Melo char filename[PATH_MAX]; 74055c67edSArnaldo Carvalho de Melo char bf[4096]; 75055c67edSArnaldo Carvalho de Melo int fd; 76055c67edSArnaldo Carvalho de Melo size_t size = 0; 77055c67edSArnaldo Carvalho de Melo ssize_t n; 78055c67edSArnaldo Carvalho de Melo char *name, *tgids, *ppids; 79055c67edSArnaldo Carvalho de Melo 80055c67edSArnaldo Carvalho de Melo *tgid = -1; 81055c67edSArnaldo Carvalho de Melo *ppid = -1; 82055c67edSArnaldo Carvalho de Melo 83055c67edSArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), "/proc/%d/status", pid); 84055c67edSArnaldo Carvalho de Melo 85055c67edSArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 86055c67edSArnaldo Carvalho de Melo if (fd < 0) { 87055c67edSArnaldo Carvalho de Melo pr_debug("couldn't open %s\n", filename); 88055c67edSArnaldo Carvalho de Melo return -1; 89055c67edSArnaldo Carvalho de Melo } 90055c67edSArnaldo Carvalho de Melo 91055c67edSArnaldo Carvalho de Melo n = read(fd, bf, sizeof(bf) - 1); 92055c67edSArnaldo Carvalho de Melo close(fd); 93055c67edSArnaldo Carvalho de Melo if (n <= 0) { 94055c67edSArnaldo Carvalho de Melo pr_warning("Couldn't get COMM, tigd and ppid for pid %d\n", 95055c67edSArnaldo Carvalho de Melo pid); 96055c67edSArnaldo Carvalho de Melo return -1; 97055c67edSArnaldo Carvalho de Melo } 98055c67edSArnaldo Carvalho de Melo bf[n] = '\0'; 99055c67edSArnaldo Carvalho de Melo 100055c67edSArnaldo Carvalho de Melo name = strstr(bf, "Name:"); 101055c67edSArnaldo Carvalho de Melo tgids = strstr(bf, "Tgid:"); 102055c67edSArnaldo Carvalho de Melo ppids = strstr(bf, "PPid:"); 103055c67edSArnaldo Carvalho de Melo 104055c67edSArnaldo Carvalho de Melo if (name) { 105055c67edSArnaldo Carvalho de Melo char *nl; 106055c67edSArnaldo Carvalho de Melo 107055c67edSArnaldo Carvalho de Melo name = skip_spaces(name + 5); /* strlen("Name:") */ 108055c67edSArnaldo Carvalho de Melo nl = strchr(name, '\n'); 109055c67edSArnaldo Carvalho de Melo if (nl) 110055c67edSArnaldo Carvalho de Melo *nl = '\0'; 111055c67edSArnaldo Carvalho de Melo 112055c67edSArnaldo Carvalho de Melo size = strlen(name); 113055c67edSArnaldo Carvalho de Melo if (size >= len) 114055c67edSArnaldo Carvalho de Melo size = len - 1; 115055c67edSArnaldo Carvalho de Melo memcpy(comm, name, size); 116055c67edSArnaldo Carvalho de Melo comm[size] = '\0'; 117055c67edSArnaldo Carvalho de Melo } else { 118055c67edSArnaldo Carvalho de Melo pr_debug("Name: string not found for pid %d\n", pid); 119055c67edSArnaldo Carvalho de Melo } 120055c67edSArnaldo Carvalho de Melo 121055c67edSArnaldo Carvalho de Melo if (tgids) { 122055c67edSArnaldo Carvalho de Melo tgids += 5; /* strlen("Tgid:") */ 123055c67edSArnaldo Carvalho de Melo *tgid = atoi(tgids); 124055c67edSArnaldo Carvalho de Melo } else { 125055c67edSArnaldo Carvalho de Melo pr_debug("Tgid: string not found for pid %d\n", pid); 126055c67edSArnaldo Carvalho de Melo } 127055c67edSArnaldo Carvalho de Melo 128055c67edSArnaldo Carvalho de Melo if (ppids) { 129055c67edSArnaldo Carvalho de Melo ppids += 5; /* strlen("PPid:") */ 130055c67edSArnaldo Carvalho de Melo *ppid = atoi(ppids); 131055c67edSArnaldo Carvalho de Melo } else { 132055c67edSArnaldo Carvalho de Melo pr_debug("PPid: string not found for pid %d\n", pid); 133055c67edSArnaldo Carvalho de Melo } 134055c67edSArnaldo Carvalho de Melo 135055c67edSArnaldo Carvalho de Melo return 0; 136055c67edSArnaldo Carvalho de Melo } 137055c67edSArnaldo Carvalho de Melo 138055c67edSArnaldo Carvalho de Melo static int perf_event__prepare_comm(union perf_event *event, pid_t pid, 139055c67edSArnaldo Carvalho de Melo struct machine *machine, 140055c67edSArnaldo Carvalho de Melo pid_t *tgid, pid_t *ppid) 141055c67edSArnaldo Carvalho de Melo { 142055c67edSArnaldo Carvalho de Melo size_t size; 143055c67edSArnaldo Carvalho de Melo 144055c67edSArnaldo Carvalho de Melo *ppid = -1; 145055c67edSArnaldo Carvalho de Melo 146055c67edSArnaldo Carvalho de Melo memset(&event->comm, 0, sizeof(event->comm)); 147055c67edSArnaldo Carvalho de Melo 148055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) { 149055c67edSArnaldo Carvalho de Melo if (perf_event__get_comm_ids(pid, event->comm.comm, 150055c67edSArnaldo Carvalho de Melo sizeof(event->comm.comm), 151055c67edSArnaldo Carvalho de Melo tgid, ppid) != 0) { 152055c67edSArnaldo Carvalho de Melo return -1; 153055c67edSArnaldo Carvalho de Melo } 154055c67edSArnaldo Carvalho de Melo } else { 155055c67edSArnaldo Carvalho de Melo *tgid = machine->pid; 156055c67edSArnaldo Carvalho de Melo } 157055c67edSArnaldo Carvalho de Melo 158055c67edSArnaldo Carvalho de Melo if (*tgid < 0) 159055c67edSArnaldo Carvalho de Melo return -1; 160055c67edSArnaldo Carvalho de Melo 161055c67edSArnaldo Carvalho de Melo event->comm.pid = *tgid; 162055c67edSArnaldo Carvalho de Melo event->comm.header.type = PERF_RECORD_COMM; 163055c67edSArnaldo Carvalho de Melo 164055c67edSArnaldo Carvalho de Melo size = strlen(event->comm.comm) + 1; 165055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 166055c67edSArnaldo Carvalho de Melo memset(event->comm.comm + size, 0, machine->id_hdr_size); 167055c67edSArnaldo Carvalho de Melo event->comm.header.size = (sizeof(event->comm) - 168055c67edSArnaldo Carvalho de Melo (sizeof(event->comm.comm) - size) + 169055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 170055c67edSArnaldo Carvalho de Melo event->comm.tid = pid; 171055c67edSArnaldo Carvalho de Melo 172055c67edSArnaldo Carvalho de Melo return 0; 173055c67edSArnaldo Carvalho de Melo } 174055c67edSArnaldo Carvalho de Melo 175055c67edSArnaldo Carvalho de Melo pid_t perf_event__synthesize_comm(struct perf_tool *tool, 176055c67edSArnaldo Carvalho de Melo union perf_event *event, pid_t pid, 177055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 178055c67edSArnaldo Carvalho de Melo struct machine *machine) 179055c67edSArnaldo Carvalho de Melo { 180055c67edSArnaldo Carvalho de Melo pid_t tgid, ppid; 181055c67edSArnaldo Carvalho de Melo 182055c67edSArnaldo Carvalho de Melo if (perf_event__prepare_comm(event, pid, machine, &tgid, &ppid) != 0) 183055c67edSArnaldo Carvalho de Melo return -1; 184055c67edSArnaldo Carvalho de Melo 185055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) 186055c67edSArnaldo Carvalho de Melo return -1; 187055c67edSArnaldo Carvalho de Melo 188055c67edSArnaldo Carvalho de Melo return tgid; 189055c67edSArnaldo Carvalho de Melo } 190055c67edSArnaldo Carvalho de Melo 191055c67edSArnaldo Carvalho de Melo static void perf_event__get_ns_link_info(pid_t pid, const char *ns, 192055c67edSArnaldo Carvalho de Melo struct perf_ns_link_info *ns_link_info) 193055c67edSArnaldo Carvalho de Melo { 194055c67edSArnaldo Carvalho de Melo struct stat64 st; 195055c67edSArnaldo Carvalho de Melo char proc_ns[128]; 196055c67edSArnaldo Carvalho de Melo 197055c67edSArnaldo Carvalho de Melo sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns); 198055c67edSArnaldo Carvalho de Melo if (stat64(proc_ns, &st) == 0) { 199055c67edSArnaldo Carvalho de Melo ns_link_info->dev = st.st_dev; 200055c67edSArnaldo Carvalho de Melo ns_link_info->ino = st.st_ino; 201055c67edSArnaldo Carvalho de Melo } 202055c67edSArnaldo Carvalho de Melo } 203055c67edSArnaldo Carvalho de Melo 204055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_namespaces(struct perf_tool *tool, 205055c67edSArnaldo Carvalho de Melo union perf_event *event, 206055c67edSArnaldo Carvalho de Melo pid_t pid, pid_t tgid, 207055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 208055c67edSArnaldo Carvalho de Melo struct machine *machine) 209055c67edSArnaldo Carvalho de Melo { 210055c67edSArnaldo Carvalho de Melo u32 idx; 211055c67edSArnaldo Carvalho de Melo struct perf_ns_link_info *ns_link_info; 212055c67edSArnaldo Carvalho de Melo 213055c67edSArnaldo Carvalho de Melo if (!tool || !tool->namespace_events) 214055c67edSArnaldo Carvalho de Melo return 0; 215055c67edSArnaldo Carvalho de Melo 216055c67edSArnaldo Carvalho de Melo memset(&event->namespaces, 0, (sizeof(event->namespaces) + 217055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 218055c67edSArnaldo Carvalho de Melo machine->id_hdr_size)); 219055c67edSArnaldo Carvalho de Melo 220055c67edSArnaldo Carvalho de Melo event->namespaces.pid = tgid; 221055c67edSArnaldo Carvalho de Melo event->namespaces.tid = pid; 222055c67edSArnaldo Carvalho de Melo 223055c67edSArnaldo Carvalho de Melo event->namespaces.nr_namespaces = NR_NAMESPACES; 224055c67edSArnaldo Carvalho de Melo 225055c67edSArnaldo Carvalho de Melo ns_link_info = event->namespaces.link_info; 226055c67edSArnaldo Carvalho de Melo 227055c67edSArnaldo Carvalho de Melo for (idx = 0; idx < event->namespaces.nr_namespaces; idx++) 228055c67edSArnaldo Carvalho de Melo perf_event__get_ns_link_info(pid, perf_ns__name(idx), 229055c67edSArnaldo Carvalho de Melo &ns_link_info[idx]); 230055c67edSArnaldo Carvalho de Melo 231055c67edSArnaldo Carvalho de Melo event->namespaces.header.type = PERF_RECORD_NAMESPACES; 232055c67edSArnaldo Carvalho de Melo 233055c67edSArnaldo Carvalho de Melo event->namespaces.header.size = (sizeof(event->namespaces) + 234055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 235055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 236055c67edSArnaldo Carvalho de Melo 237055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) 238055c67edSArnaldo Carvalho de Melo return -1; 239055c67edSArnaldo Carvalho de Melo 240055c67edSArnaldo Carvalho de Melo return 0; 241055c67edSArnaldo Carvalho de Melo } 242055c67edSArnaldo Carvalho de Melo 243055c67edSArnaldo Carvalho de Melo static int perf_event__synthesize_fork(struct perf_tool *tool, 244055c67edSArnaldo Carvalho de Melo union perf_event *event, 245055c67edSArnaldo Carvalho de Melo pid_t pid, pid_t tgid, pid_t ppid, 246055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 247055c67edSArnaldo Carvalho de Melo struct machine *machine) 248055c67edSArnaldo Carvalho de Melo { 249055c67edSArnaldo Carvalho de Melo memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size); 250055c67edSArnaldo Carvalho de Melo 251055c67edSArnaldo Carvalho de Melo /* 252055c67edSArnaldo Carvalho de Melo * for main thread set parent to ppid from status file. For other 253055c67edSArnaldo Carvalho de Melo * threads set parent pid to main thread. ie., assume main thread 254055c67edSArnaldo Carvalho de Melo * spawns all threads in a process 255055c67edSArnaldo Carvalho de Melo */ 256055c67edSArnaldo Carvalho de Melo if (tgid == pid) { 257055c67edSArnaldo Carvalho de Melo event->fork.ppid = ppid; 258055c67edSArnaldo Carvalho de Melo event->fork.ptid = ppid; 259055c67edSArnaldo Carvalho de Melo } else { 260055c67edSArnaldo Carvalho de Melo event->fork.ppid = tgid; 261055c67edSArnaldo Carvalho de Melo event->fork.ptid = tgid; 262055c67edSArnaldo Carvalho de Melo } 263055c67edSArnaldo Carvalho de Melo event->fork.pid = tgid; 264055c67edSArnaldo Carvalho de Melo event->fork.tid = pid; 265055c67edSArnaldo Carvalho de Melo event->fork.header.type = PERF_RECORD_FORK; 266055c67edSArnaldo Carvalho de Melo event->fork.header.misc = PERF_RECORD_MISC_FORK_EXEC; 267055c67edSArnaldo Carvalho de Melo 268055c67edSArnaldo Carvalho de Melo event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); 269055c67edSArnaldo Carvalho de Melo 270055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) 271055c67edSArnaldo Carvalho de Melo return -1; 272055c67edSArnaldo Carvalho de Melo 273055c67edSArnaldo Carvalho de Melo return 0; 274055c67edSArnaldo Carvalho de Melo } 275055c67edSArnaldo Carvalho de Melo 276055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_mmap_events(struct perf_tool *tool, 277055c67edSArnaldo Carvalho de Melo union perf_event *event, 278055c67edSArnaldo Carvalho de Melo pid_t pid, pid_t tgid, 279055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 280055c67edSArnaldo Carvalho de Melo struct machine *machine, 281055c67edSArnaldo Carvalho de Melo bool mmap_data) 282055c67edSArnaldo Carvalho de Melo { 283055c67edSArnaldo Carvalho de Melo char filename[PATH_MAX]; 284055c67edSArnaldo Carvalho de Melo FILE *fp; 285055c67edSArnaldo Carvalho de Melo unsigned long long t; 286055c67edSArnaldo Carvalho de Melo bool truncation = false; 287055c67edSArnaldo Carvalho de Melo unsigned long long timeout = proc_map_timeout * 1000000ULL; 288055c67edSArnaldo Carvalho de Melo int rc = 0; 289055c67edSArnaldo Carvalho de Melo const char *hugetlbfs_mnt = hugetlbfs__mountpoint(); 290055c67edSArnaldo Carvalho de Melo int hugetlbfs_mnt_len = hugetlbfs_mnt ? strlen(hugetlbfs_mnt) : 0; 291055c67edSArnaldo Carvalho de Melo 292055c67edSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 293055c67edSArnaldo Carvalho de Melo return 0; 294055c67edSArnaldo Carvalho de Melo 295055c67edSArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), "%s/proc/%d/task/%d/maps", 296055c67edSArnaldo Carvalho de Melo machine->root_dir, pid, pid); 297055c67edSArnaldo Carvalho de Melo 298055c67edSArnaldo Carvalho de Melo fp = fopen(filename, "r"); 299055c67edSArnaldo Carvalho de Melo if (fp == NULL) { 300055c67edSArnaldo Carvalho de Melo /* 301055c67edSArnaldo Carvalho de Melo * We raced with a task exiting - just return: 302055c67edSArnaldo Carvalho de Melo */ 303055c67edSArnaldo Carvalho de Melo pr_debug("couldn't open %s\n", filename); 304055c67edSArnaldo Carvalho de Melo return -1; 305055c67edSArnaldo Carvalho de Melo } 306055c67edSArnaldo Carvalho de Melo 307055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_MMAP2; 308055c67edSArnaldo Carvalho de Melo t = rdclock(); 309055c67edSArnaldo Carvalho de Melo 310055c67edSArnaldo Carvalho de Melo while (1) { 311055c67edSArnaldo Carvalho de Melo char bf[BUFSIZ]; 312055c67edSArnaldo Carvalho de Melo char prot[5]; 313055c67edSArnaldo Carvalho de Melo char execname[PATH_MAX]; 314055c67edSArnaldo Carvalho de Melo char anonstr[] = "//anon"; 315055c67edSArnaldo Carvalho de Melo unsigned int ino; 316055c67edSArnaldo Carvalho de Melo size_t size; 317055c67edSArnaldo Carvalho de Melo ssize_t n; 318055c67edSArnaldo Carvalho de Melo 319055c67edSArnaldo Carvalho de Melo if (fgets(bf, sizeof(bf), fp) == NULL) 320055c67edSArnaldo Carvalho de Melo break; 321055c67edSArnaldo Carvalho de Melo 322055c67edSArnaldo Carvalho de Melo if ((rdclock() - t) > timeout) { 323055c67edSArnaldo Carvalho de Melo pr_warning("Reading %s time out. " 324055c67edSArnaldo Carvalho de Melo "You may want to increase " 325055c67edSArnaldo Carvalho de Melo "the time limit by --proc-map-timeout\n", 326055c67edSArnaldo Carvalho de Melo filename); 327055c67edSArnaldo Carvalho de Melo truncation = true; 328055c67edSArnaldo Carvalho de Melo goto out; 329055c67edSArnaldo Carvalho de Melo } 330055c67edSArnaldo Carvalho de Melo 331055c67edSArnaldo Carvalho de Melo /* ensure null termination since stack will be reused. */ 332055c67edSArnaldo Carvalho de Melo strcpy(execname, ""); 333055c67edSArnaldo Carvalho de Melo 334055c67edSArnaldo Carvalho de Melo /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 335055c67edSArnaldo Carvalho de Melo n = sscanf(bf, "%"PRI_lx64"-%"PRI_lx64" %s %"PRI_lx64" %x:%x %u %[^\n]\n", 336055c67edSArnaldo Carvalho de Melo &event->mmap2.start, &event->mmap2.len, prot, 337055c67edSArnaldo Carvalho de Melo &event->mmap2.pgoff, &event->mmap2.maj, 338055c67edSArnaldo Carvalho de Melo &event->mmap2.min, 339055c67edSArnaldo Carvalho de Melo &ino, execname); 340055c67edSArnaldo Carvalho de Melo 341055c67edSArnaldo Carvalho de Melo /* 342055c67edSArnaldo Carvalho de Melo * Anon maps don't have the execname. 343055c67edSArnaldo Carvalho de Melo */ 344055c67edSArnaldo Carvalho de Melo if (n < 7) 345055c67edSArnaldo Carvalho de Melo continue; 346055c67edSArnaldo Carvalho de Melo 347055c67edSArnaldo Carvalho de Melo event->mmap2.ino = (u64)ino; 348055c67edSArnaldo Carvalho de Melo 349055c67edSArnaldo Carvalho de Melo /* 350055c67edSArnaldo Carvalho de Melo * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 351055c67edSArnaldo Carvalho de Melo */ 352055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) 353055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_USER; 354055c67edSArnaldo Carvalho de Melo else 355055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_GUEST_USER; 356055c67edSArnaldo Carvalho de Melo 357055c67edSArnaldo Carvalho de Melo /* map protection and flags bits */ 358055c67edSArnaldo Carvalho de Melo event->mmap2.prot = 0; 359055c67edSArnaldo Carvalho de Melo event->mmap2.flags = 0; 360055c67edSArnaldo Carvalho de Melo if (prot[0] == 'r') 361055c67edSArnaldo Carvalho de Melo event->mmap2.prot |= PROT_READ; 362055c67edSArnaldo Carvalho de Melo if (prot[1] == 'w') 363055c67edSArnaldo Carvalho de Melo event->mmap2.prot |= PROT_WRITE; 364055c67edSArnaldo Carvalho de Melo if (prot[2] == 'x') 365055c67edSArnaldo Carvalho de Melo event->mmap2.prot |= PROT_EXEC; 366055c67edSArnaldo Carvalho de Melo 367055c67edSArnaldo Carvalho de Melo if (prot[3] == 's') 368055c67edSArnaldo Carvalho de Melo event->mmap2.flags |= MAP_SHARED; 369055c67edSArnaldo Carvalho de Melo else 370055c67edSArnaldo Carvalho de Melo event->mmap2.flags |= MAP_PRIVATE; 371055c67edSArnaldo Carvalho de Melo 372055c67edSArnaldo Carvalho de Melo if (prot[2] != 'x') { 373055c67edSArnaldo Carvalho de Melo if (!mmap_data || prot[0] != 'r') 374055c67edSArnaldo Carvalho de Melo continue; 375055c67edSArnaldo Carvalho de Melo 376055c67edSArnaldo Carvalho de Melo event->header.misc |= PERF_RECORD_MISC_MMAP_DATA; 377055c67edSArnaldo Carvalho de Melo } 378055c67edSArnaldo Carvalho de Melo 379055c67edSArnaldo Carvalho de Melo out: 380055c67edSArnaldo Carvalho de Melo if (truncation) 381055c67edSArnaldo Carvalho de Melo event->header.misc |= PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT; 382055c67edSArnaldo Carvalho de Melo 383055c67edSArnaldo Carvalho de Melo if (!strcmp(execname, "")) 384055c67edSArnaldo Carvalho de Melo strcpy(execname, anonstr); 385055c67edSArnaldo Carvalho de Melo 386055c67edSArnaldo Carvalho de Melo if (hugetlbfs_mnt_len && 387055c67edSArnaldo Carvalho de Melo !strncmp(execname, hugetlbfs_mnt, hugetlbfs_mnt_len)) { 388055c67edSArnaldo Carvalho de Melo strcpy(execname, anonstr); 389055c67edSArnaldo Carvalho de Melo event->mmap2.flags |= MAP_HUGETLB; 390055c67edSArnaldo Carvalho de Melo } 391055c67edSArnaldo Carvalho de Melo 392055c67edSArnaldo Carvalho de Melo size = strlen(execname) + 1; 393055c67edSArnaldo Carvalho de Melo memcpy(event->mmap2.filename, execname, size); 394055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 395055c67edSArnaldo Carvalho de Melo event->mmap2.len -= event->mmap.start; 396055c67edSArnaldo Carvalho de Melo event->mmap2.header.size = (sizeof(event->mmap2) - 397055c67edSArnaldo Carvalho de Melo (sizeof(event->mmap2.filename) - size)); 398055c67edSArnaldo Carvalho de Melo memset(event->mmap2.filename + size, 0, machine->id_hdr_size); 399055c67edSArnaldo Carvalho de Melo event->mmap2.header.size += machine->id_hdr_size; 400055c67edSArnaldo Carvalho de Melo event->mmap2.pid = tgid; 401055c67edSArnaldo Carvalho de Melo event->mmap2.tid = pid; 402055c67edSArnaldo Carvalho de Melo 403055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { 404055c67edSArnaldo Carvalho de Melo rc = -1; 405055c67edSArnaldo Carvalho de Melo break; 406055c67edSArnaldo Carvalho de Melo } 407055c67edSArnaldo Carvalho de Melo 408055c67edSArnaldo Carvalho de Melo if (truncation) 409055c67edSArnaldo Carvalho de Melo break; 410055c67edSArnaldo Carvalho de Melo } 411055c67edSArnaldo Carvalho de Melo 412055c67edSArnaldo Carvalho de Melo fclose(fp); 413055c67edSArnaldo Carvalho de Melo return rc; 414055c67edSArnaldo Carvalho de Melo } 415055c67edSArnaldo Carvalho de Melo 416055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process, 417055c67edSArnaldo Carvalho de Melo struct machine *machine) 418055c67edSArnaldo Carvalho de Melo { 419055c67edSArnaldo Carvalho de Melo int rc = 0; 420055c67edSArnaldo Carvalho de Melo struct map *pos; 421055c67edSArnaldo Carvalho de Melo struct maps *maps = machine__kernel_maps(machine); 422055c67edSArnaldo Carvalho de Melo union perf_event *event = zalloc((sizeof(event->mmap) + 423055c67edSArnaldo Carvalho de Melo machine->id_hdr_size)); 424055c67edSArnaldo Carvalho de Melo if (event == NULL) { 425055c67edSArnaldo Carvalho de Melo pr_debug("Not enough memory synthesizing mmap event " 426055c67edSArnaldo Carvalho de Melo "for kernel modules\n"); 427055c67edSArnaldo Carvalho de Melo return -1; 428055c67edSArnaldo Carvalho de Melo } 429055c67edSArnaldo Carvalho de Melo 430055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_MMAP; 431055c67edSArnaldo Carvalho de Melo 432055c67edSArnaldo Carvalho de Melo /* 433055c67edSArnaldo Carvalho de Melo * kernel uses 0 for user space maps, see kernel/perf_event.c 434055c67edSArnaldo Carvalho de Melo * __perf_event_mmap 435055c67edSArnaldo Carvalho de Melo */ 436055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) 437055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_KERNEL; 438055c67edSArnaldo Carvalho de Melo else 439055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 440055c67edSArnaldo Carvalho de Melo 4418efc4f05SArnaldo Carvalho de Melo maps__for_each_entry(maps, pos) { 442055c67edSArnaldo Carvalho de Melo size_t size; 443055c67edSArnaldo Carvalho de Melo 444055c67edSArnaldo Carvalho de Melo if (!__map__is_kmodule(pos)) 445055c67edSArnaldo Carvalho de Melo continue; 446055c67edSArnaldo Carvalho de Melo 447055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); 448055c67edSArnaldo Carvalho de Melo event->mmap.header.type = PERF_RECORD_MMAP; 449055c67edSArnaldo Carvalho de Melo event->mmap.header.size = (sizeof(event->mmap) - 450055c67edSArnaldo Carvalho de Melo (sizeof(event->mmap.filename) - size)); 451055c67edSArnaldo Carvalho de Melo memset(event->mmap.filename + size, 0, machine->id_hdr_size); 452055c67edSArnaldo Carvalho de Melo event->mmap.header.size += machine->id_hdr_size; 453055c67edSArnaldo Carvalho de Melo event->mmap.start = pos->start; 454055c67edSArnaldo Carvalho de Melo event->mmap.len = pos->end - pos->start; 455055c67edSArnaldo Carvalho de Melo event->mmap.pid = machine->pid; 456055c67edSArnaldo Carvalho de Melo 457055c67edSArnaldo Carvalho de Melo memcpy(event->mmap.filename, pos->dso->long_name, 458055c67edSArnaldo Carvalho de Melo pos->dso->long_name_len + 1); 459055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { 460055c67edSArnaldo Carvalho de Melo rc = -1; 461055c67edSArnaldo Carvalho de Melo break; 462055c67edSArnaldo Carvalho de Melo } 463055c67edSArnaldo Carvalho de Melo } 464055c67edSArnaldo Carvalho de Melo 465055c67edSArnaldo Carvalho de Melo free(event); 466055c67edSArnaldo Carvalho de Melo return rc; 467055c67edSArnaldo Carvalho de Melo } 468055c67edSArnaldo Carvalho de Melo 469055c67edSArnaldo Carvalho de Melo static int __event__synthesize_thread(union perf_event *comm_event, 470055c67edSArnaldo Carvalho de Melo union perf_event *mmap_event, 471055c67edSArnaldo Carvalho de Melo union perf_event *fork_event, 472055c67edSArnaldo Carvalho de Melo union perf_event *namespaces_event, 473055c67edSArnaldo Carvalho de Melo pid_t pid, int full, perf_event__handler_t process, 474055c67edSArnaldo Carvalho de Melo struct perf_tool *tool, struct machine *machine, bool mmap_data) 475055c67edSArnaldo Carvalho de Melo { 476055c67edSArnaldo Carvalho de Melo char filename[PATH_MAX]; 477055c67edSArnaldo Carvalho de Melo DIR *tasks; 478055c67edSArnaldo Carvalho de Melo struct dirent *dirent; 479055c67edSArnaldo Carvalho de Melo pid_t tgid, ppid; 480055c67edSArnaldo Carvalho de Melo int rc = 0; 481055c67edSArnaldo Carvalho de Melo 482055c67edSArnaldo Carvalho de Melo /* special case: only send one comm event using passed in pid */ 483055c67edSArnaldo Carvalho de Melo if (!full) { 484055c67edSArnaldo Carvalho de Melo tgid = perf_event__synthesize_comm(tool, comm_event, pid, 485055c67edSArnaldo Carvalho de Melo process, machine); 486055c67edSArnaldo Carvalho de Melo 487055c67edSArnaldo Carvalho de Melo if (tgid == -1) 488055c67edSArnaldo Carvalho de Melo return -1; 489055c67edSArnaldo Carvalho de Melo 490055c67edSArnaldo Carvalho de Melo if (perf_event__synthesize_namespaces(tool, namespaces_event, pid, 491055c67edSArnaldo Carvalho de Melo tgid, process, machine) < 0) 492055c67edSArnaldo Carvalho de Melo return -1; 493055c67edSArnaldo Carvalho de Melo 494055c67edSArnaldo Carvalho de Melo /* 495055c67edSArnaldo Carvalho de Melo * send mmap only for thread group leader 496055c67edSArnaldo Carvalho de Melo * see thread__init_map_groups 497055c67edSArnaldo Carvalho de Melo */ 498055c67edSArnaldo Carvalho de Melo if (pid == tgid && 499055c67edSArnaldo Carvalho de Melo perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 500055c67edSArnaldo Carvalho de Melo process, machine, mmap_data)) 501055c67edSArnaldo Carvalho de Melo return -1; 502055c67edSArnaldo Carvalho de Melo 503055c67edSArnaldo Carvalho de Melo return 0; 504055c67edSArnaldo Carvalho de Melo } 505055c67edSArnaldo Carvalho de Melo 506055c67edSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 507055c67edSArnaldo Carvalho de Melo return 0; 508055c67edSArnaldo Carvalho de Melo 509055c67edSArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), "%s/proc/%d/task", 510055c67edSArnaldo Carvalho de Melo machine->root_dir, pid); 511055c67edSArnaldo Carvalho de Melo 512055c67edSArnaldo Carvalho de Melo tasks = opendir(filename); 513055c67edSArnaldo Carvalho de Melo if (tasks == NULL) { 514055c67edSArnaldo Carvalho de Melo pr_debug("couldn't open %s\n", filename); 515055c67edSArnaldo Carvalho de Melo return 0; 516055c67edSArnaldo Carvalho de Melo } 517055c67edSArnaldo Carvalho de Melo 518055c67edSArnaldo Carvalho de Melo while ((dirent = readdir(tasks)) != NULL) { 519055c67edSArnaldo Carvalho de Melo char *end; 520055c67edSArnaldo Carvalho de Melo pid_t _pid; 521055c67edSArnaldo Carvalho de Melo 522055c67edSArnaldo Carvalho de Melo _pid = strtol(dirent->d_name, &end, 10); 523055c67edSArnaldo Carvalho de Melo if (*end) 524055c67edSArnaldo Carvalho de Melo continue; 525055c67edSArnaldo Carvalho de Melo 526055c67edSArnaldo Carvalho de Melo rc = -1; 527055c67edSArnaldo Carvalho de Melo if (perf_event__prepare_comm(comm_event, _pid, machine, 528055c67edSArnaldo Carvalho de Melo &tgid, &ppid) != 0) 529055c67edSArnaldo Carvalho de Melo break; 530055c67edSArnaldo Carvalho de Melo 531055c67edSArnaldo Carvalho de Melo if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid, 532055c67edSArnaldo Carvalho de Melo ppid, process, machine) < 0) 533055c67edSArnaldo Carvalho de Melo break; 534055c67edSArnaldo Carvalho de Melo 535055c67edSArnaldo Carvalho de Melo if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid, 536055c67edSArnaldo Carvalho de Melo tgid, process, machine) < 0) 537055c67edSArnaldo Carvalho de Melo break; 538055c67edSArnaldo Carvalho de Melo 539055c67edSArnaldo Carvalho de Melo /* 540055c67edSArnaldo Carvalho de Melo * Send the prepared comm event 541055c67edSArnaldo Carvalho de Melo */ 542055c67edSArnaldo Carvalho de Melo if (perf_tool__process_synth_event(tool, comm_event, machine, process) != 0) 543055c67edSArnaldo Carvalho de Melo break; 544055c67edSArnaldo Carvalho de Melo 545055c67edSArnaldo Carvalho de Melo rc = 0; 546055c67edSArnaldo Carvalho de Melo if (_pid == pid) { 547055c67edSArnaldo Carvalho de Melo /* process the parent's maps too */ 548055c67edSArnaldo Carvalho de Melo rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 549055c67edSArnaldo Carvalho de Melo process, machine, mmap_data); 550055c67edSArnaldo Carvalho de Melo if (rc) 551055c67edSArnaldo Carvalho de Melo break; 552055c67edSArnaldo Carvalho de Melo } 553055c67edSArnaldo Carvalho de Melo } 554055c67edSArnaldo Carvalho de Melo 555055c67edSArnaldo Carvalho de Melo closedir(tasks); 556055c67edSArnaldo Carvalho de Melo return rc; 557055c67edSArnaldo Carvalho de Melo } 558055c67edSArnaldo Carvalho de Melo 559055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_thread_map(struct perf_tool *tool, 560055c67edSArnaldo Carvalho de Melo struct perf_thread_map *threads, 561055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 562055c67edSArnaldo Carvalho de Melo struct machine *machine, 563055c67edSArnaldo Carvalho de Melo bool mmap_data) 564055c67edSArnaldo Carvalho de Melo { 565055c67edSArnaldo Carvalho de Melo union perf_event *comm_event, *mmap_event, *fork_event; 566055c67edSArnaldo Carvalho de Melo union perf_event *namespaces_event; 567055c67edSArnaldo Carvalho de Melo int err = -1, thread, j; 568055c67edSArnaldo Carvalho de Melo 569055c67edSArnaldo Carvalho de Melo comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 570055c67edSArnaldo Carvalho de Melo if (comm_event == NULL) 571055c67edSArnaldo Carvalho de Melo goto out; 572055c67edSArnaldo Carvalho de Melo 573055c67edSArnaldo Carvalho de Melo mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); 574055c67edSArnaldo Carvalho de Melo if (mmap_event == NULL) 575055c67edSArnaldo Carvalho de Melo goto out_free_comm; 576055c67edSArnaldo Carvalho de Melo 577055c67edSArnaldo Carvalho de Melo fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); 578055c67edSArnaldo Carvalho de Melo if (fork_event == NULL) 579055c67edSArnaldo Carvalho de Melo goto out_free_mmap; 580055c67edSArnaldo Carvalho de Melo 581055c67edSArnaldo Carvalho de Melo namespaces_event = malloc(sizeof(namespaces_event->namespaces) + 582055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 583055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 584055c67edSArnaldo Carvalho de Melo if (namespaces_event == NULL) 585055c67edSArnaldo Carvalho de Melo goto out_free_fork; 586055c67edSArnaldo Carvalho de Melo 587055c67edSArnaldo Carvalho de Melo err = 0; 588055c67edSArnaldo Carvalho de Melo for (thread = 0; thread < threads->nr; ++thread) { 589055c67edSArnaldo Carvalho de Melo if (__event__synthesize_thread(comm_event, mmap_event, 590055c67edSArnaldo Carvalho de Melo fork_event, namespaces_event, 591055c67edSArnaldo Carvalho de Melo perf_thread_map__pid(threads, thread), 0, 592055c67edSArnaldo Carvalho de Melo process, tool, machine, 593055c67edSArnaldo Carvalho de Melo mmap_data)) { 594055c67edSArnaldo Carvalho de Melo err = -1; 595055c67edSArnaldo Carvalho de Melo break; 596055c67edSArnaldo Carvalho de Melo } 597055c67edSArnaldo Carvalho de Melo 598055c67edSArnaldo Carvalho de Melo /* 599055c67edSArnaldo Carvalho de Melo * comm.pid is set to thread group id by 600055c67edSArnaldo Carvalho de Melo * perf_event__synthesize_comm 601055c67edSArnaldo Carvalho de Melo */ 602055c67edSArnaldo Carvalho de Melo if ((int) comm_event->comm.pid != perf_thread_map__pid(threads, thread)) { 603055c67edSArnaldo Carvalho de Melo bool need_leader = true; 604055c67edSArnaldo Carvalho de Melo 605055c67edSArnaldo Carvalho de Melo /* is thread group leader in thread_map? */ 606055c67edSArnaldo Carvalho de Melo for (j = 0; j < threads->nr; ++j) { 607055c67edSArnaldo Carvalho de Melo if ((int) comm_event->comm.pid == perf_thread_map__pid(threads, j)) { 608055c67edSArnaldo Carvalho de Melo need_leader = false; 609055c67edSArnaldo Carvalho de Melo break; 610055c67edSArnaldo Carvalho de Melo } 611055c67edSArnaldo Carvalho de Melo } 612055c67edSArnaldo Carvalho de Melo 613055c67edSArnaldo Carvalho de Melo /* if not, generate events for it */ 614055c67edSArnaldo Carvalho de Melo if (need_leader && 615055c67edSArnaldo Carvalho de Melo __event__synthesize_thread(comm_event, mmap_event, 616055c67edSArnaldo Carvalho de Melo fork_event, namespaces_event, 617055c67edSArnaldo Carvalho de Melo comm_event->comm.pid, 0, 618055c67edSArnaldo Carvalho de Melo process, tool, machine, 619055c67edSArnaldo Carvalho de Melo mmap_data)) { 620055c67edSArnaldo Carvalho de Melo err = -1; 621055c67edSArnaldo Carvalho de Melo break; 622055c67edSArnaldo Carvalho de Melo } 623055c67edSArnaldo Carvalho de Melo } 624055c67edSArnaldo Carvalho de Melo } 625055c67edSArnaldo Carvalho de Melo free(namespaces_event); 626055c67edSArnaldo Carvalho de Melo out_free_fork: 627055c67edSArnaldo Carvalho de Melo free(fork_event); 628055c67edSArnaldo Carvalho de Melo out_free_mmap: 629055c67edSArnaldo Carvalho de Melo free(mmap_event); 630055c67edSArnaldo Carvalho de Melo out_free_comm: 631055c67edSArnaldo Carvalho de Melo free(comm_event); 632055c67edSArnaldo Carvalho de Melo out: 633055c67edSArnaldo Carvalho de Melo return err; 634055c67edSArnaldo Carvalho de Melo } 635055c67edSArnaldo Carvalho de Melo 636055c67edSArnaldo Carvalho de Melo static int __perf_event__synthesize_threads(struct perf_tool *tool, 637055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 638055c67edSArnaldo Carvalho de Melo struct machine *machine, 639055c67edSArnaldo Carvalho de Melo bool mmap_data, 640055c67edSArnaldo Carvalho de Melo struct dirent **dirent, 641055c67edSArnaldo Carvalho de Melo int start, 642055c67edSArnaldo Carvalho de Melo int num) 643055c67edSArnaldo Carvalho de Melo { 644055c67edSArnaldo Carvalho de Melo union perf_event *comm_event, *mmap_event, *fork_event; 645055c67edSArnaldo Carvalho de Melo union perf_event *namespaces_event; 646055c67edSArnaldo Carvalho de Melo int err = -1; 647055c67edSArnaldo Carvalho de Melo char *end; 648055c67edSArnaldo Carvalho de Melo pid_t pid; 649055c67edSArnaldo Carvalho de Melo int i; 650055c67edSArnaldo Carvalho de Melo 651055c67edSArnaldo Carvalho de Melo comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 652055c67edSArnaldo Carvalho de Melo if (comm_event == NULL) 653055c67edSArnaldo Carvalho de Melo goto out; 654055c67edSArnaldo Carvalho de Melo 655055c67edSArnaldo Carvalho de Melo mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); 656055c67edSArnaldo Carvalho de Melo if (mmap_event == NULL) 657055c67edSArnaldo Carvalho de Melo goto out_free_comm; 658055c67edSArnaldo Carvalho de Melo 659055c67edSArnaldo Carvalho de Melo fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); 660055c67edSArnaldo Carvalho de Melo if (fork_event == NULL) 661055c67edSArnaldo Carvalho de Melo goto out_free_mmap; 662055c67edSArnaldo Carvalho de Melo 663055c67edSArnaldo Carvalho de Melo namespaces_event = malloc(sizeof(namespaces_event->namespaces) + 664055c67edSArnaldo Carvalho de Melo (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + 665055c67edSArnaldo Carvalho de Melo machine->id_hdr_size); 666055c67edSArnaldo Carvalho de Melo if (namespaces_event == NULL) 667055c67edSArnaldo Carvalho de Melo goto out_free_fork; 668055c67edSArnaldo Carvalho de Melo 669055c67edSArnaldo Carvalho de Melo for (i = start; i < start + num; i++) { 670055c67edSArnaldo Carvalho de Melo if (!isdigit(dirent[i]->d_name[0])) 671055c67edSArnaldo Carvalho de Melo continue; 672055c67edSArnaldo Carvalho de Melo 673055c67edSArnaldo Carvalho de Melo pid = (pid_t)strtol(dirent[i]->d_name, &end, 10); 674055c67edSArnaldo Carvalho de Melo /* only interested in proper numerical dirents */ 675055c67edSArnaldo Carvalho de Melo if (*end) 676055c67edSArnaldo Carvalho de Melo continue; 677055c67edSArnaldo Carvalho de Melo /* 678055c67edSArnaldo Carvalho de Melo * We may race with exiting thread, so don't stop just because 679055c67edSArnaldo Carvalho de Melo * one thread couldn't be synthesized. 680055c67edSArnaldo Carvalho de Melo */ 681055c67edSArnaldo Carvalho de Melo __event__synthesize_thread(comm_event, mmap_event, fork_event, 682055c67edSArnaldo Carvalho de Melo namespaces_event, pid, 1, process, 683055c67edSArnaldo Carvalho de Melo tool, machine, mmap_data); 684055c67edSArnaldo Carvalho de Melo } 685055c67edSArnaldo Carvalho de Melo err = 0; 686055c67edSArnaldo Carvalho de Melo 687055c67edSArnaldo Carvalho de Melo free(namespaces_event); 688055c67edSArnaldo Carvalho de Melo out_free_fork: 689055c67edSArnaldo Carvalho de Melo free(fork_event); 690055c67edSArnaldo Carvalho de Melo out_free_mmap: 691055c67edSArnaldo Carvalho de Melo free(mmap_event); 692055c67edSArnaldo Carvalho de Melo out_free_comm: 693055c67edSArnaldo Carvalho de Melo free(comm_event); 694055c67edSArnaldo Carvalho de Melo out: 695055c67edSArnaldo Carvalho de Melo return err; 696055c67edSArnaldo Carvalho de Melo } 697055c67edSArnaldo Carvalho de Melo 698055c67edSArnaldo Carvalho de Melo struct synthesize_threads_arg { 699055c67edSArnaldo Carvalho de Melo struct perf_tool *tool; 700055c67edSArnaldo Carvalho de Melo perf_event__handler_t process; 701055c67edSArnaldo Carvalho de Melo struct machine *machine; 702055c67edSArnaldo Carvalho de Melo bool mmap_data; 703055c67edSArnaldo Carvalho de Melo struct dirent **dirent; 704055c67edSArnaldo Carvalho de Melo int num; 705055c67edSArnaldo Carvalho de Melo int start; 706055c67edSArnaldo Carvalho de Melo }; 707055c67edSArnaldo Carvalho de Melo 708055c67edSArnaldo Carvalho de Melo static void *synthesize_threads_worker(void *arg) 709055c67edSArnaldo Carvalho de Melo { 710055c67edSArnaldo Carvalho de Melo struct synthesize_threads_arg *args = arg; 711055c67edSArnaldo Carvalho de Melo 712055c67edSArnaldo Carvalho de Melo __perf_event__synthesize_threads(args->tool, args->process, 713055c67edSArnaldo Carvalho de Melo args->machine, args->mmap_data, 714055c67edSArnaldo Carvalho de Melo args->dirent, 715055c67edSArnaldo Carvalho de Melo args->start, args->num); 716055c67edSArnaldo Carvalho de Melo return NULL; 717055c67edSArnaldo Carvalho de Melo } 718055c67edSArnaldo Carvalho de Melo 719055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_threads(struct perf_tool *tool, 720055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 721055c67edSArnaldo Carvalho de Melo struct machine *machine, 722055c67edSArnaldo Carvalho de Melo bool mmap_data, 723055c67edSArnaldo Carvalho de Melo unsigned int nr_threads_synthesize) 724055c67edSArnaldo Carvalho de Melo { 725055c67edSArnaldo Carvalho de Melo struct synthesize_threads_arg *args = NULL; 726055c67edSArnaldo Carvalho de Melo pthread_t *synthesize_threads = NULL; 727055c67edSArnaldo Carvalho de Melo char proc_path[PATH_MAX]; 728055c67edSArnaldo Carvalho de Melo struct dirent **dirent; 729055c67edSArnaldo Carvalho de Melo int num_per_thread; 730055c67edSArnaldo Carvalho de Melo int m, n, i, j; 731055c67edSArnaldo Carvalho de Melo int thread_nr; 732055c67edSArnaldo Carvalho de Melo int base = 0; 733055c67edSArnaldo Carvalho de Melo int err = -1; 734055c67edSArnaldo Carvalho de Melo 735055c67edSArnaldo Carvalho de Melo 736055c67edSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 737055c67edSArnaldo Carvalho de Melo return 0; 738055c67edSArnaldo Carvalho de Melo 739055c67edSArnaldo Carvalho de Melo snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); 740055c67edSArnaldo Carvalho de Melo n = scandir(proc_path, &dirent, 0, alphasort); 741055c67edSArnaldo Carvalho de Melo if (n < 0) 742055c67edSArnaldo Carvalho de Melo return err; 743055c67edSArnaldo Carvalho de Melo 744055c67edSArnaldo Carvalho de Melo if (nr_threads_synthesize == UINT_MAX) 745055c67edSArnaldo Carvalho de Melo thread_nr = sysconf(_SC_NPROCESSORS_ONLN); 746055c67edSArnaldo Carvalho de Melo else 747055c67edSArnaldo Carvalho de Melo thread_nr = nr_threads_synthesize; 748055c67edSArnaldo Carvalho de Melo 749055c67edSArnaldo Carvalho de Melo if (thread_nr <= 1) { 750055c67edSArnaldo Carvalho de Melo err = __perf_event__synthesize_threads(tool, process, 751055c67edSArnaldo Carvalho de Melo machine, mmap_data, 752055c67edSArnaldo Carvalho de Melo dirent, base, n); 753055c67edSArnaldo Carvalho de Melo goto free_dirent; 754055c67edSArnaldo Carvalho de Melo } 755055c67edSArnaldo Carvalho de Melo if (thread_nr > n) 756055c67edSArnaldo Carvalho de Melo thread_nr = n; 757055c67edSArnaldo Carvalho de Melo 758055c67edSArnaldo Carvalho de Melo synthesize_threads = calloc(sizeof(pthread_t), thread_nr); 759055c67edSArnaldo Carvalho de Melo if (synthesize_threads == NULL) 760055c67edSArnaldo Carvalho de Melo goto free_dirent; 761055c67edSArnaldo Carvalho de Melo 762055c67edSArnaldo Carvalho de Melo args = calloc(sizeof(*args), thread_nr); 763055c67edSArnaldo Carvalho de Melo if (args == NULL) 764055c67edSArnaldo Carvalho de Melo goto free_threads; 765055c67edSArnaldo Carvalho de Melo 766055c67edSArnaldo Carvalho de Melo num_per_thread = n / thread_nr; 767055c67edSArnaldo Carvalho de Melo m = n % thread_nr; 768055c67edSArnaldo Carvalho de Melo for (i = 0; i < thread_nr; i++) { 769055c67edSArnaldo Carvalho de Melo args[i].tool = tool; 770055c67edSArnaldo Carvalho de Melo args[i].process = process; 771055c67edSArnaldo Carvalho de Melo args[i].machine = machine; 772055c67edSArnaldo Carvalho de Melo args[i].mmap_data = mmap_data; 773055c67edSArnaldo Carvalho de Melo args[i].dirent = dirent; 774055c67edSArnaldo Carvalho de Melo } 775055c67edSArnaldo Carvalho de Melo for (i = 0; i < m; i++) { 776055c67edSArnaldo Carvalho de Melo args[i].num = num_per_thread + 1; 777055c67edSArnaldo Carvalho de Melo args[i].start = i * args[i].num; 778055c67edSArnaldo Carvalho de Melo } 779055c67edSArnaldo Carvalho de Melo if (i != 0) 780055c67edSArnaldo Carvalho de Melo base = args[i-1].start + args[i-1].num; 781055c67edSArnaldo Carvalho de Melo for (j = i; j < thread_nr; j++) { 782055c67edSArnaldo Carvalho de Melo args[j].num = num_per_thread; 783055c67edSArnaldo Carvalho de Melo args[j].start = base + (j - i) * args[i].num; 784055c67edSArnaldo Carvalho de Melo } 785055c67edSArnaldo Carvalho de Melo 786055c67edSArnaldo Carvalho de Melo for (i = 0; i < thread_nr; i++) { 787055c67edSArnaldo Carvalho de Melo if (pthread_create(&synthesize_threads[i], NULL, 788055c67edSArnaldo Carvalho de Melo synthesize_threads_worker, &args[i])) 789055c67edSArnaldo Carvalho de Melo goto out_join; 790055c67edSArnaldo Carvalho de Melo } 791055c67edSArnaldo Carvalho de Melo err = 0; 792055c67edSArnaldo Carvalho de Melo out_join: 793055c67edSArnaldo Carvalho de Melo for (i = 0; i < thread_nr; i++) 794055c67edSArnaldo Carvalho de Melo pthread_join(synthesize_threads[i], NULL); 795055c67edSArnaldo Carvalho de Melo free(args); 796055c67edSArnaldo Carvalho de Melo free_threads: 797055c67edSArnaldo Carvalho de Melo free(synthesize_threads); 798055c67edSArnaldo Carvalho de Melo free_dirent: 799055c67edSArnaldo Carvalho de Melo for (i = 0; i < n; i++) 800055c67edSArnaldo Carvalho de Melo zfree(&dirent[i]); 801055c67edSArnaldo Carvalho de Melo free(dirent); 802055c67edSArnaldo Carvalho de Melo 803055c67edSArnaldo Carvalho de Melo return err; 804055c67edSArnaldo Carvalho de Melo } 805055c67edSArnaldo Carvalho de Melo 806055c67edSArnaldo Carvalho de Melo int __weak perf_event__synthesize_extra_kmaps(struct perf_tool *tool __maybe_unused, 807055c67edSArnaldo Carvalho de Melo perf_event__handler_t process __maybe_unused, 808055c67edSArnaldo Carvalho de Melo struct machine *machine __maybe_unused) 809055c67edSArnaldo Carvalho de Melo { 810055c67edSArnaldo Carvalho de Melo return 0; 811055c67edSArnaldo Carvalho de Melo } 812055c67edSArnaldo Carvalho de Melo 813055c67edSArnaldo Carvalho de Melo static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 814055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 815055c67edSArnaldo Carvalho de Melo struct machine *machine) 816055c67edSArnaldo Carvalho de Melo { 817055c67edSArnaldo Carvalho de Melo size_t size; 818055c67edSArnaldo Carvalho de Melo struct map *map = machine__kernel_map(machine); 819055c67edSArnaldo Carvalho de Melo struct kmap *kmap; 820055c67edSArnaldo Carvalho de Melo int err; 821055c67edSArnaldo Carvalho de Melo union perf_event *event; 822055c67edSArnaldo Carvalho de Melo 823055c67edSArnaldo Carvalho de Melo if (map == NULL) 824055c67edSArnaldo Carvalho de Melo return -1; 825055c67edSArnaldo Carvalho de Melo 826055c67edSArnaldo Carvalho de Melo kmap = map__kmap(map); 827055c67edSArnaldo Carvalho de Melo if (!kmap->ref_reloc_sym) 828055c67edSArnaldo Carvalho de Melo return -1; 829055c67edSArnaldo Carvalho de Melo 830055c67edSArnaldo Carvalho de Melo /* 831055c67edSArnaldo Carvalho de Melo * We should get this from /sys/kernel/sections/.text, but till that is 832055c67edSArnaldo Carvalho de Melo * available use this, and after it is use this as a fallback for older 833055c67edSArnaldo Carvalho de Melo * kernels. 834055c67edSArnaldo Carvalho de Melo */ 835055c67edSArnaldo Carvalho de Melo event = zalloc((sizeof(event->mmap) + machine->id_hdr_size)); 836055c67edSArnaldo Carvalho de Melo if (event == NULL) { 837055c67edSArnaldo Carvalho de Melo pr_debug("Not enough memory synthesizing mmap event " 838055c67edSArnaldo Carvalho de Melo "for kernel modules\n"); 839055c67edSArnaldo Carvalho de Melo return -1; 840055c67edSArnaldo Carvalho de Melo } 841055c67edSArnaldo Carvalho de Melo 842055c67edSArnaldo Carvalho de Melo if (machine__is_host(machine)) { 843055c67edSArnaldo Carvalho de Melo /* 844055c67edSArnaldo Carvalho de Melo * kernel uses PERF_RECORD_MISC_USER for user space maps, 845055c67edSArnaldo Carvalho de Melo * see kernel/perf_event.c __perf_event_mmap 846055c67edSArnaldo Carvalho de Melo */ 847055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_KERNEL; 848055c67edSArnaldo Carvalho de Melo } else { 849055c67edSArnaldo Carvalho de Melo event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 850055c67edSArnaldo Carvalho de Melo } 851055c67edSArnaldo Carvalho de Melo 852055c67edSArnaldo Carvalho de Melo size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 853055c67edSArnaldo Carvalho de Melo "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1; 854055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 855055c67edSArnaldo Carvalho de Melo event->mmap.header.type = PERF_RECORD_MMAP; 856055c67edSArnaldo Carvalho de Melo event->mmap.header.size = (sizeof(event->mmap) - 857055c67edSArnaldo Carvalho de Melo (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); 858055c67edSArnaldo Carvalho de Melo event->mmap.pgoff = kmap->ref_reloc_sym->addr; 859055c67edSArnaldo Carvalho de Melo event->mmap.start = map->start; 860055c67edSArnaldo Carvalho de Melo event->mmap.len = map->end - event->mmap.start; 861055c67edSArnaldo Carvalho de Melo event->mmap.pid = machine->pid; 862055c67edSArnaldo Carvalho de Melo 863055c67edSArnaldo Carvalho de Melo err = perf_tool__process_synth_event(tool, event, machine, process); 864055c67edSArnaldo Carvalho de Melo free(event); 865055c67edSArnaldo Carvalho de Melo 866055c67edSArnaldo Carvalho de Melo return err; 867055c67edSArnaldo Carvalho de Melo } 868055c67edSArnaldo Carvalho de Melo 869055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 870055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 871055c67edSArnaldo Carvalho de Melo struct machine *machine) 872055c67edSArnaldo Carvalho de Melo { 873055c67edSArnaldo Carvalho de Melo int err; 874055c67edSArnaldo Carvalho de Melo 875055c67edSArnaldo Carvalho de Melo err = __perf_event__synthesize_kernel_mmap(tool, process, machine); 876055c67edSArnaldo Carvalho de Melo if (err < 0) 877055c67edSArnaldo Carvalho de Melo return err; 878055c67edSArnaldo Carvalho de Melo 879055c67edSArnaldo Carvalho de Melo return perf_event__synthesize_extra_kmaps(tool, process, machine); 880055c67edSArnaldo Carvalho de Melo } 881055c67edSArnaldo Carvalho de Melo 882055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_thread_map2(struct perf_tool *tool, 883055c67edSArnaldo Carvalho de Melo struct perf_thread_map *threads, 884055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 885055c67edSArnaldo Carvalho de Melo struct machine *machine) 886055c67edSArnaldo Carvalho de Melo { 887055c67edSArnaldo Carvalho de Melo union perf_event *event; 888055c67edSArnaldo Carvalho de Melo int i, err, size; 889055c67edSArnaldo Carvalho de Melo 890055c67edSArnaldo Carvalho de Melo size = sizeof(event->thread_map); 891055c67edSArnaldo Carvalho de Melo size += threads->nr * sizeof(event->thread_map.entries[0]); 892055c67edSArnaldo Carvalho de Melo 893055c67edSArnaldo Carvalho de Melo event = zalloc(size); 894055c67edSArnaldo Carvalho de Melo if (!event) 895055c67edSArnaldo Carvalho de Melo return -ENOMEM; 896055c67edSArnaldo Carvalho de Melo 897055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_THREAD_MAP; 898055c67edSArnaldo Carvalho de Melo event->header.size = size; 899055c67edSArnaldo Carvalho de Melo event->thread_map.nr = threads->nr; 900055c67edSArnaldo Carvalho de Melo 901055c67edSArnaldo Carvalho de Melo for (i = 0; i < threads->nr; i++) { 902055c67edSArnaldo Carvalho de Melo struct perf_record_thread_map_entry *entry = &event->thread_map.entries[i]; 903055c67edSArnaldo Carvalho de Melo char *comm = perf_thread_map__comm(threads, i); 904055c67edSArnaldo Carvalho de Melo 905055c67edSArnaldo Carvalho de Melo if (!comm) 906055c67edSArnaldo Carvalho de Melo comm = (char *) ""; 907055c67edSArnaldo Carvalho de Melo 908055c67edSArnaldo Carvalho de Melo entry->pid = perf_thread_map__pid(threads, i); 909055c67edSArnaldo Carvalho de Melo strncpy((char *) &entry->comm, comm, sizeof(entry->comm)); 910055c67edSArnaldo Carvalho de Melo } 911055c67edSArnaldo Carvalho de Melo 912055c67edSArnaldo Carvalho de Melo err = process(tool, event, NULL, machine); 913055c67edSArnaldo Carvalho de Melo 914055c67edSArnaldo Carvalho de Melo free(event); 915055c67edSArnaldo Carvalho de Melo return err; 916055c67edSArnaldo Carvalho de Melo } 917055c67edSArnaldo Carvalho de Melo 918055c67edSArnaldo Carvalho de Melo static void synthesize_cpus(struct cpu_map_entries *cpus, 919055c67edSArnaldo Carvalho de Melo struct perf_cpu_map *map) 920055c67edSArnaldo Carvalho de Melo { 921055c67edSArnaldo Carvalho de Melo int i; 922055c67edSArnaldo Carvalho de Melo 923055c67edSArnaldo Carvalho de Melo cpus->nr = map->nr; 924055c67edSArnaldo Carvalho de Melo 925055c67edSArnaldo Carvalho de Melo for (i = 0; i < map->nr; i++) 926055c67edSArnaldo Carvalho de Melo cpus->cpu[i] = map->map[i]; 927055c67edSArnaldo Carvalho de Melo } 928055c67edSArnaldo Carvalho de Melo 929055c67edSArnaldo Carvalho de Melo static void synthesize_mask(struct perf_record_record_cpu_map *mask, 930055c67edSArnaldo Carvalho de Melo struct perf_cpu_map *map, int max) 931055c67edSArnaldo Carvalho de Melo { 932055c67edSArnaldo Carvalho de Melo int i; 933055c67edSArnaldo Carvalho de Melo 934055c67edSArnaldo Carvalho de Melo mask->nr = BITS_TO_LONGS(max); 935055c67edSArnaldo Carvalho de Melo mask->long_size = sizeof(long); 936055c67edSArnaldo Carvalho de Melo 937055c67edSArnaldo Carvalho de Melo for (i = 0; i < map->nr; i++) 938055c67edSArnaldo Carvalho de Melo set_bit(map->map[i], mask->mask); 939055c67edSArnaldo Carvalho de Melo } 940055c67edSArnaldo Carvalho de Melo 941055c67edSArnaldo Carvalho de Melo static size_t cpus_size(struct perf_cpu_map *map) 942055c67edSArnaldo Carvalho de Melo { 943055c67edSArnaldo Carvalho de Melo return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16); 944055c67edSArnaldo Carvalho de Melo } 945055c67edSArnaldo Carvalho de Melo 946055c67edSArnaldo Carvalho de Melo static size_t mask_size(struct perf_cpu_map *map, int *max) 947055c67edSArnaldo Carvalho de Melo { 948055c67edSArnaldo Carvalho de Melo int i; 949055c67edSArnaldo Carvalho de Melo 950055c67edSArnaldo Carvalho de Melo *max = 0; 951055c67edSArnaldo Carvalho de Melo 952055c67edSArnaldo Carvalho de Melo for (i = 0; i < map->nr; i++) { 953055c67edSArnaldo Carvalho de Melo /* bit possition of the cpu is + 1 */ 954055c67edSArnaldo Carvalho de Melo int bit = map->map[i] + 1; 955055c67edSArnaldo Carvalho de Melo 956055c67edSArnaldo Carvalho de Melo if (bit > *max) 957055c67edSArnaldo Carvalho de Melo *max = bit; 958055c67edSArnaldo Carvalho de Melo } 959055c67edSArnaldo Carvalho de Melo 960055c67edSArnaldo Carvalho de Melo return sizeof(struct perf_record_record_cpu_map) + BITS_TO_LONGS(*max) * sizeof(long); 961055c67edSArnaldo Carvalho de Melo } 962055c67edSArnaldo Carvalho de Melo 963055c67edSArnaldo Carvalho de Melo void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max) 964055c67edSArnaldo Carvalho de Melo { 965055c67edSArnaldo Carvalho de Melo size_t size_cpus, size_mask; 966055c67edSArnaldo Carvalho de Melo bool is_dummy = perf_cpu_map__empty(map); 967055c67edSArnaldo Carvalho de Melo 968055c67edSArnaldo Carvalho de Melo /* 969055c67edSArnaldo Carvalho de Melo * Both array and mask data have variable size based 970055c67edSArnaldo Carvalho de Melo * on the number of cpus and their actual values. 971055c67edSArnaldo Carvalho de Melo * The size of the 'struct perf_record_cpu_map_data' is: 972055c67edSArnaldo Carvalho de Melo * 973055c67edSArnaldo Carvalho de Melo * array = size of 'struct cpu_map_entries' + 974055c67edSArnaldo Carvalho de Melo * number of cpus * sizeof(u64) 975055c67edSArnaldo Carvalho de Melo * 976055c67edSArnaldo Carvalho de Melo * mask = size of 'struct perf_record_record_cpu_map' + 977055c67edSArnaldo Carvalho de Melo * maximum cpu bit converted to size of longs 978055c67edSArnaldo Carvalho de Melo * 979055c67edSArnaldo Carvalho de Melo * and finaly + the size of 'struct perf_record_cpu_map_data'. 980055c67edSArnaldo Carvalho de Melo */ 981055c67edSArnaldo Carvalho de Melo size_cpus = cpus_size(map); 982055c67edSArnaldo Carvalho de Melo size_mask = mask_size(map, max); 983055c67edSArnaldo Carvalho de Melo 984055c67edSArnaldo Carvalho de Melo if (is_dummy || (size_cpus < size_mask)) { 985055c67edSArnaldo Carvalho de Melo *size += size_cpus; 986055c67edSArnaldo Carvalho de Melo *type = PERF_CPU_MAP__CPUS; 987055c67edSArnaldo Carvalho de Melo } else { 988055c67edSArnaldo Carvalho de Melo *size += size_mask; 989055c67edSArnaldo Carvalho de Melo *type = PERF_CPU_MAP__MASK; 990055c67edSArnaldo Carvalho de Melo } 991055c67edSArnaldo Carvalho de Melo 992055c67edSArnaldo Carvalho de Melo *size += sizeof(struct perf_record_cpu_map_data); 993055c67edSArnaldo Carvalho de Melo *size = PERF_ALIGN(*size, sizeof(u64)); 994055c67edSArnaldo Carvalho de Melo return zalloc(*size); 995055c67edSArnaldo Carvalho de Melo } 996055c67edSArnaldo Carvalho de Melo 997055c67edSArnaldo Carvalho de Melo void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map, 998055c67edSArnaldo Carvalho de Melo u16 type, int max) 999055c67edSArnaldo Carvalho de Melo { 1000055c67edSArnaldo Carvalho de Melo data->type = type; 1001055c67edSArnaldo Carvalho de Melo 1002055c67edSArnaldo Carvalho de Melo switch (type) { 1003055c67edSArnaldo Carvalho de Melo case PERF_CPU_MAP__CPUS: 1004055c67edSArnaldo Carvalho de Melo synthesize_cpus((struct cpu_map_entries *) data->data, map); 1005055c67edSArnaldo Carvalho de Melo break; 1006055c67edSArnaldo Carvalho de Melo case PERF_CPU_MAP__MASK: 1007055c67edSArnaldo Carvalho de Melo synthesize_mask((struct perf_record_record_cpu_map *)data->data, map, max); 1008055c67edSArnaldo Carvalho de Melo default: 1009055c67edSArnaldo Carvalho de Melo break; 1010055c67edSArnaldo Carvalho de Melo }; 1011055c67edSArnaldo Carvalho de Melo } 1012055c67edSArnaldo Carvalho de Melo 1013055c67edSArnaldo Carvalho de Melo static struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map) 1014055c67edSArnaldo Carvalho de Melo { 1015055c67edSArnaldo Carvalho de Melo size_t size = sizeof(struct perf_record_cpu_map); 1016055c67edSArnaldo Carvalho de Melo struct perf_record_cpu_map *event; 1017055c67edSArnaldo Carvalho de Melo int max; 1018055c67edSArnaldo Carvalho de Melo u16 type; 1019055c67edSArnaldo Carvalho de Melo 1020055c67edSArnaldo Carvalho de Melo event = cpu_map_data__alloc(map, &size, &type, &max); 1021055c67edSArnaldo Carvalho de Melo if (!event) 1022055c67edSArnaldo Carvalho de Melo return NULL; 1023055c67edSArnaldo Carvalho de Melo 1024055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_CPU_MAP; 1025055c67edSArnaldo Carvalho de Melo event->header.size = size; 1026055c67edSArnaldo Carvalho de Melo event->data.type = type; 1027055c67edSArnaldo Carvalho de Melo 1028055c67edSArnaldo Carvalho de Melo cpu_map_data__synthesize(&event->data, map, type, max); 1029055c67edSArnaldo Carvalho de Melo return event; 1030055c67edSArnaldo Carvalho de Melo } 1031055c67edSArnaldo Carvalho de Melo 1032055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_cpu_map(struct perf_tool *tool, 1033055c67edSArnaldo Carvalho de Melo struct perf_cpu_map *map, 1034055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1035055c67edSArnaldo Carvalho de Melo struct machine *machine) 1036055c67edSArnaldo Carvalho de Melo { 1037055c67edSArnaldo Carvalho de Melo struct perf_record_cpu_map *event; 1038055c67edSArnaldo Carvalho de Melo int err; 1039055c67edSArnaldo Carvalho de Melo 1040055c67edSArnaldo Carvalho de Melo event = cpu_map_event__new(map); 1041055c67edSArnaldo Carvalho de Melo if (!event) 1042055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1043055c67edSArnaldo Carvalho de Melo 1044055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *) event, NULL, machine); 1045055c67edSArnaldo Carvalho de Melo 1046055c67edSArnaldo Carvalho de Melo free(event); 1047055c67edSArnaldo Carvalho de Melo return err; 1048055c67edSArnaldo Carvalho de Melo } 1049055c67edSArnaldo Carvalho de Melo 1050055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_config(struct perf_tool *tool, 1051055c67edSArnaldo Carvalho de Melo struct perf_stat_config *config, 1052055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1053055c67edSArnaldo Carvalho de Melo struct machine *machine) 1054055c67edSArnaldo Carvalho de Melo { 1055055c67edSArnaldo Carvalho de Melo struct perf_record_stat_config *event; 1056055c67edSArnaldo Carvalho de Melo int size, i = 0, err; 1057055c67edSArnaldo Carvalho de Melo 1058055c67edSArnaldo Carvalho de Melo size = sizeof(*event); 1059055c67edSArnaldo Carvalho de Melo size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0])); 1060055c67edSArnaldo Carvalho de Melo 1061055c67edSArnaldo Carvalho de Melo event = zalloc(size); 1062055c67edSArnaldo Carvalho de Melo if (!event) 1063055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1064055c67edSArnaldo Carvalho de Melo 1065055c67edSArnaldo Carvalho de Melo event->header.type = PERF_RECORD_STAT_CONFIG; 1066055c67edSArnaldo Carvalho de Melo event->header.size = size; 1067055c67edSArnaldo Carvalho de Melo event->nr = PERF_STAT_CONFIG_TERM__MAX; 1068055c67edSArnaldo Carvalho de Melo 1069055c67edSArnaldo Carvalho de Melo #define ADD(__term, __val) \ 1070055c67edSArnaldo Carvalho de Melo event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term; \ 1071055c67edSArnaldo Carvalho de Melo event->data[i].val = __val; \ 1072055c67edSArnaldo Carvalho de Melo i++; 1073055c67edSArnaldo Carvalho de Melo 1074055c67edSArnaldo Carvalho de Melo ADD(AGGR_MODE, config->aggr_mode) 1075055c67edSArnaldo Carvalho de Melo ADD(INTERVAL, config->interval) 1076055c67edSArnaldo Carvalho de Melo ADD(SCALE, config->scale) 1077055c67edSArnaldo Carvalho de Melo 1078055c67edSArnaldo Carvalho de Melo WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX, 1079055c67edSArnaldo Carvalho de Melo "stat config terms unbalanced\n"); 1080055c67edSArnaldo Carvalho de Melo #undef ADD 1081055c67edSArnaldo Carvalho de Melo 1082055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *) event, NULL, machine); 1083055c67edSArnaldo Carvalho de Melo 1084055c67edSArnaldo Carvalho de Melo free(event); 1085055c67edSArnaldo Carvalho de Melo return err; 1086055c67edSArnaldo Carvalho de Melo } 1087055c67edSArnaldo Carvalho de Melo 1088055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat(struct perf_tool *tool, 1089055c67edSArnaldo Carvalho de Melo u32 cpu, u32 thread, u64 id, 1090055c67edSArnaldo Carvalho de Melo struct perf_counts_values *count, 1091055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1092055c67edSArnaldo Carvalho de Melo struct machine *machine) 1093055c67edSArnaldo Carvalho de Melo { 1094055c67edSArnaldo Carvalho de Melo struct perf_record_stat event; 1095055c67edSArnaldo Carvalho de Melo 1096055c67edSArnaldo Carvalho de Melo event.header.type = PERF_RECORD_STAT; 1097055c67edSArnaldo Carvalho de Melo event.header.size = sizeof(event); 1098055c67edSArnaldo Carvalho de Melo event.header.misc = 0; 1099055c67edSArnaldo Carvalho de Melo 1100055c67edSArnaldo Carvalho de Melo event.id = id; 1101055c67edSArnaldo Carvalho de Melo event.cpu = cpu; 1102055c67edSArnaldo Carvalho de Melo event.thread = thread; 1103055c67edSArnaldo Carvalho de Melo event.val = count->val; 1104055c67edSArnaldo Carvalho de Melo event.ena = count->ena; 1105055c67edSArnaldo Carvalho de Melo event.run = count->run; 1106055c67edSArnaldo Carvalho de Melo 1107055c67edSArnaldo Carvalho de Melo return process(tool, (union perf_event *) &event, NULL, machine); 1108055c67edSArnaldo Carvalho de Melo } 1109055c67edSArnaldo Carvalho de Melo 1110055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_round(struct perf_tool *tool, 1111055c67edSArnaldo Carvalho de Melo u64 evtime, u64 type, 1112055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, 1113055c67edSArnaldo Carvalho de Melo struct machine *machine) 1114055c67edSArnaldo Carvalho de Melo { 1115055c67edSArnaldo Carvalho de Melo struct perf_record_stat_round event; 1116055c67edSArnaldo Carvalho de Melo 1117055c67edSArnaldo Carvalho de Melo event.header.type = PERF_RECORD_STAT_ROUND; 1118055c67edSArnaldo Carvalho de Melo event.header.size = sizeof(event); 1119055c67edSArnaldo Carvalho de Melo event.header.misc = 0; 1120055c67edSArnaldo Carvalho de Melo 1121055c67edSArnaldo Carvalho de Melo event.time = evtime; 1122055c67edSArnaldo Carvalho de Melo event.type = type; 1123055c67edSArnaldo Carvalho de Melo 1124055c67edSArnaldo Carvalho de Melo return process(tool, (union perf_event *) &event, NULL, machine); 1125055c67edSArnaldo Carvalho de Melo } 1126055c67edSArnaldo Carvalho de Melo 1127055c67edSArnaldo Carvalho de Melo size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format) 1128055c67edSArnaldo Carvalho de Melo { 1129055c67edSArnaldo Carvalho de Melo size_t sz, result = sizeof(struct perf_record_sample); 1130055c67edSArnaldo Carvalho de Melo 1131055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IDENTIFIER) 1132055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1133055c67edSArnaldo Carvalho de Melo 1134055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IP) 1135055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1136055c67edSArnaldo Carvalho de Melo 1137055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TID) 1138055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1139055c67edSArnaldo Carvalho de Melo 1140055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TIME) 1141055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1142055c67edSArnaldo Carvalho de Melo 1143055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ADDR) 1144055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1145055c67edSArnaldo Carvalho de Melo 1146055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ID) 1147055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1148055c67edSArnaldo Carvalho de Melo 1149055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STREAM_ID) 1150055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1151055c67edSArnaldo Carvalho de Melo 1152055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CPU) 1153055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1154055c67edSArnaldo Carvalho de Melo 1155055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PERIOD) 1156055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1157055c67edSArnaldo Carvalho de Melo 1158055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_READ) { 1159055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1160055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 1161055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1162055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 1163055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1164055c67edSArnaldo Carvalho de Melo /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 1165055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) { 1166055c67edSArnaldo Carvalho de Melo sz = sample->read.group.nr * 1167055c67edSArnaldo Carvalho de Melo sizeof(struct sample_read_value); 1168055c67edSArnaldo Carvalho de Melo result += sz; 1169055c67edSArnaldo Carvalho de Melo } else { 1170055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1171055c67edSArnaldo Carvalho de Melo } 1172055c67edSArnaldo Carvalho de Melo } 1173055c67edSArnaldo Carvalho de Melo 1174055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CALLCHAIN) { 1175055c67edSArnaldo Carvalho de Melo sz = (sample->callchain->nr + 1) * sizeof(u64); 1176055c67edSArnaldo Carvalho de Melo result += sz; 1177055c67edSArnaldo Carvalho de Melo } 1178055c67edSArnaldo Carvalho de Melo 1179055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_RAW) { 1180055c67edSArnaldo Carvalho de Melo result += sizeof(u32); 1181055c67edSArnaldo Carvalho de Melo result += sample->raw_size; 1182055c67edSArnaldo Carvalho de Melo } 1183055c67edSArnaldo Carvalho de Melo 1184055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_BRANCH_STACK) { 1185055c67edSArnaldo Carvalho de Melo sz = sample->branch_stack->nr * sizeof(struct branch_entry); 1186055c67edSArnaldo Carvalho de Melo sz += sizeof(u64); 1187055c67edSArnaldo Carvalho de Melo result += sz; 1188055c67edSArnaldo Carvalho de Melo } 1189055c67edSArnaldo Carvalho de Melo 1190055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_USER) { 1191055c67edSArnaldo Carvalho de Melo if (sample->user_regs.abi) { 1192055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1193055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->user_regs.mask) * sizeof(u64); 1194055c67edSArnaldo Carvalho de Melo result += sz; 1195055c67edSArnaldo Carvalho de Melo } else { 1196055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1197055c67edSArnaldo Carvalho de Melo } 1198055c67edSArnaldo Carvalho de Melo } 1199055c67edSArnaldo Carvalho de Melo 1200055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STACK_USER) { 1201055c67edSArnaldo Carvalho de Melo sz = sample->user_stack.size; 1202055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1203055c67edSArnaldo Carvalho de Melo if (sz) { 1204055c67edSArnaldo Carvalho de Melo result += sz; 1205055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1206055c67edSArnaldo Carvalho de Melo } 1207055c67edSArnaldo Carvalho de Melo } 1208055c67edSArnaldo Carvalho de Melo 1209055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_WEIGHT) 1210055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1211055c67edSArnaldo Carvalho de Melo 1212055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_DATA_SRC) 1213055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1214055c67edSArnaldo Carvalho de Melo 1215055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TRANSACTION) 1216055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1217055c67edSArnaldo Carvalho de Melo 1218055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_INTR) { 1219055c67edSArnaldo Carvalho de Melo if (sample->intr_regs.abi) { 1220055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1221055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 1222055c67edSArnaldo Carvalho de Melo result += sz; 1223055c67edSArnaldo Carvalho de Melo } else { 1224055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1225055c67edSArnaldo Carvalho de Melo } 1226055c67edSArnaldo Carvalho de Melo } 1227055c67edSArnaldo Carvalho de Melo 1228055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PHYS_ADDR) 1229055c67edSArnaldo Carvalho de Melo result += sizeof(u64); 1230055c67edSArnaldo Carvalho de Melo 123198dcf14dSAdrian Hunter if (type & PERF_SAMPLE_AUX) { 123298dcf14dSAdrian Hunter result += sizeof(u64); 123398dcf14dSAdrian Hunter result += sample->aux_sample.size; 123498dcf14dSAdrian Hunter } 123598dcf14dSAdrian Hunter 1236055c67edSArnaldo Carvalho de Melo return result; 1237055c67edSArnaldo Carvalho de Melo } 1238055c67edSArnaldo Carvalho de Melo 1239055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format, 1240055c67edSArnaldo Carvalho de Melo const struct perf_sample *sample) 1241055c67edSArnaldo Carvalho de Melo { 1242055c67edSArnaldo Carvalho de Melo __u64 *array; 1243055c67edSArnaldo Carvalho de Melo size_t sz; 1244055c67edSArnaldo Carvalho de Melo /* 1245055c67edSArnaldo Carvalho de Melo * used for cross-endian analysis. See git commit 65014ab3 1246055c67edSArnaldo Carvalho de Melo * for why this goofiness is needed. 1247055c67edSArnaldo Carvalho de Melo */ 1248055c67edSArnaldo Carvalho de Melo union u64_swap u; 1249055c67edSArnaldo Carvalho de Melo 1250055c67edSArnaldo Carvalho de Melo array = event->sample.array; 1251055c67edSArnaldo Carvalho de Melo 1252055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IDENTIFIER) { 1253055c67edSArnaldo Carvalho de Melo *array = sample->id; 1254055c67edSArnaldo Carvalho de Melo array++; 1255055c67edSArnaldo Carvalho de Melo } 1256055c67edSArnaldo Carvalho de Melo 1257055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_IP) { 1258055c67edSArnaldo Carvalho de Melo *array = sample->ip; 1259055c67edSArnaldo Carvalho de Melo array++; 1260055c67edSArnaldo Carvalho de Melo } 1261055c67edSArnaldo Carvalho de Melo 1262055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TID) { 1263055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->pid; 1264055c67edSArnaldo Carvalho de Melo u.val32[1] = sample->tid; 1265055c67edSArnaldo Carvalho de Melo *array = u.val64; 1266055c67edSArnaldo Carvalho de Melo array++; 1267055c67edSArnaldo Carvalho de Melo } 1268055c67edSArnaldo Carvalho de Melo 1269055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TIME) { 1270055c67edSArnaldo Carvalho de Melo *array = sample->time; 1271055c67edSArnaldo Carvalho de Melo array++; 1272055c67edSArnaldo Carvalho de Melo } 1273055c67edSArnaldo Carvalho de Melo 1274055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ADDR) { 1275055c67edSArnaldo Carvalho de Melo *array = sample->addr; 1276055c67edSArnaldo Carvalho de Melo array++; 1277055c67edSArnaldo Carvalho de Melo } 1278055c67edSArnaldo Carvalho de Melo 1279055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_ID) { 1280055c67edSArnaldo Carvalho de Melo *array = sample->id; 1281055c67edSArnaldo Carvalho de Melo array++; 1282055c67edSArnaldo Carvalho de Melo } 1283055c67edSArnaldo Carvalho de Melo 1284055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STREAM_ID) { 1285055c67edSArnaldo Carvalho de Melo *array = sample->stream_id; 1286055c67edSArnaldo Carvalho de Melo array++; 1287055c67edSArnaldo Carvalho de Melo } 1288055c67edSArnaldo Carvalho de Melo 1289055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CPU) { 1290055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->cpu; 1291055c67edSArnaldo Carvalho de Melo u.val32[1] = 0; 1292055c67edSArnaldo Carvalho de Melo *array = u.val64; 1293055c67edSArnaldo Carvalho de Melo array++; 1294055c67edSArnaldo Carvalho de Melo } 1295055c67edSArnaldo Carvalho de Melo 1296055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PERIOD) { 1297055c67edSArnaldo Carvalho de Melo *array = sample->period; 1298055c67edSArnaldo Carvalho de Melo array++; 1299055c67edSArnaldo Carvalho de Melo } 1300055c67edSArnaldo Carvalho de Melo 1301055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_READ) { 1302055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) 1303055c67edSArnaldo Carvalho de Melo *array = sample->read.group.nr; 1304055c67edSArnaldo Carvalho de Melo else 1305055c67edSArnaldo Carvalho de Melo *array = sample->read.one.value; 1306055c67edSArnaldo Carvalho de Melo array++; 1307055c67edSArnaldo Carvalho de Melo 1308055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { 1309055c67edSArnaldo Carvalho de Melo *array = sample->read.time_enabled; 1310055c67edSArnaldo Carvalho de Melo array++; 1311055c67edSArnaldo Carvalho de Melo } 1312055c67edSArnaldo Carvalho de Melo 1313055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { 1314055c67edSArnaldo Carvalho de Melo *array = sample->read.time_running; 1315055c67edSArnaldo Carvalho de Melo array++; 1316055c67edSArnaldo Carvalho de Melo } 1317055c67edSArnaldo Carvalho de Melo 1318055c67edSArnaldo Carvalho de Melo /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ 1319055c67edSArnaldo Carvalho de Melo if (read_format & PERF_FORMAT_GROUP) { 1320055c67edSArnaldo Carvalho de Melo sz = sample->read.group.nr * 1321055c67edSArnaldo Carvalho de Melo sizeof(struct sample_read_value); 1322055c67edSArnaldo Carvalho de Melo memcpy(array, sample->read.group.values, sz); 1323055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1324055c67edSArnaldo Carvalho de Melo } else { 1325055c67edSArnaldo Carvalho de Melo *array = sample->read.one.id; 1326055c67edSArnaldo Carvalho de Melo array++; 1327055c67edSArnaldo Carvalho de Melo } 1328055c67edSArnaldo Carvalho de Melo } 1329055c67edSArnaldo Carvalho de Melo 1330055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_CALLCHAIN) { 1331055c67edSArnaldo Carvalho de Melo sz = (sample->callchain->nr + 1) * sizeof(u64); 1332055c67edSArnaldo Carvalho de Melo memcpy(array, sample->callchain, sz); 1333055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1334055c67edSArnaldo Carvalho de Melo } 1335055c67edSArnaldo Carvalho de Melo 1336055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_RAW) { 1337055c67edSArnaldo Carvalho de Melo u.val32[0] = sample->raw_size; 1338055c67edSArnaldo Carvalho de Melo *array = u.val64; 1339055c67edSArnaldo Carvalho de Melo array = (void *)array + sizeof(u32); 1340055c67edSArnaldo Carvalho de Melo 1341055c67edSArnaldo Carvalho de Melo memcpy(array, sample->raw_data, sample->raw_size); 1342055c67edSArnaldo Carvalho de Melo array = (void *)array + sample->raw_size; 1343055c67edSArnaldo Carvalho de Melo } 1344055c67edSArnaldo Carvalho de Melo 1345055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_BRANCH_STACK) { 1346055c67edSArnaldo Carvalho de Melo sz = sample->branch_stack->nr * sizeof(struct branch_entry); 1347055c67edSArnaldo Carvalho de Melo sz += sizeof(u64); 1348055c67edSArnaldo Carvalho de Melo memcpy(array, sample->branch_stack, sz); 1349055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1350055c67edSArnaldo Carvalho de Melo } 1351055c67edSArnaldo Carvalho de Melo 1352055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_USER) { 1353055c67edSArnaldo Carvalho de Melo if (sample->user_regs.abi) { 1354055c67edSArnaldo Carvalho de Melo *array++ = sample->user_regs.abi; 1355055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->user_regs.mask) * sizeof(u64); 1356055c67edSArnaldo Carvalho de Melo memcpy(array, sample->user_regs.regs, sz); 1357055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1358055c67edSArnaldo Carvalho de Melo } else { 1359055c67edSArnaldo Carvalho de Melo *array++ = 0; 1360055c67edSArnaldo Carvalho de Melo } 1361055c67edSArnaldo Carvalho de Melo } 1362055c67edSArnaldo Carvalho de Melo 1363055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_STACK_USER) { 1364055c67edSArnaldo Carvalho de Melo sz = sample->user_stack.size; 1365055c67edSArnaldo Carvalho de Melo *array++ = sz; 1366055c67edSArnaldo Carvalho de Melo if (sz) { 1367055c67edSArnaldo Carvalho de Melo memcpy(array, sample->user_stack.data, sz); 1368055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1369055c67edSArnaldo Carvalho de Melo *array++ = sz; 1370055c67edSArnaldo Carvalho de Melo } 1371055c67edSArnaldo Carvalho de Melo } 1372055c67edSArnaldo Carvalho de Melo 1373055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_WEIGHT) { 1374055c67edSArnaldo Carvalho de Melo *array = sample->weight; 1375055c67edSArnaldo Carvalho de Melo array++; 1376055c67edSArnaldo Carvalho de Melo } 1377055c67edSArnaldo Carvalho de Melo 1378055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_DATA_SRC) { 1379055c67edSArnaldo Carvalho de Melo *array = sample->data_src; 1380055c67edSArnaldo Carvalho de Melo array++; 1381055c67edSArnaldo Carvalho de Melo } 1382055c67edSArnaldo Carvalho de Melo 1383055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_TRANSACTION) { 1384055c67edSArnaldo Carvalho de Melo *array = sample->transaction; 1385055c67edSArnaldo Carvalho de Melo array++; 1386055c67edSArnaldo Carvalho de Melo } 1387055c67edSArnaldo Carvalho de Melo 1388055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_REGS_INTR) { 1389055c67edSArnaldo Carvalho de Melo if (sample->intr_regs.abi) { 1390055c67edSArnaldo Carvalho de Melo *array++ = sample->intr_regs.abi; 1391055c67edSArnaldo Carvalho de Melo sz = hweight64(sample->intr_regs.mask) * sizeof(u64); 1392055c67edSArnaldo Carvalho de Melo memcpy(array, sample->intr_regs.regs, sz); 1393055c67edSArnaldo Carvalho de Melo array = (void *)array + sz; 1394055c67edSArnaldo Carvalho de Melo } else { 1395055c67edSArnaldo Carvalho de Melo *array++ = 0; 1396055c67edSArnaldo Carvalho de Melo } 1397055c67edSArnaldo Carvalho de Melo } 1398055c67edSArnaldo Carvalho de Melo 1399055c67edSArnaldo Carvalho de Melo if (type & PERF_SAMPLE_PHYS_ADDR) { 1400055c67edSArnaldo Carvalho de Melo *array = sample->phys_addr; 1401055c67edSArnaldo Carvalho de Melo array++; 1402055c67edSArnaldo Carvalho de Melo } 1403055c67edSArnaldo Carvalho de Melo 140498dcf14dSAdrian Hunter if (type & PERF_SAMPLE_AUX) { 140598dcf14dSAdrian Hunter sz = sample->aux_sample.size; 140698dcf14dSAdrian Hunter *array++ = sz; 140798dcf14dSAdrian Hunter memcpy(array, sample->aux_sample.data, sz); 140898dcf14dSAdrian Hunter array = (void *)array + sz; 140998dcf14dSAdrian Hunter } 141098dcf14dSAdrian Hunter 1411055c67edSArnaldo Carvalho de Melo return 0; 1412055c67edSArnaldo Carvalho de Melo } 1413055c67edSArnaldo Carvalho de Melo 1414055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, 1415055c67edSArnaldo Carvalho de Melo struct evlist *evlist, struct machine *machine) 1416055c67edSArnaldo Carvalho de Melo { 1417055c67edSArnaldo Carvalho de Melo union perf_event *ev; 1418055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 1419055c67edSArnaldo Carvalho de Melo size_t nr = 0, i = 0, sz, max_nr, n; 1420055c67edSArnaldo Carvalho de Melo int err; 1421055c67edSArnaldo Carvalho de Melo 1422055c67edSArnaldo Carvalho de Melo pr_debug2("Synthesizing id index\n"); 1423055c67edSArnaldo Carvalho de Melo 1424055c67edSArnaldo Carvalho de Melo max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / 1425055c67edSArnaldo Carvalho de Melo sizeof(struct id_index_entry); 1426055c67edSArnaldo Carvalho de Melo 1427055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) 1428e7eb9002SJiri Olsa nr += evsel->core.ids; 1429055c67edSArnaldo Carvalho de Melo 1430055c67edSArnaldo Carvalho de Melo n = nr > max_nr ? max_nr : nr; 1431055c67edSArnaldo Carvalho de Melo sz = sizeof(struct perf_record_id_index) + n * sizeof(struct id_index_entry); 1432055c67edSArnaldo Carvalho de Melo ev = zalloc(sz); 1433055c67edSArnaldo Carvalho de Melo if (!ev) 1434055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1435055c67edSArnaldo Carvalho de Melo 1436055c67edSArnaldo Carvalho de Melo ev->id_index.header.type = PERF_RECORD_ID_INDEX; 1437055c67edSArnaldo Carvalho de Melo ev->id_index.header.size = sz; 1438055c67edSArnaldo Carvalho de Melo ev->id_index.nr = n; 1439055c67edSArnaldo Carvalho de Melo 1440055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) { 1441055c67edSArnaldo Carvalho de Melo u32 j; 1442055c67edSArnaldo Carvalho de Melo 1443e7eb9002SJiri Olsa for (j = 0; j < evsel->core.ids; j++) { 1444055c67edSArnaldo Carvalho de Melo struct id_index_entry *e; 1445055c67edSArnaldo Carvalho de Melo struct perf_sample_id *sid; 1446055c67edSArnaldo Carvalho de Melo 1447055c67edSArnaldo Carvalho de Melo if (i >= n) { 1448055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, machine); 1449055c67edSArnaldo Carvalho de Melo if (err) 1450055c67edSArnaldo Carvalho de Melo goto out_err; 1451055c67edSArnaldo Carvalho de Melo nr -= n; 1452055c67edSArnaldo Carvalho de Melo i = 0; 1453055c67edSArnaldo Carvalho de Melo } 1454055c67edSArnaldo Carvalho de Melo 1455055c67edSArnaldo Carvalho de Melo e = &ev->id_index.entries[i++]; 1456055c67edSArnaldo Carvalho de Melo 1457deaf3219SJiri Olsa e->id = evsel->core.id[j]; 1458055c67edSArnaldo Carvalho de Melo 1459055c67edSArnaldo Carvalho de Melo sid = perf_evlist__id2sid(evlist, e->id); 1460055c67edSArnaldo Carvalho de Melo if (!sid) { 1461055c67edSArnaldo Carvalho de Melo free(ev); 1462055c67edSArnaldo Carvalho de Melo return -ENOENT; 1463055c67edSArnaldo Carvalho de Melo } 1464055c67edSArnaldo Carvalho de Melo 1465055c67edSArnaldo Carvalho de Melo e->idx = sid->idx; 1466055c67edSArnaldo Carvalho de Melo e->cpu = sid->cpu; 1467055c67edSArnaldo Carvalho de Melo e->tid = sid->tid; 1468055c67edSArnaldo Carvalho de Melo } 1469055c67edSArnaldo Carvalho de Melo } 1470055c67edSArnaldo Carvalho de Melo 1471055c67edSArnaldo Carvalho de Melo sz = sizeof(struct perf_record_id_index) + nr * sizeof(struct id_index_entry); 1472055c67edSArnaldo Carvalho de Melo ev->id_index.header.size = sz; 1473055c67edSArnaldo Carvalho de Melo ev->id_index.nr = nr; 1474055c67edSArnaldo Carvalho de Melo 1475055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, machine); 1476055c67edSArnaldo Carvalho de Melo out_err: 1477055c67edSArnaldo Carvalho de Melo free(ev); 1478055c67edSArnaldo Carvalho de Melo 1479055c67edSArnaldo Carvalho de Melo return err; 1480055c67edSArnaldo Carvalho de Melo } 1481055c67edSArnaldo Carvalho de Melo 1482055c67edSArnaldo Carvalho de Melo int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, 1483055c67edSArnaldo Carvalho de Melo struct target *target, struct perf_thread_map *threads, 1484055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, bool data_mmap, 1485055c67edSArnaldo Carvalho de Melo unsigned int nr_threads_synthesize) 1486055c67edSArnaldo Carvalho de Melo { 1487055c67edSArnaldo Carvalho de Melo if (target__has_task(target)) 1488055c67edSArnaldo Carvalho de Melo return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap); 1489055c67edSArnaldo Carvalho de Melo else if (target__has_cpu(target)) 1490055c67edSArnaldo Carvalho de Melo return perf_event__synthesize_threads(tool, process, 1491055c67edSArnaldo Carvalho de Melo machine, data_mmap, 1492055c67edSArnaldo Carvalho de Melo nr_threads_synthesize); 1493055c67edSArnaldo Carvalho de Melo /* command specified */ 1494055c67edSArnaldo Carvalho de Melo return 0; 1495055c67edSArnaldo Carvalho de Melo } 1496055c67edSArnaldo Carvalho de Melo 1497055c67edSArnaldo Carvalho de Melo int machine__synthesize_threads(struct machine *machine, struct target *target, 1498055c67edSArnaldo Carvalho de Melo struct perf_thread_map *threads, bool data_mmap, 1499055c67edSArnaldo Carvalho de Melo unsigned int nr_threads_synthesize) 1500055c67edSArnaldo Carvalho de Melo { 1501055c67edSArnaldo Carvalho de Melo return __machine__synthesize_threads(machine, NULL, target, threads, 1502055c67edSArnaldo Carvalho de Melo perf_event__process, data_mmap, 1503055c67edSArnaldo Carvalho de Melo nr_threads_synthesize); 1504055c67edSArnaldo Carvalho de Melo } 1505055c67edSArnaldo Carvalho de Melo 1506055c67edSArnaldo Carvalho de Melo static struct perf_record_event_update *event_update_event__new(size_t size, u64 type, u64 id) 1507055c67edSArnaldo Carvalho de Melo { 1508055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1509055c67edSArnaldo Carvalho de Melo 1510055c67edSArnaldo Carvalho de Melo size += sizeof(*ev); 1511055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 1512055c67edSArnaldo Carvalho de Melo 1513055c67edSArnaldo Carvalho de Melo ev = zalloc(size); 1514055c67edSArnaldo Carvalho de Melo if (ev) { 1515055c67edSArnaldo Carvalho de Melo ev->header.type = PERF_RECORD_EVENT_UPDATE; 1516055c67edSArnaldo Carvalho de Melo ev->header.size = (u16)size; 1517055c67edSArnaldo Carvalho de Melo ev->type = type; 1518055c67edSArnaldo Carvalho de Melo ev->id = id; 1519055c67edSArnaldo Carvalho de Melo } 1520055c67edSArnaldo Carvalho de Melo return ev; 1521055c67edSArnaldo Carvalho de Melo } 1522055c67edSArnaldo Carvalho de Melo 1523055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_unit(struct perf_tool *tool, struct evsel *evsel, 1524055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1525055c67edSArnaldo Carvalho de Melo { 1526055c67edSArnaldo Carvalho de Melo size_t size = strlen(evsel->unit); 1527055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1528055c67edSArnaldo Carvalho de Melo int err; 1529055c67edSArnaldo Carvalho de Melo 1530deaf3219SJiri Olsa ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->core.id[0]); 1531055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1532055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1533055c67edSArnaldo Carvalho de Melo 1534055c67edSArnaldo Carvalho de Melo strlcpy(ev->data, evsel->unit, size + 1); 1535055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1536055c67edSArnaldo Carvalho de Melo free(ev); 1537055c67edSArnaldo Carvalho de Melo return err; 1538055c67edSArnaldo Carvalho de Melo } 1539055c67edSArnaldo Carvalho de Melo 1540055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_scale(struct perf_tool *tool, struct evsel *evsel, 1541055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1542055c67edSArnaldo Carvalho de Melo { 1543055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1544055c67edSArnaldo Carvalho de Melo struct perf_record_event_update_scale *ev_data; 1545055c67edSArnaldo Carvalho de Melo int err; 1546055c67edSArnaldo Carvalho de Melo 1547deaf3219SJiri Olsa ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->core.id[0]); 1548055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1549055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1550055c67edSArnaldo Carvalho de Melo 1551055c67edSArnaldo Carvalho de Melo ev_data = (struct perf_record_event_update_scale *)ev->data; 1552055c67edSArnaldo Carvalho de Melo ev_data->scale = evsel->scale; 1553055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1554055c67edSArnaldo Carvalho de Melo free(ev); 1555055c67edSArnaldo Carvalho de Melo return err; 1556055c67edSArnaldo Carvalho de Melo } 1557055c67edSArnaldo Carvalho de Melo 1558055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_name(struct perf_tool *tool, struct evsel *evsel, 1559055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1560055c67edSArnaldo Carvalho de Melo { 1561055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1562055c67edSArnaldo Carvalho de Melo size_t len = strlen(evsel->name); 1563055c67edSArnaldo Carvalho de Melo int err; 1564055c67edSArnaldo Carvalho de Melo 1565deaf3219SJiri Olsa ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->core.id[0]); 1566055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1567055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1568055c67edSArnaldo Carvalho de Melo 1569055c67edSArnaldo Carvalho de Melo strlcpy(ev->data, evsel->name, len + 1); 1570055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1571055c67edSArnaldo Carvalho de Melo free(ev); 1572055c67edSArnaldo Carvalho de Melo return err; 1573055c67edSArnaldo Carvalho de Melo } 1574055c67edSArnaldo Carvalho de Melo 1575055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, struct evsel *evsel, 1576055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1577055c67edSArnaldo Carvalho de Melo { 1578055c67edSArnaldo Carvalho de Melo size_t size = sizeof(struct perf_record_event_update); 1579055c67edSArnaldo Carvalho de Melo struct perf_record_event_update *ev; 1580055c67edSArnaldo Carvalho de Melo int max, err; 1581055c67edSArnaldo Carvalho de Melo u16 type; 1582055c67edSArnaldo Carvalho de Melo 1583055c67edSArnaldo Carvalho de Melo if (!evsel->core.own_cpus) 1584055c67edSArnaldo Carvalho de Melo return 0; 1585055c67edSArnaldo Carvalho de Melo 1586055c67edSArnaldo Carvalho de Melo ev = cpu_map_data__alloc(evsel->core.own_cpus, &size, &type, &max); 1587055c67edSArnaldo Carvalho de Melo if (!ev) 1588055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1589055c67edSArnaldo Carvalho de Melo 1590055c67edSArnaldo Carvalho de Melo ev->header.type = PERF_RECORD_EVENT_UPDATE; 1591055c67edSArnaldo Carvalho de Melo ev->header.size = (u16)size; 1592055c67edSArnaldo Carvalho de Melo ev->type = PERF_EVENT_UPDATE__CPUS; 1593deaf3219SJiri Olsa ev->id = evsel->core.id[0]; 1594055c67edSArnaldo Carvalho de Melo 1595055c67edSArnaldo Carvalho de Melo cpu_map_data__synthesize((struct perf_record_cpu_map_data *)ev->data, 1596055c67edSArnaldo Carvalho de Melo evsel->core.own_cpus, type, max); 1597055c67edSArnaldo Carvalho de Melo 1598055c67edSArnaldo Carvalho de Melo err = process(tool, (union perf_event *)ev, NULL, NULL); 1599055c67edSArnaldo Carvalho de Melo free(ev); 1600055c67edSArnaldo Carvalho de Melo return err; 1601055c67edSArnaldo Carvalho de Melo } 1602055c67edSArnaldo Carvalho de Melo 1603055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_attrs(struct perf_tool *tool, struct evlist *evlist, 1604055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1605055c67edSArnaldo Carvalho de Melo { 1606055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 1607055c67edSArnaldo Carvalho de Melo int err = 0; 1608055c67edSArnaldo Carvalho de Melo 1609055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) { 1610e7eb9002SJiri Olsa err = perf_event__synthesize_attr(tool, &evsel->core.attr, evsel->core.ids, 1611deaf3219SJiri Olsa evsel->core.id, process); 1612055c67edSArnaldo Carvalho de Melo if (err) { 1613055c67edSArnaldo Carvalho de Melo pr_debug("failed to create perf header attribute\n"); 1614055c67edSArnaldo Carvalho de Melo return err; 1615055c67edSArnaldo Carvalho de Melo } 1616055c67edSArnaldo Carvalho de Melo } 1617055c67edSArnaldo Carvalho de Melo 1618055c67edSArnaldo Carvalho de Melo return err; 1619055c67edSArnaldo Carvalho de Melo } 1620055c67edSArnaldo Carvalho de Melo 1621055c67edSArnaldo Carvalho de Melo static bool has_unit(struct evsel *evsel) 1622055c67edSArnaldo Carvalho de Melo { 1623055c67edSArnaldo Carvalho de Melo return evsel->unit && *evsel->unit; 1624055c67edSArnaldo Carvalho de Melo } 1625055c67edSArnaldo Carvalho de Melo 1626055c67edSArnaldo Carvalho de Melo static bool has_scale(struct evsel *evsel) 1627055c67edSArnaldo Carvalho de Melo { 1628055c67edSArnaldo Carvalho de Melo return evsel->scale != 1; 1629055c67edSArnaldo Carvalho de Melo } 1630055c67edSArnaldo Carvalho de Melo 1631055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_extra_attr(struct perf_tool *tool, struct evlist *evsel_list, 1632055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, bool is_pipe) 1633055c67edSArnaldo Carvalho de Melo { 1634055c67edSArnaldo Carvalho de Melo struct evsel *evsel; 1635055c67edSArnaldo Carvalho de Melo int err; 1636055c67edSArnaldo Carvalho de Melo 1637055c67edSArnaldo Carvalho de Melo /* 1638055c67edSArnaldo Carvalho de Melo * Synthesize other events stuff not carried within 1639055c67edSArnaldo Carvalho de Melo * attr event - unit, scale, name 1640055c67edSArnaldo Carvalho de Melo */ 1641055c67edSArnaldo Carvalho de Melo evlist__for_each_entry(evsel_list, evsel) { 1642055c67edSArnaldo Carvalho de Melo if (!evsel->supported) 1643055c67edSArnaldo Carvalho de Melo continue; 1644055c67edSArnaldo Carvalho de Melo 1645055c67edSArnaldo Carvalho de Melo /* 1646055c67edSArnaldo Carvalho de Melo * Synthesize unit and scale only if it's defined. 1647055c67edSArnaldo Carvalho de Melo */ 1648055c67edSArnaldo Carvalho de Melo if (has_unit(evsel)) { 1649055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_unit(tool, evsel, process); 1650055c67edSArnaldo Carvalho de Melo if (err < 0) { 1651055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel unit.\n"); 1652055c67edSArnaldo Carvalho de Melo return err; 1653055c67edSArnaldo Carvalho de Melo } 1654055c67edSArnaldo Carvalho de Melo } 1655055c67edSArnaldo Carvalho de Melo 1656055c67edSArnaldo Carvalho de Melo if (has_scale(evsel)) { 1657055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_scale(tool, evsel, process); 1658055c67edSArnaldo Carvalho de Melo if (err < 0) { 1659055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel evsel.\n"); 1660055c67edSArnaldo Carvalho de Melo return err; 1661055c67edSArnaldo Carvalho de Melo } 1662055c67edSArnaldo Carvalho de Melo } 1663055c67edSArnaldo Carvalho de Melo 1664055c67edSArnaldo Carvalho de Melo if (evsel->core.own_cpus) { 1665055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_cpus(tool, evsel, process); 1666055c67edSArnaldo Carvalho de Melo if (err < 0) { 1667055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel cpus.\n"); 1668055c67edSArnaldo Carvalho de Melo return err; 1669055c67edSArnaldo Carvalho de Melo } 1670055c67edSArnaldo Carvalho de Melo } 1671055c67edSArnaldo Carvalho de Melo 1672055c67edSArnaldo Carvalho de Melo /* 1673055c67edSArnaldo Carvalho de Melo * Name is needed only for pipe output, 1674055c67edSArnaldo Carvalho de Melo * perf.data carries event names. 1675055c67edSArnaldo Carvalho de Melo */ 1676055c67edSArnaldo Carvalho de Melo if (is_pipe) { 1677055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_event_update_name(tool, evsel, process); 1678055c67edSArnaldo Carvalho de Melo if (err < 0) { 1679055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize evsel name.\n"); 1680055c67edSArnaldo Carvalho de Melo return err; 1681055c67edSArnaldo Carvalho de Melo } 1682055c67edSArnaldo Carvalho de Melo } 1683055c67edSArnaldo Carvalho de Melo } 1684055c67edSArnaldo Carvalho de Melo return 0; 1685055c67edSArnaldo Carvalho de Melo } 1686055c67edSArnaldo Carvalho de Melo 1687055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, 1688055c67edSArnaldo Carvalho de Melo u32 ids, u64 *id, perf_event__handler_t process) 1689055c67edSArnaldo Carvalho de Melo { 1690055c67edSArnaldo Carvalho de Melo union perf_event *ev; 1691055c67edSArnaldo Carvalho de Melo size_t size; 1692055c67edSArnaldo Carvalho de Melo int err; 1693055c67edSArnaldo Carvalho de Melo 1694055c67edSArnaldo Carvalho de Melo size = sizeof(struct perf_event_attr); 1695055c67edSArnaldo Carvalho de Melo size = PERF_ALIGN(size, sizeof(u64)); 1696055c67edSArnaldo Carvalho de Melo size += sizeof(struct perf_event_header); 1697055c67edSArnaldo Carvalho de Melo size += ids * sizeof(u64); 1698055c67edSArnaldo Carvalho de Melo 1699055c67edSArnaldo Carvalho de Melo ev = zalloc(size); 1700055c67edSArnaldo Carvalho de Melo 1701055c67edSArnaldo Carvalho de Melo if (ev == NULL) 1702055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1703055c67edSArnaldo Carvalho de Melo 1704055c67edSArnaldo Carvalho de Melo ev->attr.attr = *attr; 1705055c67edSArnaldo Carvalho de Melo memcpy(ev->attr.id, id, ids * sizeof(u64)); 1706055c67edSArnaldo Carvalho de Melo 1707055c67edSArnaldo Carvalho de Melo ev->attr.header.type = PERF_RECORD_HEADER_ATTR; 1708055c67edSArnaldo Carvalho de Melo ev->attr.header.size = (u16)size; 1709055c67edSArnaldo Carvalho de Melo 1710055c67edSArnaldo Carvalho de Melo if (ev->attr.header.size == size) 1711055c67edSArnaldo Carvalho de Melo err = process(tool, ev, NULL, NULL); 1712055c67edSArnaldo Carvalho de Melo else 1713055c67edSArnaldo Carvalho de Melo err = -E2BIG; 1714055c67edSArnaldo Carvalho de Melo 1715055c67edSArnaldo Carvalho de Melo free(ev); 1716055c67edSArnaldo Carvalho de Melo 1717055c67edSArnaldo Carvalho de Melo return err; 1718055c67edSArnaldo Carvalho de Melo } 1719055c67edSArnaldo Carvalho de Melo 1720055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct evlist *evlist, 1721055c67edSArnaldo Carvalho de Melo perf_event__handler_t process) 1722055c67edSArnaldo Carvalho de Melo { 1723055c67edSArnaldo Carvalho de Melo union perf_event ev; 1724055c67edSArnaldo Carvalho de Melo struct tracing_data *tdata; 1725055c67edSArnaldo Carvalho de Melo ssize_t size = 0, aligned_size = 0, padding; 1726055c67edSArnaldo Carvalho de Melo struct feat_fd ff; 1727055c67edSArnaldo Carvalho de Melo 1728055c67edSArnaldo Carvalho de Melo /* 1729055c67edSArnaldo Carvalho de Melo * We are going to store the size of the data followed 1730055c67edSArnaldo Carvalho de Melo * by the data contents. Since the fd descriptor is a pipe, 1731055c67edSArnaldo Carvalho de Melo * we cannot seek back to store the size of the data once 1732055c67edSArnaldo Carvalho de Melo * we know it. Instead we: 1733055c67edSArnaldo Carvalho de Melo * 1734055c67edSArnaldo Carvalho de Melo * - write the tracing data to the temp file 1735055c67edSArnaldo Carvalho de Melo * - get/write the data size to pipe 1736055c67edSArnaldo Carvalho de Melo * - write the tracing data from the temp file 1737055c67edSArnaldo Carvalho de Melo * to the pipe 1738055c67edSArnaldo Carvalho de Melo */ 1739055c67edSArnaldo Carvalho de Melo tdata = tracing_data_get(&evlist->core.entries, fd, true); 1740055c67edSArnaldo Carvalho de Melo if (!tdata) 1741055c67edSArnaldo Carvalho de Melo return -1; 1742055c67edSArnaldo Carvalho de Melo 1743055c67edSArnaldo Carvalho de Melo memset(&ev, 0, sizeof(ev)); 1744055c67edSArnaldo Carvalho de Melo 1745055c67edSArnaldo Carvalho de Melo ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 1746055c67edSArnaldo Carvalho de Melo size = tdata->size; 1747055c67edSArnaldo Carvalho de Melo aligned_size = PERF_ALIGN(size, sizeof(u64)); 1748055c67edSArnaldo Carvalho de Melo padding = aligned_size - size; 1749055c67edSArnaldo Carvalho de Melo ev.tracing_data.header.size = sizeof(ev.tracing_data); 1750055c67edSArnaldo Carvalho de Melo ev.tracing_data.size = aligned_size; 1751055c67edSArnaldo Carvalho de Melo 1752055c67edSArnaldo Carvalho de Melo process(tool, &ev, NULL, NULL); 1753055c67edSArnaldo Carvalho de Melo 1754055c67edSArnaldo Carvalho de Melo /* 1755055c67edSArnaldo Carvalho de Melo * The put function will copy all the tracing data 1756055c67edSArnaldo Carvalho de Melo * stored in temp file to the pipe. 1757055c67edSArnaldo Carvalho de Melo */ 1758055c67edSArnaldo Carvalho de Melo tracing_data_put(tdata); 1759055c67edSArnaldo Carvalho de Melo 1760055c67edSArnaldo Carvalho de Melo ff = (struct feat_fd){ .fd = fd }; 1761055c67edSArnaldo Carvalho de Melo if (write_padded(&ff, NULL, 0, padding)) 1762055c67edSArnaldo Carvalho de Melo return -1; 1763055c67edSArnaldo Carvalho de Melo 1764055c67edSArnaldo Carvalho de Melo return aligned_size; 1765055c67edSArnaldo Carvalho de Melo } 1766055c67edSArnaldo Carvalho de Melo 1767055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_build_id(struct perf_tool *tool, struct dso *pos, u16 misc, 1768055c67edSArnaldo Carvalho de Melo perf_event__handler_t process, struct machine *machine) 1769055c67edSArnaldo Carvalho de Melo { 1770055c67edSArnaldo Carvalho de Melo union perf_event ev; 1771055c67edSArnaldo Carvalho de Melo size_t len; 1772055c67edSArnaldo Carvalho de Melo 1773055c67edSArnaldo Carvalho de Melo if (!pos->hit) 1774055c67edSArnaldo Carvalho de Melo return 0; 1775055c67edSArnaldo Carvalho de Melo 1776055c67edSArnaldo Carvalho de Melo memset(&ev, 0, sizeof(ev)); 1777055c67edSArnaldo Carvalho de Melo 1778055c67edSArnaldo Carvalho de Melo len = pos->long_name_len + 1; 1779055c67edSArnaldo Carvalho de Melo len = PERF_ALIGN(len, NAME_ALIGN); 1780055c67edSArnaldo Carvalho de Melo memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id)); 1781055c67edSArnaldo Carvalho de Melo ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; 1782055c67edSArnaldo Carvalho de Melo ev.build_id.header.misc = misc; 1783055c67edSArnaldo Carvalho de Melo ev.build_id.pid = machine->pid; 1784055c67edSArnaldo Carvalho de Melo ev.build_id.header.size = sizeof(ev.build_id) + len; 1785055c67edSArnaldo Carvalho de Melo memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); 1786055c67edSArnaldo Carvalho de Melo 1787055c67edSArnaldo Carvalho de Melo return process(tool, &ev, NULL, machine); 1788055c67edSArnaldo Carvalho de Melo } 1789055c67edSArnaldo Carvalho de Melo 1790055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_stat_events(struct perf_stat_config *config, struct perf_tool *tool, 1791055c67edSArnaldo Carvalho de Melo struct evlist *evlist, perf_event__handler_t process, bool attrs) 1792055c67edSArnaldo Carvalho de Melo { 1793055c67edSArnaldo Carvalho de Melo int err; 1794055c67edSArnaldo Carvalho de Melo 1795055c67edSArnaldo Carvalho de Melo if (attrs) { 1796055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_attrs(tool, evlist, process); 1797055c67edSArnaldo Carvalho de Melo if (err < 0) { 1798055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize attrs.\n"); 1799055c67edSArnaldo Carvalho de Melo return err; 1800055c67edSArnaldo Carvalho de Melo } 1801055c67edSArnaldo Carvalho de Melo } 1802055c67edSArnaldo Carvalho de Melo 1803055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_extra_attr(tool, evlist, process, attrs); 1804055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_thread_map2(tool, evlist->core.threads, process, NULL); 1805055c67edSArnaldo Carvalho de Melo if (err < 0) { 1806055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize thread map.\n"); 1807055c67edSArnaldo Carvalho de Melo return err; 1808055c67edSArnaldo Carvalho de Melo } 1809055c67edSArnaldo Carvalho de Melo 1810055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_cpu_map(tool, evlist->core.cpus, process, NULL); 1811055c67edSArnaldo Carvalho de Melo if (err < 0) { 1812055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize thread map.\n"); 1813055c67edSArnaldo Carvalho de Melo return err; 1814055c67edSArnaldo Carvalho de Melo } 1815055c67edSArnaldo Carvalho de Melo 1816055c67edSArnaldo Carvalho de Melo err = perf_event__synthesize_stat_config(tool, config, process, NULL); 1817055c67edSArnaldo Carvalho de Melo if (err < 0) { 1818055c67edSArnaldo Carvalho de Melo pr_err("Couldn't synthesize config.\n"); 1819055c67edSArnaldo Carvalho de Melo return err; 1820055c67edSArnaldo Carvalho de Melo } 1821055c67edSArnaldo Carvalho de Melo 1822055c67edSArnaldo Carvalho de Melo return 0; 1823055c67edSArnaldo Carvalho de Melo } 1824055c67edSArnaldo Carvalho de Melo 1825055c67edSArnaldo Carvalho de Melo int __weak perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused, 1826055c67edSArnaldo Carvalho de Melo struct perf_tool *tool __maybe_unused, 1827055c67edSArnaldo Carvalho de Melo perf_event__handler_t process __maybe_unused, 1828055c67edSArnaldo Carvalho de Melo struct machine *machine __maybe_unused) 1829055c67edSArnaldo Carvalho de Melo { 1830055c67edSArnaldo Carvalho de Melo return 0; 1831055c67edSArnaldo Carvalho de Melo } 1832055c67edSArnaldo Carvalho de Melo 1833055c67edSArnaldo Carvalho de Melo extern const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE]; 1834055c67edSArnaldo Carvalho de Melo 1835055c67edSArnaldo Carvalho de Melo int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, 1836055c67edSArnaldo Carvalho de Melo struct evlist *evlist, perf_event__handler_t process) 1837055c67edSArnaldo Carvalho de Melo { 1838055c67edSArnaldo Carvalho de Melo struct perf_header *header = &session->header; 1839055c67edSArnaldo Carvalho de Melo struct perf_record_header_feature *fe; 1840055c67edSArnaldo Carvalho de Melo struct feat_fd ff; 1841055c67edSArnaldo Carvalho de Melo size_t sz, sz_hdr; 1842055c67edSArnaldo Carvalho de Melo int feat, ret; 1843055c67edSArnaldo Carvalho de Melo 1844055c67edSArnaldo Carvalho de Melo sz_hdr = sizeof(fe->header); 1845055c67edSArnaldo Carvalho de Melo sz = sizeof(union perf_event); 1846055c67edSArnaldo Carvalho de Melo /* get a nice alignment */ 1847055c67edSArnaldo Carvalho de Melo sz = PERF_ALIGN(sz, page_size); 1848055c67edSArnaldo Carvalho de Melo 1849055c67edSArnaldo Carvalho de Melo memset(&ff, 0, sizeof(ff)); 1850055c67edSArnaldo Carvalho de Melo 1851055c67edSArnaldo Carvalho de Melo ff.buf = malloc(sz); 1852055c67edSArnaldo Carvalho de Melo if (!ff.buf) 1853055c67edSArnaldo Carvalho de Melo return -ENOMEM; 1854055c67edSArnaldo Carvalho de Melo 1855055c67edSArnaldo Carvalho de Melo ff.size = sz - sz_hdr; 1856055c67edSArnaldo Carvalho de Melo ff.ph = &session->header; 1857055c67edSArnaldo Carvalho de Melo 1858055c67edSArnaldo Carvalho de Melo for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { 1859055c67edSArnaldo Carvalho de Melo if (!feat_ops[feat].synthesize) { 1860055c67edSArnaldo Carvalho de Melo pr_debug("No record header feature for header :%d\n", feat); 1861055c67edSArnaldo Carvalho de Melo continue; 1862055c67edSArnaldo Carvalho de Melo } 1863055c67edSArnaldo Carvalho de Melo 1864055c67edSArnaldo Carvalho de Melo ff.offset = sizeof(*fe); 1865055c67edSArnaldo Carvalho de Melo 1866055c67edSArnaldo Carvalho de Melo ret = feat_ops[feat].write(&ff, evlist); 1867055c67edSArnaldo Carvalho de Melo if (ret || ff.offset <= (ssize_t)sizeof(*fe)) { 1868055c67edSArnaldo Carvalho de Melo pr_debug("Error writing feature\n"); 1869055c67edSArnaldo Carvalho de Melo continue; 1870055c67edSArnaldo Carvalho de Melo } 1871055c67edSArnaldo Carvalho de Melo /* ff.buf may have changed due to realloc in do_write() */ 1872055c67edSArnaldo Carvalho de Melo fe = ff.buf; 1873055c67edSArnaldo Carvalho de Melo memset(fe, 0, sizeof(*fe)); 1874055c67edSArnaldo Carvalho de Melo 1875055c67edSArnaldo Carvalho de Melo fe->feat_id = feat; 1876055c67edSArnaldo Carvalho de Melo fe->header.type = PERF_RECORD_HEADER_FEATURE; 1877055c67edSArnaldo Carvalho de Melo fe->header.size = ff.offset; 1878055c67edSArnaldo Carvalho de Melo 1879055c67edSArnaldo Carvalho de Melo ret = process(tool, ff.buf, NULL, NULL); 1880055c67edSArnaldo Carvalho de Melo if (ret) { 1881055c67edSArnaldo Carvalho de Melo free(ff.buf); 1882055c67edSArnaldo Carvalho de Melo return ret; 1883055c67edSArnaldo Carvalho de Melo } 1884055c67edSArnaldo Carvalho de Melo } 1885055c67edSArnaldo Carvalho de Melo 1886055c67edSArnaldo Carvalho de Melo /* Send HEADER_LAST_FEATURE mark. */ 1887055c67edSArnaldo Carvalho de Melo fe = ff.buf; 1888055c67edSArnaldo Carvalho de Melo fe->feat_id = HEADER_LAST_FEATURE; 1889055c67edSArnaldo Carvalho de Melo fe->header.type = PERF_RECORD_HEADER_FEATURE; 1890055c67edSArnaldo Carvalho de Melo fe->header.size = sizeof(*fe); 1891055c67edSArnaldo Carvalho de Melo 1892055c67edSArnaldo Carvalho de Melo ret = process(tool, ff.buf, NULL, NULL); 1893055c67edSArnaldo Carvalho de Melo 1894055c67edSArnaldo Carvalho de Melo free(ff.buf); 1895055c67edSArnaldo Carvalho de Melo return ret; 1896055c67edSArnaldo Carvalho de Melo } 1897