aboutsummaryrefslogtreecommitdiff
path: root/tools/perf/util/header.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r--tools/perf/util/header.c1015
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;
}