Merge tag 'driver-core-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / tools / perf / util / synthetic-events.c
index d9c6243..b698046 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/perf_event.h>
 #include <asm/bug.h>
 #include <perf/evsel.h>
-#include <internal/cpumap.h>
 #include <perf/cpumap.h>
 #include <internal/lib.h> // page_size
 #include <internal/threadmap.h>
@@ -69,19 +68,22 @@ int perf_tool__process_synth_event(struct perf_tool *tool,
  * Assumes that the first 4095 bytes of /proc/pid/stat contains
  * the comm, tgid and ppid.
  */
-static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len,
-                                   pid_t *tgid, pid_t *ppid)
+static int perf_event__get_comm_ids(pid_t pid, pid_t tid, char *comm, size_t len,
+                                   pid_t *tgid, pid_t *ppid, bool *kernel)
 {
        char bf[4096];
        int fd;
        size_t size = 0;
        ssize_t n;
-       char *name, *tgids, *ppids;
+       char *name, *tgids, *ppids, *vmpeak, *threads;
 
        *tgid = -1;
        *ppid = -1;
 
-       snprintf(bf, sizeof(bf), "/proc/%d/status", pid);
+       if (pid)
+               snprintf(bf, sizeof(bf), "/proc/%d/task/%d/status", pid, tid);
+       else
+               snprintf(bf, sizeof(bf), "/proc/%d/status", tid);
 
        fd = open(bf, O_RDONLY);
        if (fd < 0) {
@@ -93,14 +95,20 @@ static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len,
        close(fd);
        if (n <= 0) {
                pr_warning("Couldn't get COMM, tigd and ppid for pid %d\n",
-                          pid);
+                          tid);
                return -1;
        }
        bf[n] = '\0';
 
        name = strstr(bf, "Name:");
-       tgids = strstr(bf, "Tgid:");
-       ppids = strstr(bf, "PPid:");
+       tgids = strstr(name ?: bf, "Tgid:");
+       ppids = strstr(tgids ?: bf, "PPid:");
+       vmpeak = strstr(ppids ?: bf, "VmPeak:");
+
+       if (vmpeak)
+               threads = NULL;
+       else
+               threads = strstr(ppids ?: bf, "Threads:");
 
        if (name) {
                char *nl;
@@ -116,29 +124,34 @@ static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len,
                memcpy(comm, name, size);
                comm[size] = '\0';
        } else {
-               pr_debug("Name: string not found for pid %d\n", pid);
+               pr_debug("Name: string not found for pid %d\n", tid);
        }
 
        if (tgids) {
                tgids += 5;  /* strlen("Tgid:") */
                *tgid = atoi(tgids);
        } else {
-               pr_debug("Tgid: string not found for pid %d\n", pid);
+               pr_debug("Tgid: string not found for pid %d\n", tid);
        }
 
        if (ppids) {
                ppids += 5;  /* strlen("PPid:") */
                *ppid = atoi(ppids);
        } else {
-               pr_debug("PPid: string not found for pid %d\n", pid);
+               pr_debug("PPid: string not found for pid %d\n", tid);
        }
 
+       if (!vmpeak && threads)
+               *kernel = true;
+       else
+               *kernel = false;
+
        return 0;
 }
 
