|
@@ -20,6 +20,7 @@
|
|
|
#include "symbol.h"
|
|
|
#include "debug.h"
|
|
|
#include "cpumap.h"
|
|
|
+#include "pmu.h"
|
|
|
|
|
|
static bool no_buildid_cache = false;
|
|
|
|
|
@@ -1003,6 +1004,45 @@ done:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * File format:
|
|
|
+ *
|
|
|
+ * struct pmu_mappings {
|
|
|
+ * u32 pmu_num;
|
|
|
+ * struct pmu_map {
|
|
|
+ * u32 type;
|
|
|
+ * char name[];
|
|
|
+ * }[pmu_num];
|
|
|
+ * };
|
|
|
+ */
|
|
|
+
|
|
|
+static int write_pmu_mappings(int fd, struct perf_header *h __used,
|
|
|
+ struct perf_evlist *evlist __used)
|
|
|
+{
|
|
|
+ struct perf_pmu *pmu = NULL;
|
|
|
+ off_t offset = lseek(fd, 0, SEEK_CUR);
|
|
|
+ __u32 pmu_num = 0;
|
|
|
+
|
|
|
+ /* write real pmu_num later */
|
|
|
+ do_write(fd, &pmu_num, sizeof(pmu_num));
|
|
|
+
|
|
|
+ while ((pmu = perf_pmu__scan(pmu))) {
|
|
|
+ if (!pmu->name)
|
|
|
+ continue;
|
|
|
+ pmu_num++;
|
|
|
+ do_write(fd, &pmu->type, sizeof(pmu->type));
|
|
|
+ do_write_string(fd, pmu->name);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) {
|
|
|
+ /* discard all */
|
|
|
+ lseek(fd, offset, SEEK_SET);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* default get_cpuid(): nothing gets recorded
|
|
|
* actual implementation must be in arch/$(ARCH)/util/header.c
|
|
@@ -1389,6 +1429,43 @@ static void print_branch_stack(struct perf_header *ph __used, int fd __used,
|
|
|
fprintf(fp, "# contains samples with branch stack\n");
|
|
|
}
|
|
|
|
|
|
+static void print_pmu_mappings(struct perf_header *ph, int fd, FILE *fp)
|
|
|
+{
|
|
|
+ const char *delimiter = "# pmu mappings: ";
|
|
|
+ char *name;
|
|
|
+ int ret;
|
|
|
+ u32 pmu_num;
|
|
|
+ u32 type;
|
|
|
+
|
|
|
+ ret = read(fd, &pmu_num, sizeof(pmu_num));
|
|
|
+ if (ret != sizeof(pmu_num))
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ if (!pmu_num) {
|
|
|
+ fprintf(fp, "# pmu mappings: not available\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (pmu_num) {
|
|
|
+ if (read(fd, &type, sizeof(type)) != sizeof(type))
|
|
|
+ break;
|
|
|
+ name = do_read_string(fd, ph);
|
|
|
+ if (!name)
|
|
|
+ break;
|
|
|
+ pmu_num--;
|
|
|
+ fprintf(fp, "%s%s = %" PRIu32, delimiter, name, type);
|
|
|
+ free(name);
|
|
|
+ delimiter = ", ";
|
|
|
+ }
|
|
|
+
|
|
|
+ fprintf(fp, "\n");
|
|
|
+
|
|
|
+ if (!pmu_num)
|
|
|
+ return;
|
|
|
+error:
|
|
|
+ fprintf(fp, "# pmu mappings: unable to read\n");
|
|
|
+}
|
|
|
+
|
|
|
static int __event_process_build_id(struct build_id_event *bev,
|
|
|
char *filename,
|
|
|
struct perf_session *session)
|
|
@@ -1644,6 +1721,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
|
|
|
FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology),
|
|
|
FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
|
|
|
FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
|
|
|
+ FEAT_OPA(HEADER_PMU_MAPPINGS, pmu_mappings),
|
|
|
};
|
|
|
|
|
|
struct header_print_data {
|