summaryrefslogtreecommitdiff
path: root/tools/perf/util/header.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-09-04 08:39:02 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-09-04 08:39:02 -0700
commit9657752cb5039c7498d4b27c4a75530f93b87d9b (patch)
treeef4198ba427da0ef5e1cb8fb4ec62843b645aed9 /tools/perf/util/header.c
parent0081a0ce809b611c1f37da5d6ae5bc8027ffd1c4 (diff)
parent1b2f76d77a277bb70d38ad0991ed7f16bbc115a9 (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar: "Kernel side changes: - Add branch type profiling/tracing support. (Jin Yao) - Add the PERF_SAMPLE_PHYS_ADDR ABI to allow the tracing/profiling of physical memory addresses, where the PMU supports it. (Kan Liang) - Export some PMU capability details in the new /sys/bus/event_source/devices/cpu/caps/ sysfs directory. (Andi Kleen) - Aux data fixes and updates (Will Deacon) - kprobes fixes and updates (Masami Hiramatsu) - AMD uncore PMU driver fixes and updates (Janakarajan Natarajan) On the tooling side, here's a (limited!) list of highlights - there were many other changes that I could not list, see the shortlog and git history for details: UI improvements: - Implement a visual marker for fused x86 instructions in the annotate TUI browser, available now in 'perf report', more work needed to have it available as well in 'perf top' (Jin Yao) Further explanation from one of Jin's patches: │ ┌──cmpl $0x0,argp_program_version_hook 81.93 │ ├──je 20 │ │ lock cmpxchg %esi,0x38a9a4(%rip) │ │↓ jne 29 │ │↓ jmp 43 11.47 │20:└─→cmpxch %esi,0x38a999(%rip) That means the cmpl+je is a fused instruction pair and they should be considered together. - Record the branch type and then show statistics and info about in callchain entries (Jin Yao) Example from one of Jin's patches: # perf record -g -j any,save_type # perf report --branch-history --stdio --no-children 38.50% div.c:45 [.] main div | ---main div.c:42 (RET CROSS_2M cycles:2) compute_flag div.c:28 (cycles:2) compute_flag div.c:27 (RET CROSS_2M cycles:1) rand rand.c:28 (cycles:1) rand rand.c:28 (RET CROSS_2M cycles:1) __random random.c:298 (cycles:1) __random random.c:297 (COND_BWD CROSS_2M cycles:1) __random random.c:295 (cycles:1) __random random.c:295 (COND_BWD CROSS_2M cycles:1) __random random.c:295 (cycles:1) __random random.c:295 (RET CROSS_2M cycles:9) namespaces support: - Add initial support for namespaces, using setns to access files in namespaces, grabbing their build-ids, etc. (Krister Johansen) perf trace enhancements: - Beautify pkey_{alloc,free,mprotect} arguments in 'perf trace' (Arnaldo Carvalho de Melo) - Add initial 'clone' syscall args beautifier in 'perf trace' (Arnaldo Carvalho de Melo) - Ignore 'fd' and 'offset' args for MAP_ANONYMOUS in 'perf trace' (Arnaldo Carvalho de Melo) - Beautifiers for the 'cmd' arg of several ioctl types, including: sound, DRM, KVM, vhost virtio and perf_events. (Arnaldo Carvalho de Melo) - Add PERF_SAMPLE_CALLCHAIN and PERF_RECORD_MMAP[2] to 'perf data' CTF conversion, allowing CTF trace visualization tools to show callchains and to resolve symbols (Geneviève Bastien) - Beautify the fcntl syscall, which is an interesting one in the sense that infrastructure had to be put in place to change the formatters of some arguments according to the value in a previous one, i.e. cmd dictates how arg and the syscall return will be formatted. (Arnaldo Carvalho de Melo perf stat enhancements: - Use group read for event groups in 'perf stat', reducing overhead when groups are defined in the event specification, i.e. when using {} to enclose a list of events, asking them to be read at the same time, e.g.: "perf stat -e '{cycles,instructions}'" (Jiri Olsa) pipe mode improvements: - Process tracing data in 'perf annotate' pipe mode (David Carrillo-Cisneros) - Add header record types to pipe-mode, now this command: $ perf record -o - -e cycles sleep 1 | perf report --stdio --header Will show the same as in non-pipe mode, i.e. involving a perf.data file (David Carrillo-Cisneros) Vendor specific hardware event support updates/enhancements: - Update POWER9 vendor events tables (Sukadev Bhattiprolu) - Add POWER9 PMU events Sukadev (Bhattiprolu) - Support additional POWER8+ PVR in PMU mapfile (Shriya) - Add Skylake server uncore JSON vendor events (Andi Kleen) - Support exporting Intel PT data to sqlite3 with python perf scripts, this is in addition to the postgresql support that was already there (Adrian Hunter)" * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (253 commits) perf symbols: Fix plt entry calculation for ARM and AARCH64 perf probe: Fix kprobe blacklist checking condition perf/x86: Fix caps/ for !Intel perf/core, x86: Add PERF_SAMPLE_PHYS_ADDR perf/core, pt, bts: Get rid of itrace_started perf trace beauty: Beautify pkey_{alloc,free,mprotect} arguments tools headers: Sync cpu features kernel ABI headers with tooling headers perf tools: Pass full path of FEATURES_DUMP perf tools: Robustify detection of clang binary tools lib: Allow external definition of CC, AR and LD perf tools: Allow external definition of flex and bison binary names tools build tests: Don't hardcode gcc name perf report: Group stat values on global event id perf values: Zero value buffers perf values: Fix allocation check perf values: Fix thread index bug perf report: Add dump_read function perf record: Set read_format for inherit_stat perf c2c: Fix remote HITM detection for Skylake perf tools: Fix static build with newer toolchains ...
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r--tools/perf/util/header.c1018
1 files changed, 559 insertions, 459 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 76ed7d03e500..605bbd5404fb 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,25 +370,22 @@ 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
-#define CPUINFO_PROC {"model name", }
-#endif
const char *cpuinfo_procs[] = CPUINFO_PROC;
unsigned int i;
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 +393,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 +408,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 +427,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 +435,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 +451,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 +489,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 +651,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 +662,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 +686,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 +702,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 +723,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 +731,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 +761,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 +783,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 +791,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 +819,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 +852,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 +901,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 +919,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 +944,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 +956,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 +1123,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 +1136,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 +1148,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 +1159,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 +1175,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 +1271,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 +1307,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 +1335,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 +1355,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 +1390,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 +1415,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 +1482,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 +1661,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 +1752,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 +1796,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 +1805,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 +1815,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 +1849,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 +1872,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 +1904,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 +1922,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 +1941,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 +1950,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 +1984,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 +1997,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 +2009,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 +2023,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 +2081,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 +2117,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 +2126,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 +2139,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 +2148,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 +2216,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 +2230,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 +2277,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 +2312,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 +2338,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 +2347,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 +2357,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 +2384,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 +2410,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 +2445,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 +2699,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 +2720,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 +2745,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 +2995,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 +3350,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 +3385,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;
}