-static int perf_event__prepare_comm(union perf_event *event, pid_t pid,
+static int perf_event__prepare_comm(union perf_event *event, pid_t pid, pid_t tid,
                                    struct machine *machine,
-                                   pid_t *tgid, pid_t *ppid)
+                                   pid_t *tgid, pid_t *ppid, bool *kernel)
 {
        size_t size;
 
@@ -147,9 +160,9 @@ static int perf_event__prepare_comm(union perf_event *event, pid_t pid,
        memset(&event->comm, 0, sizeof(event->comm));
 
        if (machine__is_host(machine)) {
-               if (perf_event__get_comm_ids(pid, event->comm.comm,
+               if (perf_event__get_comm_ids(pid, tid, event->comm.comm,
                                             sizeof(event->comm.comm),
-                                            tgid, ppid) != 0) {
+                                            tgid, ppid, kernel) != 0) {
                        return -1;
                }
        } else {
@@ -168,7 +181,7 @@ static int perf_event__prepare_comm(union perf_event *event, pid_t pid,
        event->comm.header.size = (sizeof(event->comm) -
                                (sizeof(event->comm.comm) - size) +
                                machine->id_hdr_size);
-       event->comm.tid = pid;
+       event->comm.tid = tid;
 
        return 0;
 }
@@ -179,8 +192,10 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
                                         struct machine *machine)
 {
        pid_t tgid, ppid;
+       bool kernel_thread;
 
-       if (perf_event__prepare_comm(event, pid, machine, &tgid, &ppid) != 0)
+       if (perf_event__prepare_comm(event, 0, pid, machine, &tgid, &ppid,
+                                    &kernel_thread) != 0)
                return -1;
 
        if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
@@ -347,6 +362,31 @@ static bool read_proc_maps_line(struct io *io, __u64 *start, __u64 *end,
        }
 }
 
+static void perf_record_mmap2__read_build_id(struct perf_record_mmap2 *event,
+                                            bool is_kernel)
+{
+       struct build_id bid;
+       int rc;
+
+       if (is_kernel)
+               rc = sysfs__read_build_id("/sys/kernel/notes", &bid);
+       else
+               rc = filename__read_build_id(event->filename, &bid) > 0 ? 0 : -1;
+
+       if (rc == 0) {
+               memcpy(event->build_id, bid.data, sizeof(bid.data));
+               event->build_id_size = (u8) bid.size;
+               event->header.misc |= PERF_RECORD_MISC_MMAP_BUILD_ID;
+               event->__reserved_1 = 0;
+               event->__reserved_2 = 0;
+       } else {
+               if (event->filename[0] == '/') {
+                       pr_debug2("Failed to read build ID for %s\n",
+                                 event->filename);
+               }
+       }
+}
+
 int perf_event__synthesize_mmap_events(struct perf_tool *tool,
                                       union perf_event *event,
                                       pid_t pid, pid_t tgid,
@@ -453,6 +493,9 @@ out:
                event->mmap2.pid = tgid;
                event->mmap2.tid = pid;
 
+               if (symbol_conf.buildid_mmap2)
+                       perf_record_mmap2__read_build_id(&event->mmap2, false);
+
                if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {
                        rc = -1;
                        break;
@@ -596,16 +639,17 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t
        int rc = 0;
        struct map *pos;
        struct maps *maps = machine__kernel_maps(machine);
-       union perf_event *event = zalloc((sizeof(event->mmap) +
-                                         machine->id_hdr_size));
+       union perf_event *event;
+       size_t size = symbol_conf.buildid_mmap2 ?
+                       sizeof(event->mmap2) : sizeof(event->mmap);
+
+       event = zalloc(size + machine->id_hdr_size);
        if (event == NULL) {
                pr_debug("Not enough memory synthesizing mmap event "
                         "for kernel modules\n");
                return -1;
        }
 
-       event->header.type = PERF_RECORD_MMAP;
-
        /*
         * kernel uses 0 for user space maps, see kernel/perf_event.c
         * __perf_event_mmap
@@ -616,23 +660,39 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t
                event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
 
        maps__for_each_entry(maps, pos) {
-               size_t size;
-
                if (!__map__is_kmodule(pos))
                        continue;
 
-               size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
-               event->mmap.header.type = PERF_RECORD_MMAP;
-               event->mmap.header.size = (sizeof(event->mmap) -
-                                       (sizeof(event->mmap.filename) - size));
-               memset(event->mmap.filename + size, 0, machine->id_hdr_size);
-               event->mmap.header.size += machine->id_hdr_size;
-               event->mmap.start = pos->start;
-               event->mmap.len   = pos->end - pos->start;
-               event->mmap.pid   = machine->pid;
+               if (symbol_conf.buildid_mmap2) {
+                       size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
+                       event->mmap2.header.type = PERF_RECORD_MMAP2;
+                       event->mmap2.header.size = (sizeof(event->mmap2) -
+                                               (sizeof(event->mmap2.filename) - size));
+                       memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
+                       event->mmap2.header.size += machine->id_hdr_size;
+                       event->mmap2.start = pos->start;
+                       event->mmap2.len   = pos->end - pos->start;
+                       event->mmap2.pid   = machine->pid;
+
+                       memcpy(event->mmap2.filename, pos->dso->long_name,
+                              pos->dso->long_name_len + 1);
+
+                       perf_record_mmap2__read_build_id(&event->mmap2, false);
+               } else {
+                       size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
+                       event->mmap.header.type = PERF_RECORD_MMAP;
+                       event->mmap.header.size = (sizeof(event->mmap) -
+                                               (sizeof(event->mmap.filename) - size));
+                       memset(event->mmap.filename + size, 0, machine->id_hdr_size);
+                       event->mmap.header.size += machine->id_hdr_size;
+                       event->mmap.start = pos->start;
+                       event->mmap.len   = pos->end - pos->start;
+                       event->mmap.pid   = machine->pid;
+
+                       memcpy(event->mmap.filename, pos->dso->long_name,
+                              pos->dso->long_name_len + 1);
+               }
 
-               memcpy(event->mmap.filename, pos->dso->long_name,
-                      pos->dso->long_name_len + 1);
                if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {
                        rc = -1;
                        break;
@@ -643,6 +703,11 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t
        return rc;
 }
 
+static int filter_task(const struct dirent *dirent)
+{
+       return isdigit(dirent->d_name[0]);
+}
+
 static int __event__synthesize_thread(union perf_event *comm_event,
                                      union perf_event *mmap_event,
                                      union perf_event *fork_event,
@@ -651,10 +716,10 @@ static int __event__synthesize_thread(union perf_event *comm_event,
                                      struct perf_tool *tool, struct machine *machine, bool mmap_data)
 {
        char filename[PATH_MAX];
-       DIR *tasks;
-       struct dirent *dirent;
+       struct dirent **dirent;
        pid_t tgid, ppid;
        int rc = 0;
+       int i, n;
 
        /* special case: only send one comm event using passed in pid */
        if (!full) {
@@ -686,23 +751,22 @@ static int __event__synthesize_thread(union perf_event *comm_event,
        snprintf(filename, sizeof(filename), "%s/proc/%d/task",
                 machine->root_dir, pid);
 
-       tasks = opendir(filename);
-       if (tasks == NULL) {
-               pr_debug("couldn't open %s\n", filename);
-               return 0;
-       }
+       n = scandir(filename, &dirent, filter_task, alphasort);
+       if (n < 0)
+               return n;
 
-       while ((dirent = readdir(tasks)) != NULL) {
+       for (i = 0; i < n; i++) {
                char *end;
                pid_t _pid;
+               bool kernel_thread;
 
-               _pid = strtol(dirent->d_name, &end, 10);
+               _pid = strtol(dirent[i]->d_name, &end, 10);
                if (*end)
                        continue;
 
                rc = -1;
-               if (perf_event__prepare_comm(comm_event, _pid, machine,
-                                            &tgid, &ppid) != 0)
+               if (perf_event__prepare_comm(comm_event, pid, _pid, machine,
+                                            &tgid, &ppid, &kernel_thread) != 0)
                        break;
 
                if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
@@ -720,7 +784,7 @@ static int __event__synthesize_thread(union perf_event *comm_event,
                        break;
 
                rc = 0;
-               if (_pid == pid) {
+               if (_pid == pid && !kernel_thread) {
                        /* process the parent's maps too */
                        rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
                                                process, machine, mmap_data);
@@ -729,7 +793,10 @@ static int __event__synthesize_thread(union perf_event *comm_event,
                }
        }
 
-       closedir(tasks);
+       for (i = 0; i < n; i++)
+               zfree(&dirent[i]);
+       free(dirent);
+
        return rc;
 }
 
@@ -914,7 +981,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
                return 0;
 
        snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
-       n = scandir(proc_path, &dirent, 0, alphasort);
+       n = scandir(proc_path, &dirent, filter_task, alphasort);
        if (n < 0)
                return err;
 
@@ -991,11 +1058,12 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
                                                perf_event__handler_t process,
                                                struct machine *machine)
 {
-       size_t size;
+       union perf_event *event;
+       size_t size = symbol_conf.buildid_mmap2 ?
+                       sizeof(event->mmap2) : sizeof(event->mmap);
        struct map *map = machine__kernel_map(machine);
        struct kmap *kmap;
        int err;
-       union perf_event *event;
 
        if (map == NULL)
                return -1;
@@ -1009,7 +1077,7 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
         * available use this, and after it is use this as a fallback for older
         * kernels.
         */
-       event = zalloc((sizeof(event->mmap) + machine->id_hdr_size));
+       event = zalloc(size + machine->id_hdr_size);
        if (event == NULL) {
                pr_debug("Not enough memory synthesizing mmap event "
                         "for kernel modules\n");
@@ -1026,16 +1094,31 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
                event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
        }
 
-       size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
-                       "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;
-       size = PERF_ALIGN(size, sizeof(u64));
-       event->mmap.header.type = PERF_RECORD_MMAP;
-       event->mmap.header.size = (sizeof(event->mmap) -
-                       (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
-       event->mmap.pgoff = kmap->ref_reloc_sym->addr;
-       event->mmap.start = map->start;
-       event->mmap.len   = map->end - event->mmap.start;
-       event->mmap.pid   = machine->pid;
+       if (symbol_conf.buildid_mmap2) {
+               size = snprintf(event->mmap2.filename, sizeof(event->mmap2.filename),
+                               "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;
+               size = PERF_ALIGN(size, sizeof(u64));
+               event->mmap2.header.type = PERF_RECORD_MMAP2;
+               event->mmap2.header.size = (sizeof(event->mmap2) -
+                               (sizeof(event->mmap2.filename) - size) + machine->id_hdr_size);
+               event->mmap2.pgoff = kmap->ref_reloc_sym->addr;
+               event->mmap2.start = map->start;
+               event->mmap2.len   = map->end - event->mmap.start;
+               event->mmap2.pid   = machine->pid;
+
+               perf_record_mmap2__read_build_id(&event->mmap2, true);
+       } else {
+               size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
+                               "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;
+               size = PERF_ALIGN(size, sizeof(u64));
+               event->mmap.header.type = PERF_RECORD_MMAP;
+               event->mmap.header.size = (sizeof(event->mmap) -
+                               (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
+               event->mmap.pgoff = kmap->ref_reloc_sym->addr;
+               event->mmap.start = map->start;
+               event->mmap.len   = map->end - event->mmap.start;
+               event->mmap.pid   = machine->pid;
+       }
 
        err = perf_tool__process_synth_event(tool, event, machine, process);
        free(event);
@@ -1384,7 +1467,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
                }
        }
 
-       if (type & PERF_SAMPLE_WEIGHT)
+       if (type & PERF_SAMPLE_WEIGHT_TYPE)
                result += sizeof(u64);
 
        if (type & PERF_SAMPLE_DATA_SRC)
@@ -1409,6 +1492,12 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
        if (type & PERF_SAMPLE_CGROUP)
                result += sizeof(u64);
 
+       if (type & PERF_SAMPLE_DATA_PAGE_SIZE)
+               result += sizeof(u64);
+
+       if (type & PERF_SAMPLE_CODE_PAGE_SIZE)
+               result += sizeof(u64);
+
        if (type & PERF_SAMPLE_AUX) {
                result += sizeof(u64);
                result += sample->aux_sample.size;
@@ -1417,6 +1506,12 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
        return result;
 }
 
+void __weak arch_perf_synthesize_sample_weight(const struct perf_sample *data,
+                                              __u64 *array, u64 type __maybe_unused)
+{
+       *array = data->weight;
+}
+
 int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format,
                                  const struct perf_sample *sample)
 {
@@ -1552,8 +1647,8 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_fo
                }
        }
 
-       if (type & PERF_SAMPLE_WEIGHT) {
-               *array = sample->weight;
+       if (type & PERF_SAMPLE_WEIGHT_TYPE) {
+               arch_perf_synthesize_sample_weight(sample, array, type);
                array++;
        }
 
@@ -1588,6 +1683,16 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_fo
                array++;
        }
 
+       if (type & PERF_SAMPLE_DATA_PAGE_SIZE) {
+               *array = sample->data_page_size;
+               array++;
+       }
+
+       if (type & PERF_SAMPLE_CODE_PAGE_SIZE) {
+               *array = sample->code_page_size;
+               array++;
+       }
+
        if (type & PERF_SAMPLE_AUX) {
                sz = sample->aux_sample.size;
                *array++ = sz;
@@ -1643,7 +1748,7 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_
 
                        e->id = evsel->core.id[j];
 
-                       sid = perf_evlist__id2sid(evlist, e->id);
+                       sid = evlist__id2sid(evlist, e->id);
                        if (!sid) {
                                free(ev);
                                return -ENOENT;