diff options
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 1015 |
1 files changed, 559 insertions, 456 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 76ed7d03e500..28bf4442d577 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -12,6 +12,7 @@ #include <linux/list.h> #include <linux/kernel.h> #include <linux/bitops.h> +#include <linux/stringify.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/utsname.h> @@ -34,6 +35,7 @@ #include "data.h" #include <api/fs/fs.h> #include "asm/bug.h" +#include "tool.h" #include "sane_ctype.h" @@ -59,6 +61,15 @@ struct perf_file_attr { struct perf_file_section ids; }; +struct feat_fd { + struct perf_header *ph; + int fd; + void *buf; /* Either buf != NULL or fd >= 0 */ + ssize_t offset; + size_t size; + struct perf_evsel *events; +}; + void perf_header__set_feat(struct perf_header *header, int feat) { set_bit(feat, header->adds_features); @@ -74,28 +85,60 @@ bool perf_header__has_feat(const struct perf_header *header, int feat) return test_bit(feat, header->adds_features); } -static int do_write(int fd, const void *buf, size_t size) +static int __do_write_fd(struct feat_fd *ff, const void *buf, size_t size) { - while (size) { - int ret = write(fd, buf, size); + ssize_t ret = writen(ff->fd, buf, size); - if (ret < 0) - return -errno; + if (ret != (ssize_t)size) + return ret < 0 ? (int)ret : -1; + return 0; +} + +static int __do_write_buf(struct feat_fd *ff, const void *buf, size_t size) +{ + /* struct perf_event_header::size is u16 */ + const size_t max_size = 0xffff - sizeof(struct perf_event_header); + size_t new_size = ff->size; + void *addr; - size -= ret; - buf += ret; + if (size + ff->offset > max_size) + return -E2BIG; + + while (size > (new_size - ff->offset)) + new_size <<= 1; + new_size = min(max_size, new_size); + + if (ff->size < new_size) { + addr = realloc(ff->buf, new_size); + if (!addr) + return -ENOMEM; + ff->buf = addr; + ff->size = new_size; } + memcpy(ff->buf + ff->offset, buf, size); + ff->offset += size; + return 0; } -int write_padded(int fd, const void *bf, size_t count, size_t count_aligned) +/* Return: 0 if succeded, -ERR if failed. */ +int do_write(struct feat_fd *ff, const void *buf, size_t size) +{ + if (!ff->buf) + return __do_write_fd(ff, buf, size); + return __do_write_buf(ff, buf, size); +} + +/* Return: 0 if succeded, -ERR if failed. */ +int write_padded(struct feat_fd *ff, const void *bf, + size_t count, size_t count_aligned) { static const char zero_buf[NAME_ALIGN]; - int err = do_write(fd, bf, count); + int err = do_write(ff, bf, count); if (!err) - err = do_write(fd, zero_buf, count_aligned - count); + err = do_write(ff, zero_buf, count_aligned - count); return err; } @@ -103,7 +146,8 @@ int write_padded(int fd, const void *bf, size_t count, size_t count_aligned) #define string_size(str) \ (PERF_ALIGN((strlen(str) + 1), NAME_ALIGN) + sizeof(u32)) -static int do_write_string(int fd, const char *str) +/* Return: 0 if succeded, -ERR if failed. */ +static int do_write_string(struct feat_fd *ff, const char *str) { u32 len, olen; int ret; @@ -112,32 +156,80 @@ static int do_write_string(int fd, const char *str) len = PERF_ALIGN(olen, NAME_ALIGN); /* write len, incl. \0 */ - ret = do_write(fd, &len, sizeof(len)); + ret = do_write(ff, &len, sizeof(len)); if (ret < 0) return ret; - return write_padded(fd, str, olen, len); + return write_padded(ff, str, olen, len); } -static char *do_read_string(int fd, struct perf_header *ph) +static int __do_read_fd(struct feat_fd *ff, void *addr, ssize_t size) +{ + ssize_t ret = readn(ff->fd, addr, size); + + if (ret != size) + return ret < 0 ? (int)ret : -1; + return 0; +} + +static int __do_read_buf(struct feat_fd *ff, void *addr, ssize_t size) +{ + if (size > (ssize_t)ff->size - ff->offset) + return -1; + + memcpy(addr, ff->buf + ff->offset, size); + ff->offset += size; + + return 0; + +} + +static int __do_read(struct feat_fd *ff, void *addr, ssize_t size) +{ + if (!ff->buf) + return __do_read_fd(ff, addr, size); + return __do_read_buf(ff, addr, size); +} + +static int do_read_u32(struct feat_fd *ff, u32 *addr) +{ + int ret; + + ret = __do_read(ff, addr, sizeof(*addr)); + if (ret) + return ret; + + if (ff->ph->needs_swap) + *addr = bswap_32(*addr); + return 0; +} + +static int do_read_u64(struct feat_fd *ff, u64 *addr) +{ + int ret; + + ret = __do_read(ff, addr, sizeof(*addr)); + if (ret) + return ret; + + if (ff->ph->needs_swap) + *addr = bswap_64(*addr); + return 0; +} + +static char *do_read_string(struct feat_fd *ff) { - ssize_t sz, ret; u32 len; char *buf; - sz = readn(fd, &len, sizeof(len)); - if (sz < (ssize_t)sizeof(len)) + if (do_read_u32(ff, &len)) return NULL; - if (ph->needs_swap) - len = bswap_32(len); - buf = malloc(len); if (!buf) return NULL; - ret = readn(fd, buf, len); - if (ret == (ssize_t)len) { + if (!__do_read(ff, buf, len)) { /* * strings are padded by zeroes * thus the actual strlen of buf @@ -150,25 +242,30 @@ static char *do_read_string(int fd, struct perf_header *ph) return NULL; } -static int write_tracing_data(int fd, struct perf_header *h __maybe_unused, - struct perf_evlist *evlist) +static int write_tracing_data(struct feat_fd *ff, + struct perf_evlist *evlist) { - return read_tracing_data(fd, &evlist->entries); -} + if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) + return -1; + return read_tracing_data(ff->fd, &evlist->entries); +} -static int write_build_id(int fd, struct perf_header *h, +static int write_build_id(struct feat_fd *ff, struct perf_evlist *evlist __maybe_unused) { struct perf_session *session; int err; - session = container_of(h, struct perf_session, header); + session = container_of(ff->ph, struct perf_session, header); if (!perf_session__read_build_ids(session, true)) return -1; - err = perf_session__write_buildid_table(session, fd); + if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) + return -1; + + err = perf_session__write_buildid_table(session, ff); if (err < 0) { pr_debug("failed to write buildid table\n"); return err; @@ -178,7 +275,7 @@ static int write_build_id(int fd, struct perf_header *h, return 0; } -static int write_hostname(int fd, struct perf_header *h __maybe_unused, +static int write_hostname(struct feat_fd *ff, struct perf_evlist *evlist __maybe_unused) { struct utsname uts; @@ -188,10 +285,10 @@ static int write_hostname(int fd, struct perf_header *h __maybe_unused, if (ret < 0) return -1; - return do_write_string(fd, uts.nodename); + return do_write_string(ff, uts.nodename); } -static int write_osrelease(int fd, struct perf_header *h __maybe_unused, +static int write_osrelease(struct feat_fd *ff, struct perf_evlist *evlist __maybe_unused) { struct utsname uts; @@ -201,10 +298,10 @@ static int write_osrelease(int fd, struct perf_header *h __maybe_unused, if (ret < 0) return -1; - return do_write_string(fd, uts.release); + return do_write_string(ff, uts.release); } -static int write_arch(int fd, struct perf_header *h __maybe_unused, +static int write_arch(struct feat_fd *ff, struct perf_evlist *evlist __maybe_unused) { struct utsname uts; @@ -214,16 +311,16 @@ static int write_arch(int fd, struct perf_header *h __maybe_unused, if (ret < 0) return -1; - return do_write_string(fd, uts.machine); + return do_write_string(ff, uts.machine); } -static int write_version(int fd, struct perf_header *h __maybe_unused, +static int write_version(struct feat_fd *ff, struct perf_evlist *evlist __maybe_unused) { - return do_write_string(fd, perf_version_string); + return do_write_string(ff, perf_version_string); } -static int __write_cpudesc(int fd, const char *cpuinfo_proc) +static int __write_cpudesc(struct feat_fd *ff, const char *cpuinfo_proc) { FILE *file; char *buf = NULL; @@ -273,14 +370,14 @@ static int __write_cpudesc(int fd, const char *cpuinfo_proc) } p++; } - ret = do_write_string(fd, s); + ret = do_write_string(ff, s); done: free(buf); fclose(file); return ret; } -static int write_cpudesc(int fd, struct perf_header *h __maybe_unused, +static int write_cpudesc(struct feat_fd *ff, struct perf_evlist *evlist __maybe_unused) { #ifndef CPUINFO_PROC @@ -291,7 +388,7 @@ static int write_cpudesc(int fd, struct perf_header *h __maybe_unused, for (i = 0; i < ARRAY_SIZE(cpuinfo_procs); i++) { int ret; - ret = __write_cpudesc(fd, cpuinfo_procs[i]); + ret = __write_cpudesc(ff, cpuinfo_procs[i]); if (ret >= 0) return ret; } @@ -299,7 +396,7 @@ static int write_cpudesc(int fd, struct perf_header *h __maybe_unused, } -static int write_nrcpus(int fd, struct perf_header *h __maybe_unused, +static int write_nrcpus(struct feat_fd *ff, struct perf_evlist *evlist __maybe_unused) { long nr; @@ -314,14 +411,14 @@ static int write_nrcpus(int fd, struct perf_header *h __maybe_unused, nra = (u32)(nr & UINT_MAX); - ret = do_write(fd, &nrc, sizeof(nrc)); + ret = do_write(ff, &nrc, sizeof(nrc)); if (ret < 0) return ret; - return do_write(fd, &nra, sizeof(nra)); + return do_write(ff, &nra, sizeof(nra)); } -static int write_event_desc(int fd, struct perf_header *h __maybe_unused, +static int write_event_desc(struct feat_fd *ff, struct perf_evlist *evlist) { struct perf_evsel *evsel; @@ -333,7 +430,7 @@ static int write_event_desc(int fd, struct perf_header *h __maybe_unused, /* * write number of events */ - ret = do_write(fd, &nre, sizeof(nre)); + ret = do_write(ff, &nre, sizeof(nre)); if (ret < 0) return ret; @@ -341,12 +438,12 @@ static int write_event_desc(int fd, struct perf_header *h __maybe_unused, * size of perf_event_attr struct */ sz = (u32)sizeof(evsel->attr); - ret = do_write(fd, &sz, sizeof(sz)); + ret = do_write(ff, &sz, sizeof(sz)); if (ret < 0) return ret; evlist__for_each_entry(evlist, evsel) { - ret = do_write(fd, &evsel->attr, sz); + ret = do_write(ff, &evsel->attr, sz); if (ret < 0) return ret; /* @@ -357,27 +454,27 @@ static int write_event_desc(int fd, struct perf_header *h __maybe_unused, * type of ids, */ nri = evsel->ids; - ret = do_write(fd, &nri, sizeof(nri)); + ret = do_write(ff, &nri, sizeof(nri)); if (ret < 0) return ret; /* * write event string as passed on cmdline */ - ret = do_write_string(fd, perf_evsel__name(evsel)); + ret = do_write_string(ff, perf_evsel__name(evsel)); if (ret < 0) return ret; /* * write unique ids for this event */ - ret = do_write(fd, evsel->id, evsel->ids * sizeof(u64)); + ret = do_write(ff, evsel->id, evsel->ids * sizeof(u64)); if (ret < 0) return ret; } return 0; } -static int write_cmdline(int fd, struct perf_header *h __maybe_unused, +static int write_cmdline(struct feat_fd *ff, struct perf_evlist *evlist __maybe_unused) { char buf[MAXPATHLEN]; @@ -395,16 +492,16 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused, /* account for binary path */ n = perf_env.nr_cmdline + 1; - ret = do_write(fd, &n, sizeof(n)); + ret = do_write(ff, &n, sizeof(n)); if (ret < 0) return ret; - ret = do_write_string(fd, buf); + ret = do_write_string(ff, buf); if (ret < 0) return ret; for (i = 0 ; i < perf_env.nr_cmdline; i++) { - ret = do_write_string(fd, perf_env.cmdline_argv[i]); + ret = do_write_string(ff, perf_env.cmdline_argv[i]); if (ret < 0) return ret; } @@ -557,8 +654,8 @@ out_free: return tp; } -static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused, - struct perf_evlist *evlist __maybe_unused) +static int write_cpu_topology(struct feat_fd *ff, + struct perf_evlist *evlist __maybe_unused) { struct cpu_topo *tp; u32 i; @@ -568,21 +665,21 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused, if (!tp) return -1; - ret = do_write(fd, &tp->core_sib, sizeof(tp->core_sib)); + ret = do_write(ff, &tp->core_sib, sizeof(tp->core_sib)); if (ret < 0) goto done; for (i = 0; i < tp->core_sib; i++) { - ret = do_write_string(fd, tp->core_siblings[i]); + ret = do_write_string(ff, tp->core_siblings[i]); if (ret < 0) goto done; } - ret = do_write(fd, &tp->thread_sib, sizeof(tp->thread_sib)); + ret = do_write(ff, &tp->thread_sib, sizeof(tp->thread_sib)); if (ret < 0) goto done; for (i = 0; i < tp->thread_sib; i++) { - ret = do_write_string(fd, tp->thread_siblings[i]); + ret = do_write_string(ff, tp->thread_siblings[i]); if (ret < 0) break; } @@ -592,11 +689,11 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused, goto done; for (j = 0; j < perf_env.nr_cpus_avail; j++) { - ret = do_write(fd, &perf_env.cpu[j].core_id, + ret = do_write(ff, &perf_env.cpu[j].core_id, sizeof(perf_env.cpu[j].core_id)); if (ret < 0) return ret; - ret = do_write(fd, &perf_env.cpu[j].socket_id, + ret = do_write(ff, &perf_env.cpu[j].socket_id, sizeof(perf_env.cpu[j].socket_id)); if (ret < 0) return ret; @@ -608,8 +705,8 @@ done: -static int write_total_mem(int fd, struct perf_header *h __maybe_unused, - struct perf_evlist *evlist __maybe_unused) +static int write_total_mem(struct feat_fd *ff, + struct perf_evlist *evlist __maybe_unused) { char *buf = NULL; FILE *fp; @@ -629,7 +726,7 @@ static int write_total_mem(int fd, struct perf_header *h __maybe_unused, if (!ret) { n = sscanf(buf, "%*s %"PRIu64, &mem); if (n == 1) - ret = do_write(fd, &mem, sizeof(mem)); + ret = do_write(ff, &mem, sizeof(mem)); } else ret = -1; free(buf); @@ -637,7 +734,7 @@ static int write_total_mem(int fd, struct perf_header *h __maybe_unused, return ret; } -static int write_topo_node(int fd, int node) +static int write_topo_node(struct feat_fd *ff, int node) { char str[MAXPATHLEN]; char field[32]; @@ -667,11 +764,11 @@ static int write_topo_node(int fd, int node) fclose(fp); fp = NULL; - ret = do_write(fd, &mem_total, sizeof(u64)); + ret = do_write(ff, &mem_total, sizeof(u64)); if (ret) goto done; - ret = do_write(fd, &mem_free, sizeof(u64)); + ret = do_write(ff, &mem_free, sizeof(u64)); if (ret) goto done; @@ -689,7 +786,7 @@ static int write_topo_node(int fd, int node) if (p) *p = '\0'; - ret = do_write_string(fd, buf); + ret = do_write_string(ff, buf); done: free(buf); if (fp) @@ -697,8 +794,8 @@ done: return ret; } -static int write_numa_topology(int fd, struct perf_header *h __maybe_unused, - struct perf_evlist *evlist __maybe_unused) +static int write_numa_topology(struct feat_fd *ff, + struct perf_evlist *evlist __maybe_unused) { char *buf = NULL; size_t len = 0; @@ -725,17 +822,17 @@ static int write_numa_topology(int fd, struct perf_header *h __maybe_unused, nr = (u32)node_map->nr; - ret = do_write(fd, &nr, sizeof(nr)); + ret = do_write(ff, &nr, sizeof(nr)); if (ret < 0) goto done; for (i = 0; i < nr; i++) { j = (u32)node_map->map[i]; - ret = do_write(fd, &j, sizeof(j)); + ret = do_write(ff, &j, sizeof(j)); if (ret < 0) break; - ret = write_topo_node(fd, i); + ret = write_topo_node(ff, i); if (ret < 0) break; } @@ -758,39 +855,40 @@ done: * }; */ -static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused, +static int write_pmu_mappings(struct feat_fd *ff, struct perf_evlist *evlist __maybe_unused) { struct perf_pmu *pmu = NULL; - off_t offset = lseek(fd, 0, SEEK_CUR); - __u32 pmu_num = 0; + u32 pmu_num = 0; int ret; - /* write real pmu_num later */ - ret = do_write(fd, &pmu_num, sizeof(pmu_num)); + /* + * Do a first pass to count number of pmu to avoid lseek so this + * works in pipe mode as well. + */ + while ((pmu = perf_pmu__scan(pmu))) { + if (!pmu->name) + continue; + pmu_num++; + } + + ret = do_write(ff, &pmu_num, sizeof(pmu_num)); if (ret < 0) return ret; while ((pmu = perf_pmu__scan(pmu))) { if (!pmu->name) continue; - pmu_num++; - ret = do_write(fd, &pmu->type, sizeof(pmu->type)); + ret = do_write(ff, &pmu->type, sizeof(pmu->type)); if (ret < 0) return ret; - ret = do_write_string(fd, pmu->name); + ret = do_write_string(ff, pmu->name); if (ret < 0) return ret; } - if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) { - /* discard all */ - lseek(fd, offset, SEEK_SET); - return -1; - } - return 0; } @@ -806,14 +904,14 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused, * }[nr_groups]; * }; */ -static int write_group_desc(int fd, struct perf_header *h __maybe_unused, +static int write_group_desc(struct feat_fd *ff, struct perf_evlist *evlist) { u32 nr_groups = evlist->nr_groups; struct perf_evsel *evsel; int ret; - ret = do_write(fd, &nr_groups, sizeof(nr_groups)); + ret = do_write(ff, &nr_groups, sizeof(nr_groups)); if (ret < 0) return ret; @@ -824,15 +922,15 @@ static int write_group_desc(int fd, struct perf_header *h __maybe_unused, u32 leader_idx = evsel->idx; u32 nr_members = evsel->nr_members; - ret = do_write_string(fd, name); + ret = do_write_string(ff, name); if (ret < 0) return ret; - ret = do_write(fd, &leader_idx, sizeof(leader_idx)); + ret = do_write(ff, &leader_idx, sizeof(leader_idx)); if (ret < 0) return ret; - ret = do_write(fd, &nr_members, sizeof(nr_members)); + ret = do_write(ff, &nr_members, sizeof(nr_members)); if (ret < 0) return ret; } @@ -849,7 +947,7 @@ int __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused) return -1; } -static int write_cpuid(int fd, struct perf_header *h __maybe_unused, +static int write_cpuid(struct feat_fd *ff, struct perf_evlist *evlist __maybe_unused) { char buffer[64]; @@ -861,25 +959,27 @@ static int write_cpuid(int fd, struct perf_header *h __maybe_unused, return -1; write_it: - return do_write_string(fd, buffer); + return do_write_string(ff, buffer); } -static int write_branch_stack(int fd __maybe_unused, - struct perf_header *h __maybe_unused, - struct perf_evlist *evlist __maybe_unused) +static int write_branch_stack(struct feat_fd *ff __maybe_unused, + struct perf_evlist *evlist __maybe_unused) { return 0; } -static int write_auxtrace(int fd, struct perf_header *h, +static int write_auxtrace(struct feat_fd *ff, struct perf_evlist *evlist __maybe_unused) { struct perf_session *session; int err; - session = container_of(h, struct perf_session, header); + if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) + return -1; + + session = container_of(ff->ph, struct perf_session, header); - err = auxtrace_index__write(fd, &session->auxtrace_index); + err = auxtrace_index__write(ff->fd, &session->auxtrace_index); if (err < 0) pr_err("Failed to write auxtrace index\n"); return err; @@ -1026,8 +1126,8 @@ static int build_caches(struct cpu_cache_level caches[], u32 size, u32 *cntp) #define MAX_CACHES 2000 -static int write_cache(int fd, struct perf_header *h __maybe_unused, - struct perf_evlist *evlist __maybe_unused) +static int write_cache(struct feat_fd *ff, + struct perf_evlist *evlist __maybe_unused) { struct cpu_cache_level caches[MAX_CACHES]; u32 cnt = 0, i, version = 1; @@ -1039,11 +1139,11 @@ static int write_cache(int fd, struct perf_header *h __maybe_unused, qsort(&caches, cnt, sizeof(struct cpu_cache_level), cpu_cache_level__sort); - ret = do_write(fd, &version, sizeof(u32)); + ret = do_write(ff, &version, sizeof(u32)); if (ret < 0) goto out; - ret = do_write(fd, &cnt, sizeof(u32)); + ret = do_write(ff, &cnt, sizeof(u32)); if (ret < 0) goto out; @@ -1051,7 +1151,7 @@ static int write_cache(int fd, struct perf_header *h __maybe_unused, struct cpu_cache_level *c = &caches[i]; #define _W(v) \ - ret = do_write(fd, &c->v, sizeof(u32)); \ + ret = do_write(ff, &c->v, sizeof(u32)); \ if (ret < 0) \ goto out; @@ -1062,7 +1162,7 @@ static int write_cache(int fd, struct perf_header *h __maybe_unused, #undef _W #define _W(v) \ - ret = do_write_string(fd, (const char *) c->v); \ + ret = do_write_string(ff, (const char *) c->v); \ if (ret < 0) \ goto out; @@ -1078,69 +1178,62 @@ out: return ret; } -static int write_stat(int fd __maybe_unused, - struct perf_header *h __maybe_unused, +static int write_stat(struct feat_fd *ff __maybe_unused, struct perf_evlist *evlist __maybe_unused) { return 0; } -static void print_hostname(struct perf_header *ph, int fd __maybe_unused, - FILE *fp) +static void print_hostname(struct feat_fd *ff, FILE *fp) { - fprintf(fp, "# hostname : %s\n", ph->env.hostname); + fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname); } -static void print_osrelease(struct perf_header *ph, int fd __maybe_unused, - FILE *fp) +static void print_osrelease(struct feat_fd *ff, FILE *fp) { - fprintf(fp, "# os release : %s\n", ph->env.os_release); + fprintf(fp, "# os release : %s\n", ff->ph->env.os_release); } -static void print_arch(struct perf_header *ph, int fd __maybe_unused, FILE *fp) +static void print_arch(struct feat_fd *ff, FILE *fp) { - fprintf(fp, "# arch : %s\n", ph->env.arch); + fprintf(fp, "# arch : %s\n", ff->ph->env.arch); } -static void print_cpudesc(struct perf_header *ph, int fd __maybe_unused, - FILE *fp) +static void print_cpudesc(struct feat_fd *ff, FILE *fp) { - fprintf(fp, "# cpudesc : %s\n", ph->env.cpu_desc); + fprintf(fp, "# cpudesc : %s\n", ff->ph->env.cpu_desc); } -static void print_nrcpus(struct perf_header *ph, int fd __maybe_unused, - FILE *fp) +static void print_nrcpus(struct feat_fd *ff, FILE *fp) { - fprintf(fp, "# nrcpus online : %u\n", ph->env.nr_cpus_online); - fprintf(fp, "# nrcpus avail : %u\n", ph->env.nr_cpus_avail); + fprintf(fp, "# nrcpus online : %u\n", ff->ph->env.nr_cpus_online); + fprintf(fp, "# nrcpus avail : %u\n", ff->ph->env.nr_cpus_avail); } -static void print_version(struct perf_header *ph, int fd __maybe_unused, - FILE *fp) +static void print_version(struct feat_fd *ff, FILE *fp) { - fprintf(fp, "# perf version : %s\n", ph->env.version); + fprintf(fp, "# perf version : %s\n", ff->ph->env.version); } -static void print_cmdline(struct perf_header *ph, int fd __maybe_unused, - FILE *fp) +static void print_cmdline(struct feat_fd *ff, FILE *fp) { int nr, i; - nr = ph->env.nr_cmdline; + nr = ff->ph->env.nr_cmdline; fprintf(fp, "# cmdline : "); for (i = 0; i < nr; i++) - fprintf(fp, "%s ", ph->env.cmdline_argv[i]); + fprintf(fp, "%s ", ff->ph->env.cmdline_argv[i]); fputc('\n', fp); } -static void print_cpu_topology(struct perf_header *ph, int fd __maybe_unused, - FILE *fp) +static void print_cpu_topology(struct feat_fd *ff, FILE *fp) { + struct perf_header *ph = ff->ph; + int cpu_nr = ph->env.nr_cpus_avail; int nr, i; char *str; - int cpu_nr = ph->env.nr_cpus_avail; nr = ph->env.nr_sibling_cores; str = ph->env.sibling_cores; @@ -1181,31 +1274,21 @@ static void free_event_desc(struct perf_evsel *events) free(events); } -static struct perf_evsel * -read_event_desc(struct perf_header *ph, int fd) +static struct perf_evsel *read_event_desc(struct feat_fd *ff) { struct perf_evsel *evsel, *events = NULL; u64 *id; void *buf = NULL; u32 nre, sz, nr, i, j; - ssize_t ret; size_t msz; /* number of events */ - ret = readn(fd, &nre, sizeof(nre)); - if (ret != (ssize_t)sizeof(nre)) + if (do_read_u32(ff, &nre)) goto error; - if (ph->needs_swap) - nre = bswap_32(nre); - - ret = readn(fd, &sz, sizeof(sz)); - if (ret != (ssize_t)sizeof(sz)) + if (do_read_u32(ff, &sz)) goto error; - if (ph->needs_swap) - sz = bswap_32(sz); - /* buffer to hold on file attr struct */ buf = malloc(sz); if (!buf) @@ -1227,25 +1310,23 @@ read_event_desc(struct perf_header *ph, int fd) * must read entire on-file attr struct to * sync up with layout. */ - ret = readn(fd, buf, sz); - if (ret != (ssize_t)sz) + if (__do_read(ff, buf, sz)) goto error; - if (ph->needs_swap) + if (ff->ph->needs_swap) perf_event__attr_swap(buf); memcpy(&evsel->attr, buf, msz); - ret = readn(fd, &nr, sizeof(nr)); - if (ret != (ssize_t)sizeof(nr)) + if (do_read_u32(ff, &nr)) goto error; - if (ph->needs_swap) { - nr = bswap_32(nr); + if (ff->ph->needs_swap) evsel->needs_swap = true; - } - evsel->name = do_read_string(fd, ph); + evsel->name = do_read_string(ff); + if (!evsel->name) + goto error; if (!nr) continue; @@ -1257,11 +1338,8 @@ read_event_desc(struct perf_header *ph, int fd) evsel->id = id; for (j = 0 ; j < nr; j++) { - ret = readn(fd, id, sizeof(*id)); - if (ret != (ssize_t)sizeof(*id)) + if (do_read_u64(ff, id)) goto error; - if (ph->needs_swap) - *id = bswap_64(*id); id++; } } @@ -1280,12 +1358,17 @@ static int __desc_attr__fprintf(FILE *fp, const char *name, const char *val, return fprintf(fp, ", %s = %s", name, val); } -static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) +static void print_event_desc(struct feat_fd *ff, FILE *fp) { - struct perf_evsel *evsel, *events = read_event_desc(ph, fd); + struct perf_evsel *evsel, *events; u32 j; u64 *id; + if (ff->events) + events = ff->events; + else + events = read_event_desc(ff); + if (!events) { fprintf(fp, "# event desc: not available or unable to read\n"); return; @@ -1310,22 +1393,21 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) } free_event_desc(events); + ff->events = NULL; } -static void print_total_mem(struct perf_header *ph, int fd __maybe_unused, - FILE *fp) +static void print_total_mem(struct feat_fd *ff, FILE *fp) { - fprintf(fp, "# total memory : %Lu kB\n", ph->env.total_mem); + fprintf(fp, "# total memory : %llu kB\n", ff->ph->env.total_mem); } -static void print_numa_topology(struct perf_header *ph, int fd __maybe_unused, - FILE *fp) +static void print_numa_topology(struct feat_fd *ff, FILE *fp) { int i; struct numa_node *n; - for (i = 0; i < ph->env.nr_numa_nodes; i++) { - n = &ph->env.numa_nodes[i]; + for (i = 0; i < ff->ph->env.nr_numa_nodes; i++) { + n = &ff->ph->env.numa_nodes[i]; fprintf(fp, "# node%u meminfo : total = %"PRIu64" kB," " free = %"PRIu64" kB\n", @@ -1336,56 +1418,51 @@ static void print_numa_topology(struct perf_header *ph, int fd __maybe_unused, } } -static void print_cpuid(struct perf_header *ph, int fd __maybe_unused, FILE *fp) +static void print_cpuid(struct feat_fd *ff, FILE *fp) { - fprintf(fp, "# cpuid : %s\n", ph->env.cpuid); + fprintf(fp, "# cpuid : %s\n", ff->ph->env.cpuid); } -static void print_branch_stack(struct perf_header *ph __maybe_unused, - int fd __maybe_unused, FILE *fp) +static void print_branch_stack(struct feat_fd *ff __maybe_unused, FILE *fp) { fprintf(fp, "# contains samples with branch stack\n"); } -static void print_auxtrace(struct perf_header *ph __maybe_unused, - int fd __maybe_unused, FILE *fp) +static void print_auxtrace(struct feat_fd *ff __maybe_unused, FILE *fp) { fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n"); } -static void print_stat(struct perf_header *ph __maybe_unused, - int fd __maybe_unused, FILE *fp) +static void print_stat(struct feat_fd *ff __maybe_unused, FILE *fp) { fprintf(fp, "# contains stat data\n"); } -static void print_cache(struct perf_header *ph __maybe_unused, - int fd __maybe_unused, FILE *fp __maybe_unused) +static void print_cache(struct feat_fd *ff, FILE *fp __maybe_unused) { int i; fprintf(fp, "# CPU cache info:\n"); - for (i = 0; i < ph->env.caches_cnt; i++) { + for (i = 0; i < ff->ph->env.caches_cnt; i++) { fprintf(fp, "# "); - cpu_cache_level__fprintf(fp, &ph->env.caches[i]); + cpu_cache_level__fprintf(fp, &ff->ph->env.caches[i]); } } -static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused, - FILE *fp) +static void print_pmu_mappings(struct feat_fd *ff, FILE *fp) { const char *delimiter = "# pmu mappings: "; char *str, *tmp; u32 pmu_num; u32 type; - pmu_num = ph->env.nr_pmu_mappings; + pmu_num = ff->ph->env.nr_pmu_mappings; if (!pmu_num) { fprintf(fp, "# pmu mappings: not available\n"); return; } - str = ph->env.pmu_mappings; + str = ff->ph->env.pmu_mappings; while (pmu_num) { type = strtoul(str, &tmp, 0); @@ -1408,14 +1485,13 @@ error: fprintf(fp, "# pmu mappings: unable to read\n"); } -static void print_group_desc(struct perf_header *ph, int fd __maybe_unused, - FILE *fp) +static void print_group_desc(struct feat_fd *ff, FILE *fp) { struct perf_session *session; struct perf_evsel *evsel; u32 nr = 0; - session = container_of(ph, struct perf_session, header); + session = container_of(ff->ph, struct perf_session, header); evlist__for_each_entry(session->evlist, evsel) { if (perf_evsel__is_group_leader(evsel) && @@ -1588,113 +1664,61 @@ out: return err; } -static int process_tracing_data(struct perf_file_section *section __maybe_unused, - struct perf_header *ph __maybe_unused, - int fd, void *data) -{ - ssize_t ret = trace_report(fd, data, false); - return ret < 0 ? -1 : 0; -} - -static int process_build_id(struct perf_file_section *section, - struct perf_header *ph, int fd, - void *data __maybe_unused) -{ - if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) - pr_debug("Failed to read buildids, continuing...\n"); - return 0; +/* Macro for features that simply need to read and store a string. */ +#define FEAT_PROCESS_STR_FUN(__feat, __feat_env) \ +static int process_##__feat(struct feat_fd *ff, void *data __maybe_unused) \ +{\ + ff->ph->env.__feat_env = do_read_string(ff); \ + return ff->ph->env.__feat_env ? 0 : -ENOMEM; \ } -static int process_hostname(struct perf_file_section *section __maybe_unused, - struct perf_header *ph, int fd, - void *data __maybe_unused) -{ - ph->env.hostname = do_read_string(fd, ph); - return ph->env.hostname ? 0 : -ENOMEM; -} +FEAT_PROCESS_STR_FUN(hostname, hostname); +FEAT_PROCESS_STR_FUN(osrelease, os_release); +FEAT_PROCESS_STR_FUN(version, version); +FEAT_PROCESS_STR_FUN(arch, arch); +FEAT_PROCESS_STR_FUN(cpudesc, cpu_desc); +FEAT_PROCESS_STR_FUN(cpuid, cpuid); -static int process_osrelease(struct perf_file_section *section __maybe_unused, - struct perf_header *ph, int fd, - void *data __maybe_unused) +static int process_tracing_data(struct feat_fd *ff, void *data) { - ph->env.os_release = do_read_string(fd, ph); - return ph->env.os_release ? 0 : -ENOMEM; -} + ssize_t ret = trace_report(ff->fd, data, false); -static int process_version(struct perf_file_section *section __maybe_unused, - struct perf_header *ph, int fd, - void *data __maybe_unused) -{ - ph->env.version = do_read_string(fd, ph); - return ph->env.version ? 0 : -ENOMEM; + return ret < 0 ? -1 : 0; } -static int process_arch(struct perf_file_section *section __maybe_unused, - struct perf_header *ph, int fd, - void *data __maybe_unused) +static int process_build_id(struct feat_fd *ff, void *data __maybe_unused) { - ph->env.arch = do_read_string(fd, ph); - return ph->env.arch ? 0 : -ENOMEM; + if (perf_header__read_build_ids(ff->ph, ff->fd, ff->offset, ff->size)) + pr_debug("Failed to read buildids, continuing...\n"); + return 0; } -static int process_nrcpus(struct perf_file_section *section __maybe_unused, - struct perf_header *ph, int fd, - void *data __maybe_unused) +static int process_nrcpus(struct feat_fd *ff, void *data __maybe_unused) { - ssize_t ret; - u32 nr; - - ret = readn(fd, &nr, sizeof(nr)); - if (ret != sizeof(nr)) - return -1; - - if (ph->needs_swap) - nr = bswap_32(nr); - - ph->env.nr_cpus_avail = nr; - - ret = readn(fd, &nr, sizeof(nr)); - if (ret != sizeof(nr)) - return -1; + int ret; + u32 nr_cpus_avail, nr_cpus_online; - if (ph->needs_swap) - nr = bswap_32(nr); + ret = do_read_u32(ff, &nr_cpus_avail); + if (ret) + return ret; - ph->env.nr_cpus_online = nr; + ret = do_read_u32(ff, &nr_cpus_online); + if (ret) + return ret; + ff->ph->env.nr_cpus_avail = (int)nr_cpus_avail; + ff->ph->env.nr_cpus_online = (int)nr_cpus_online; return 0; } -static int process_cpudesc(struct perf_file_section *section __maybe_unused, - struct perf_header *ph, int fd, - void *data __maybe_unused) -{ - ph->env.cpu_desc = do_read_string(fd, ph); - return ph->env.cpu_desc ? 0 : -ENOMEM; -} - -static int process_cpuid(struct perf_file_section *section __maybe_unused, - struct perf_header *ph, int fd, - void *data __maybe_unused) -{ - ph->env.cpuid = do_read_string(fd, ph); - return ph->env.cpuid ? 0 : -ENOMEM; -} - -static int process_total_mem(struct perf_file_section *section __maybe_unused, - struct perf_header *ph, int fd, - void *data __maybe_unused) +static int process_total_mem(struct feat_fd *ff, void *data __maybe_unused) { - uint64_t mem; - ssize_t ret; + u64 total_mem; + int ret; - ret = readn(fd, &mem, sizeof(mem)); - if (ret != sizeof(mem)) + ret = do_read_u64(ff, &total_mem); + if (ret) return -1; - - if (ph->needs_swap) - mem = bswap_64(mem); - - ph->env.total_mem = mem; + ff->ph->env.total_mem = (unsigned long long)total_mem; return 0; } @@ -1731,43 +1755,42 @@ perf_evlist__set_event_name(struct perf_evlist *evlist, } static int -process_event_desc(struct perf_file_section *section __maybe_unused, - struct perf_header *header, int fd, - void *data __maybe_unused) +process_event_desc(struct feat_fd *ff, void *data __maybe_unused) { struct perf_session *session; - struct perf_evsel *evsel, *events = read_event_desc(header, fd); + struct perf_evsel *evsel, *events = read_event_desc(ff); if (!events) return 0; - session = container_of(header, struct perf_session, header); + session = container_of(ff->ph, struct perf_session, header); + + if (session->file->is_pipe) { + /* Save events for reading later by print_event_desc, + * since they can't be read again in pipe mode. */ + ff->events = events; + } + for (evsel = events; evsel->attr.size; evsel++) perf_evlist__set_event_name(session->evlist, evsel); - free_event_desc(events); + if (!session->file->is_pipe) + free_event_desc(events); return 0; } -static int process_cmdline(struct perf_file_section *section, - struct perf_header *ph, int fd, - void *data __maybe_unused) +static int process_cmdline(struct feat_fd *ff, void *data __maybe_unused) { - ssize_t ret; char *str, *cmdline = NULL, **argv = NULL; u32 nr, i, len = 0; - ret = readn(fd, &nr, sizeof(nr)); - if (ret != sizeof(nr)) + if (do_read_u32(ff, &nr)) return -1; - if (ph->needs_swap) - nr = bswap_32(nr); - - ph->env.nr_cmdline = nr; + ff->ph->env.nr_cmdline = nr; - cmdline = zalloc(section->size + nr + 1); + cmdline = zalloc(ff->size + nr + 1); if (!cmdline) return -1; @@ -1776,7 +1799,7 @@ static int process_cmdline(struct perf_file_section *section, goto error; for (i = 0; i < nr; i++) { - str = do_read_string(fd, ph); + str = do_read_string(ff); if (!str) goto error; @@ -1785,8 +1808,8 @@ static int process_cmdline(struct perf_file_section *section, len += strlen(str) + 1; free(str); } - ph->env.cmdline = cmdline; - ph->env.cmdline_argv = (const char **) argv; + ff->ph->env.cmdline = cmdline; + ff->ph->env.cmdline_argv = (const char **) argv; return 0; error: @@ -1795,35 +1818,29 @@ error: return -1; } -static int process_cpu_topology(struct perf_file_section *section, - struct perf_header *ph, int fd, - void *data __maybe_unused) +static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) { - ssize_t ret; u32 nr, i; char *str; struct strbuf sb; - int cpu_nr = ph->env.nr_cpus_avail; + int cpu_nr = ff->ph->env.nr_cpus_avail; u64 size = 0; + struct perf_header *ph = ff->ph; ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu)); if (!ph->env.cpu) return -1; - ret = readn(fd, &nr, sizeof(nr)); - if (ret != sizeof(nr)) + if (do_read_u32(ff, &nr)) goto free_cpu; - if (ph->needs_swap) - nr = bswap_32(nr); - ph->env.nr_sibling_cores = nr; size += sizeof(u32); if (strbuf_init(&sb, 128) < 0) goto free_cpu; for (i = 0; i < nr; i++) { - str = do_read_string(fd, ph); + str = do_read_string(ff); if (!str) goto error; @@ -1835,18 +1852,14 @@ static int process_cpu_topology(struct perf_file_section *section, } ph->env.sibling_cores = strbuf_detach(&sb, NULL); - ret = readn(fd, &nr, sizeof(nr)); - if (ret != sizeof(nr)) + if (do_read_u32(ff, &nr)) return -1; - if (ph->needs_swap) - nr = bswap_32(nr); - ph->env.nr_sibling_threads = nr; size += sizeof(u32); for (i = 0; i < nr; i++) { - str = do_read_string(fd, ph); + str = do_read_string(ff); if (!str) goto error; @@ -1862,28 +1875,20 @@ static int process_cpu_topology(struct perf_file_section *section, * The header may be from old perf, * which doesn't include core id and socket id information. */ - if (section->size <= size) { + if (ff->size <= size) { zfree(&ph->env.cpu); return 0; } for (i = 0; i < (u32)cpu_nr; i++) { - ret = readn(fd, &nr, sizeof(nr)); - if (ret != sizeof(nr)) + if (do_read_u32(ff, &nr)) goto free_cpu; - if (ph->needs_swap) - nr = bswap_32(nr); - ph->env.cpu[i].core_id = nr; - ret = readn(fd, &nr, sizeof(nr)); - if (ret != sizeof(nr)) + if (do_read_u32(ff, &nr)) goto free_cpu; - if (ph->needs_swap) - nr = bswap_32(nr); - if (nr != (u32)-1 && nr > (u32)cpu_nr) { pr_debug("socket_id number is too big." "You may need to upgrade the perf tool.\n"); @@ -1902,23 +1907,16 @@ free_cpu: return -1; } -static int process_numa_topology(struct perf_file_section *section __maybe_unused, - struct perf_header *ph, int fd, - void *data __maybe_unused) +static int process_numa_topology(struct feat_fd *ff, void *data __maybe_unused) { struct numa_node *nodes, *n; - ssize_t ret; u32 nr, i; char *str; /* nr nodes */ - ret = readn(fd, &nr, sizeof(nr)); - if (ret != sizeof(nr)) + if (do_read_u32(ff, &nr)) return -1; - if (ph->needs_swap) - nr = bswap_32(nr); - nodes = zalloc(sizeof(*nodes) * nr); if (!nodes) return -ENOMEM; @@ -1927,25 +1925,16 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse n = &nodes[i]; /* node number */ - ret = readn(fd, &n->node, sizeof(u32)); - if (ret != sizeof(n->node)) + if (do_read_u32(ff, &n->node)) goto error; - ret = readn(fd, &n->mem_total, sizeof(u64)); - if (ret != sizeof(u64)) + if (do_read_u64(ff, &n->mem_total)) goto error; - ret = readn(fd, &n->mem_free, sizeof(u64)); - if (ret != sizeof(u64)) + if (do_read_u64(ff, &n->mem_free)) goto error; - if (ph->needs_swap) { - n->node = bswap_32(n->node); - n->mem_total = bswap_64(n->mem_total); - n->mem_free = bswap_64(n->mem_free); - } - - str = do_read_string(fd, ph); + str = do_read_string(ff); if (!str) goto error; @@ -1955,8 +1944,8 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse free(str); } - ph->env.nr_numa_nodes = nr; - ph->env.numa_nodes = nodes; + ff->ph->env.nr_numa_nodes = nr; + ff->ph->env.numa_nodes = nodes; return 0; error: @@ -1964,39 +1953,30 @@ error: return -1; } -static int process_pmu_mappings(struct perf_file_section *section __maybe_unused, - struct perf_header *ph, int fd, - void *data __maybe_unused) +static int process_pmu_mappings(struct feat_fd *ff, void *data __maybe_unused) { - ssize_t ret; char *name; u32 pmu_num; u32 type; struct strbuf sb; - ret = readn(fd, &pmu_num, sizeof(pmu_num)); - if (ret != sizeof(pmu_num)) + if (do_read_u32(ff, &pmu_num)) return -1; - if (ph->needs_swap) - pmu_num = bswap_32(pmu_num); - if (!pmu_num) { pr_debug("pmu mappings not available\n"); return 0; } - ph->env.nr_pmu_mappings = pmu_num; + ff->ph->env.nr_pmu_mappings = pmu_num; if (strbuf_init(&sb, 128) < 0) return -1; while (pmu_num) { - if (readn(fd, &type, sizeof(type)) != sizeof(type)) + if (do_read_u32(ff, &type)) goto error; - if (ph->needs_swap) - type = bswap_32(type); - name = do_read_string(fd, ph); + name = do_read_string(ff); if (!name) goto error; @@ -2007,12 +1987,12 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused goto error; if (!strcmp(name, "msr")) - ph->env.msr_pmu_type = type; + ff->ph->env.msr_pmu_type = type; free(name); pmu_num--; } - ph->env.pmu_mappings = strbuf_detach(&sb, NULL); + ff->ph->env.pmu_mappings = strbuf_detach(&sb, NULL); return 0; error: @@ -2020,9 +2000,7 @@ error: return -1; } -static int process_group_desc(struct perf_file_section *section __maybe_unused, - struct perf_header *ph, int fd, - void *data __maybe_unused) +static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused) { size_t ret = -1; u32 i, nr, nr_groups; @@ -2034,13 +2012,10 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused, u32 nr_members; } *desc; - if (readn(fd, &nr_groups, sizeof(nr_groups)) != sizeof(nr_groups)) + if (do_read_u32(ff, &nr_groups)) return -1; - if (ph->needs_swap) - nr_groups = bswap_32(nr_groups); - - ph->env.nr_groups = nr_groups; + ff->ph->env.nr_groups = nr_groups; if (!nr_groups) { pr_debug("group desc not available\n"); return 0; @@ -2051,26 +2026,21 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused, return -1; for (i = 0; i < nr_groups; i++) { - desc[i].name = do_read_string(fd, ph); + desc[i].name = do_read_string(ff); if (!desc[i].name) goto out_free; - if (readn(fd, &desc[i].leader_idx, sizeof(u32)) != sizeof(u32)) + if (do_read_u32(ff, &desc[i].leader_idx)) goto out_free; - if (readn(fd, &desc[i].nr_members, sizeof(u32)) != sizeof(u32)) + if (do_read_u32(ff, &desc[i].nr_members)) goto out_free; - - if (ph->needs_swap) { - desc[i].leader_idx = bswap_32(desc[i].leader_idx); - desc[i].nr_members = bswap_32(desc[i].nr_members); - } } /* * Rebuild group relationship based on the group_desc */ - session = container_of(ph, struct perf_session, header); + session = container_of(ff->ph, struct perf_session, header); session->evlist->nr_groups = nr_groups; i = nr = 0; @@ -2114,44 +2084,34 @@ out_free: return ret; } -static int process_auxtrace(struct perf_file_section *section, - struct perf_header *ph, int fd, - void *data __maybe_unused) +static int process_auxtrace(struct feat_fd *ff, void *data __maybe_unused) { struct perf_session *session; int err; - session = container_of(ph, struct perf_session, header); + session = container_of(ff->ph, struct perf_session, header); - err = auxtrace_index__process(fd, section->size, session, - ph->needs_swap); + err = auxtrace_index__process(ff->fd, ff->size, session, + ff->ph->needs_swap); if (err < 0) pr_err("Failed to process auxtrace index\n"); return err; } -static int process_cache(struct perf_file_section *section __maybe_unused, - struct perf_header *ph __maybe_unused, int fd __maybe_unused, - void *data __maybe_unused) +static int process_cache(struct feat_fd *ff, void *data __maybe_unused) { struct cpu_cache_level *caches; u32 cnt, i, version; - if (readn(fd, &version, sizeof(version)) != sizeof(version)) + if (do_read_u32(ff, &version)) return -1; - if (ph->needs_swap) - version = bswap_32(version); - if (version != 1) return -1; - if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt)) + if (do_read_u32(ff, &cnt)) return -1; - if (ph->needs_swap) - cnt = bswap_32(cnt); - caches = zalloc(sizeof(*caches) * cnt); if (!caches) return -1; @@ -2160,10 +2120,8 @@ static int process_cache(struct perf_file_section *section __maybe_unused, struct cpu_cache_level c; #define _R(v) \ - if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\ + if (do_read_u32(ff, &c.v))\ goto out_free_caches; \ - if (ph->needs_swap) \ - c.v = bswap_32(c.v); \ _R(level) _R(line_size) @@ -2171,9 +2129,9 @@ static int process_cache(struct perf_file_section *section __maybe_unused, _R(ways) #undef _R - #define _R(v) \ - c.v = do_read_string(fd, ph); \ - if (!c.v) \ + #define _R(v) \ + c.v = do_read_string(ff); \ + if (!c.v) \ goto out_free_caches; _R(type) @@ -2184,8 +2142,8 @@ static int process_cache(struct perf_file_section *section __maybe_unused, caches[i] = c; } - ph->env.caches = caches; - ph->env.caches_cnt = cnt; + ff->ph->env.caches = caches; + ff->ph->env.caches_cnt = cnt; return 0; out_free_caches: free(caches); @@ -2193,48 +2151,62 @@ out_free_caches: } struct feature_ops { - int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); - void (*print)(struct perf_header *h, int fd, FILE *fp); - int (*process)(struct perf_file_section *section, - struct perf_header *h, int fd, void *data); + int (*write)(struct feat_fd *ff, struct perf_evlist *evlist); + void (*print)(struct feat_fd *ff, FILE *fp); + int (*process)(struct feat_fd *ff, void *data); const char *name; bool full_only; + bool synthesize; }; -#define FEAT_OPA(n, func) \ - [n] = { .name = #n, .write = write_##func, .print = print_##func } -#define FEAT_OPP(n, func) \ - [n] = { .name = #n, .write = write_##func, .print = print_##func, \ - .process = process_##func } -#define FEAT_OPF(n, func) \ - [n] = { .name = #n, .write = write_##func, .print = print_##func, \ - .process = process_##func, .full_only = true } +#define FEAT_OPR(n, func, __full_only) \ + [HEADER_##n] = { \ + .name = __stringify(n), \ + .write = write_##func, \ + .print = print_##func, \ + .full_only = __full_only, \ + .process = process_##func, \ + .synthesize = true \ + } + +#define FEAT_OPN(n, func, __full_only) \ + [HEADER_##n] = { \ + .name = __stringify(n), \ + .write = write_##func, \ + .print = print_##func, \ + .full_only = __full_only, \ + .process = process_##func \ + } /* feature_ops not implemented: */ #define print_tracing_data NULL #define print_build_id NULL +#define process_branch_stack NULL +#define process_stat NULL + + static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { - FEAT_OPP(HEADER_TRACING_DATA, tracing_data), - FEAT_OPP(HEADER_BUILD_ID, build_id), - FEAT_OPP(HEADER_HOSTNAME, hostname), - FEAT_OPP(HEADER_OSRELEASE, osrelease), - FEAT_OPP(HEADER_VERSION, version), - FEAT_OPP(HEADER_ARCH, arch), - FEAT_OPP(HEADER_NRCPUS, nrcpus), - FEAT_OPP(HEADER_CPUDESC, cpudesc), - FEAT_OPP(HEADER_CPUID, cpuid), - FEAT_OPP(HEADER_TOTAL_MEM, total_mem), - FEAT_OPP(HEADER_EVENT_DESC, event_desc), - FEAT_OPP(HEADER_CMDLINE, cmdline), - FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology), - FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), - FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), - FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), - FEAT_OPP(HEADER_GROUP_DESC, group_desc), - FEAT_OPP(HEADER_AUXTRACE, auxtrace), - FEAT_OPA(HEADER_STAT, stat), - FEAT_OPF(HEADER_CACHE, cache), + FEAT_OPN(TRACING_DATA, tracing_data, false), + FEAT_OPN(BUILD_ID, build_id, false), + FEAT_OPR(HOSTNAME, hostname, false), + FEAT_OPR(OSRELEASE, osrelease, false), + FEAT_OPR(VERSION, version, false), + FEAT_OPR(ARCH, arch, false), + FEAT_OPR(NRCPUS, nrcpus, false), + FEAT_OPR(CPUDESC, cpudesc, false), + FEAT_OPR(CPUID, cpuid, false), + FEAT_OPR(TOTAL_MEM, total_mem, false), + FEAT_OPR(EVENT_DESC, event_desc, false), + FEAT_OPR(CMDLINE, cmdline, false), + FEAT_OPR(CPU_TOPOLOGY, cpu_topology, true), + FEAT_OPR(NUMA_TOPOLOGY, numa_topology, true), + FEAT_OPN(BRANCH_STACK, branch_stack, false), + FEAT_OPR(PMU_MAPPINGS, pmu_mappings, false), + FEAT_OPN(GROUP_DESC, group_desc, false), + FEAT_OPN(AUXTRACE, auxtrace, false), + FEAT_OPN(STAT, stat, false), + FEAT_OPN(CACHE, cache, true), }; struct header_print_data { @@ -2247,6 +2219,7 @@ static int perf_file_section__fprintf_info(struct perf_file_section *section, int feat, int fd, void *data) { struct header_print_data *hd = data; + struct feat_fd ff; if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { pr_debug("Failed to lseek to %" PRIu64 " offset for feature " @@ -2260,8 +2233,13 @@ static int perf_file_section__fprintf_info(struct perf_file_section *section, if (!feat_ops[feat].print) return 0; + ff = (struct feat_fd) { + .fd = fd, + .ph = ph, + }; + if (!feat_ops[feat].full_only || hd->full) - feat_ops[feat].print(ph, fd, hd->fp); + feat_ops[feat].print(&ff, hd->fp); else fprintf(hd->fp, "# %s info available, use -I to display\n", feat_ops[feat].name); @@ -2302,29 +2280,32 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) return 0; } -static int do_write_feat(int fd, struct perf_header *h, int type, +static int do_write_feat(struct feat_fd *ff, int type, struct perf_file_section **p, struct perf_evlist *evlist) { int err; int ret = 0; - if (perf_header__has_feat(h, type)) { + if (perf_header__has_feat(ff->ph, type)) { if (!feat_ops[type].write) return -1; - (*p)->offset = lseek(fd, 0, SEEK_CUR); + if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) + return -1; - err = feat_ops[type].write(fd, h, evlist); + (*p)->offset = lseek(ff->fd, 0, SEEK_CUR); + + err = feat_ops[type].write(ff, evlist); if (err < 0) { pr_debug("failed to write feature %s\n", feat_ops[type].name); /* undo anything written */ - lseek(fd, (*p)->offset, SEEK_SET); + lseek(ff->fd, (*p)->offset, SEEK_SET); return -1; } - (*p)->size = lseek(fd, 0, SEEK_CUR) - (*p)->offset; + (*p)->size = lseek(ff->fd, 0, SEEK_CUR) - (*p)->offset; (*p)++; } return ret; @@ -2334,12 +2315,18 @@ static int perf_header__adds_write(struct perf_header *header, struct perf_evlist *evlist, int fd) { int nr_sections; + struct feat_fd ff; struct perf_file_section *feat_sec, *p; int sec_size; u64 sec_start; int feat; int err; + ff = (struct feat_fd){ + .fd = fd, + .ph = header, + }; + nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); if (!nr_sections) return 0; @@ -2354,7 +2341,7 @@ static int perf_header__adds_write(struct perf_header *header, lseek(fd, sec_start + sec_size, SEEK_SET); for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { - if (do_write_feat(fd, header, feat, &p, evlist)) + if (do_write_feat(&ff, feat, &p, evlist)) perf_header__clear_feat(header, feat); } @@ -2363,7 +2350,7 @@ static int perf_header__adds_write(struct perf_header *header, * may write more than needed due to dropped feature, but * this is okay, reader will skip the mising entries */ - err = do_write(fd, feat_sec, sec_size); + err = do_write(&ff, feat_sec, sec_size); if (err < 0) pr_debug("failed to write feature section\n"); free(feat_sec); @@ -2373,14 +2360,17 @@ static int perf_header__adds_write(struct perf_header *header, int perf_header__write_pipe(int fd) { struct perf_pipe_file_header f_header; + struct feat_fd ff; int err; + ff = (struct feat_fd){ .fd = fd }; + f_header = (struct perf_pipe_file_header){ .magic = PERF_MAGIC, .size = sizeof(f_header), }; - err = do_write(fd, &f_header, sizeof(f_header)); + err = do_write(&ff, &f_header, sizeof(f_header)); if (err < 0) { pr_debug("failed to write perf pipe header\n"); return err; @@ -2397,21 +2387,23 @@ int perf_session__write_header(struct perf_session *session, struct perf_file_attr f_attr; struct perf_header *header = &session->header; struct perf_evsel *evsel; + struct feat_fd ff; u64 attr_offset; int err; + ff = (struct feat_fd){ .fd = fd}; lseek(fd, sizeof(f_header), SEEK_SET); evlist__for_each_entry(session->evlist, evsel) { evsel->id_offset = lseek(fd, 0, SEEK_CUR); - err = do_write(fd, evsel->id, evsel->ids * sizeof(u64)); + err = do_write(&ff, evsel->id, evsel->ids * sizeof(u64)); if (err < 0) { pr_debug("failed to write perf header\n"); return err; } } - attr_offset = lseek(fd, 0, SEEK_CUR); + attr_offset = lseek(ff.fd, 0, SEEK_CUR); evlist__for_each_entry(evlist, evsel) { f_attr = (struct perf_file_attr){ @@ -2421,7 +2413,7 @@ int perf_session__write_header(struct perf_session *session, .size = evsel->ids * sizeof(u64), } }; - err = do_write(fd, &f_attr, sizeof(f_attr)); + err = do_write(&ff, &f_attr, sizeof(f_attr)); if (err < 0) { pr_debug("failed to write perf header attribute\n"); return err; @@ -2456,7 +2448,7 @@ int perf_session__write_header(struct perf_session *session, memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features)); lseek(fd, 0, SEEK_SET); - err = do_write(fd, &f_header, sizeof(f_header)); + err = do_write(&ff, &f_header, sizeof(f_header)); if (err < 0) { pr_debug("failed to write perf header\n"); return err; @@ -2710,6 +2702,13 @@ static int perf_file_section__process(struct perf_file_section *section, struct perf_header *ph, int feat, int fd, void *data) { + struct feat_fd fdd = { + .fd = fd, + .ph = ph, + .size = section->size, + .offset = section->offset, + }; + if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { pr_debug("Failed to lseek to %" PRIu64 " offset for feature " "%d, continuing...\n", section->offset, feat); @@ -2724,13 +2723,17 @@ static int perf_file_section__process(struct perf_file_section *section, if (!feat_ops[feat].process) return 0; - return feat_ops[feat].process(section, ph, fd, data); + return feat_ops[feat].process(&fdd, data); } static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, struct perf_header *ph, int fd, bool repipe) { + struct feat_fd ff = { + .fd = STDOUT_FILENO, + .ph = ph, + }; ssize_t ret; ret = readn(fd, header, sizeof(*header)); @@ -2745,7 +2748,7 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, if (ph->needs_swap) header->size = bswap_64(header->size); - if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0) + if (repipe && do_write(&ff, header, sizeof(*header)) < 0) return -1; return 0; @@ -2995,6 +2998,103 @@ int perf_event__synthesize_attr(struct perf_tool *tool, return err; } +int perf_event__synthesize_features(struct perf_tool *tool, + struct perf_session *session, + struct perf_evlist *evlist, + perf_event__handler_t process) +{ + struct perf_header *header = &session->header; + struct feat_fd ff; + struct feature_event *fe; + size_t sz, sz_hdr; + int feat, ret; + + sz_hdr = sizeof(fe->header); + sz = sizeof(union perf_event); + /* get a nice alignment */ + sz = PERF_ALIGN(sz, page_size); + + memset(&ff, 0, sizeof(ff)); + + ff.buf = malloc(sz); + if (!ff.buf) + return -ENOMEM; + + ff.size = sz - sz_hdr; + + for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { + if (!feat_ops[feat].synthesize) { + pr_debug("No record header feature for header :%d\n", feat); + continue; + } + + ff.offset = sizeof(*fe); + + ret = feat_ops[feat].write(&ff, evlist); + if (ret || ff.offset <= (ssize_t)sizeof(*fe)) { + pr_debug("Error writing feature\n"); + continue; + } + /* ff.buf may have changed due to realloc in do_write() */ + fe = ff.buf; + memset(fe, 0, sizeof(*fe)); + + fe->feat_id = feat; + fe->header.type = PERF_RECORD_HEADER_FEATURE; + fe->header.size = ff.offset; + + ret = process(tool, ff.buf, NULL, NULL); + if (ret) { + free(ff.buf); + return ret; + } + } + free(ff.buf); + return 0; +} + +int perf_event__process_feature(struct perf_tool *tool, + union perf_event *event, + struct perf_session *session __maybe_unused) +{ + struct feat_fd ff = { .fd = 0 }; + struct feature_event *fe = (struct feature_event *)event; + int type = fe->header.type; + u64 feat = fe->feat_id; + + if (type < 0 || type >= PERF_RECORD_HEADER_MAX) { + pr_warning("invalid record type %d in pipe-mode\n", type); + return 0; + } + if (feat == HEADER_RESERVED || feat > HEADER_LAST_FEATURE) { + pr_warning("invalid record type %d in pipe-mode\n", type); + return -1; + } + + if (!feat_ops[feat].process) + return 0; + + ff.buf = (void *)fe->data; + ff.size = event->header.size - sizeof(event->header); + ff.ph = &session->header; + + if (feat_ops[feat].process(&ff, NULL)) + return -1; + + if (!feat_ops[feat].print || !tool->show_feat_hdr) + return 0; + + if (!feat_ops[feat].full_only || + tool->show_feat_hdr >= SHOW_FEAT_HEADER_FULL_INFO) { + feat_ops[feat].print(&ff, stdout); + } else { + fprintf(stdout, "# %s info available, use -I to display\n", + feat_ops[feat].name); + } + + return 0; +} + static struct event_update_event * event_update_event__new(size_t size, u64 type, u64 id) { @@ -3253,6 +3353,7 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, union perf_event ev; struct tracing_data *tdata; ssize_t size = 0, aligned_size = 0, padding; + struct feat_fd ff; int err __maybe_unused = 0; /* @@ -3287,7 +3388,9 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, */ tracing_data_put(tdata); - write_padded(fd, NULL, 0, padding); + ff = (struct feat_fd){ .fd = fd }; + if (write_padded(&ff, NULL, 0, padding)) + return -1; return aligned_size; } |