summaryrefslogtreecommitdiffstats
path: root/kernel/tools/perf/util/header.c
diff options
context:
space:
mode:
authorJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-11 10:41:07 +0300
committerJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-13 08:17:18 +0300
commite09b41010ba33a20a87472ee821fa407a5b8da36 (patch)
treed10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/tools/perf/util/header.c
parentf93b97fd65072de626c074dbe099a1fff05ce060 (diff)
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page. During the rebasing, the following patch collided: Force tick interrupt and get rid of softirq magic(I70131fb85). Collisions have been removed because its logic was found on the source already. Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769 Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/tools/perf/util/header.c')
-rw-r--r--kernel/tools/perf/util/header.c231
1 files changed, 160 insertions, 71 deletions
diff --git a/kernel/tools/perf/util/header.c b/kernel/tools/perf/util/header.c
index 918fd8ae2..43838003c 100644
--- a/kernel/tools/perf/util/header.c
+++ b/kernel/tools/perf/util/header.c
@@ -24,9 +24,6 @@
#include "build-id.h"
#include "data.h"
-static u32 header_argc;
-static const char **header_argv;
-
/*
* magic2 = "PERFILE2"
* must be a numerical value to let the endianness
@@ -88,6 +85,9 @@ int write_padded(int fd, const void *bf, size_t count, size_t count_aligned)
return err;
}
+#define string_size(str) \
+ (PERF_ALIGN((strlen(str) + 1), NAME_ALIGN) + sizeof(u32))
+
static int do_write_string(int fd, const char *str)
{
u32 len, olen;
@@ -135,37 +135,6 @@ static char *do_read_string(int fd, struct perf_header *ph)
return NULL;
}
-int
-perf_header__set_cmdline(int argc, const char **argv)
-{
- int i;
-
- /*
- * If header_argv has already been set, do not override it.
- * This allows a command to set the cmdline, parse args and
- * then call another builtin function that implements a
- * command -- e.g, cmd_kvm calling cmd_record.
- */
- if (header_argv)
- return 0;
-
- header_argc = (u32)argc;
-
- /* do not include NULL termination */
- header_argv = calloc(argc, sizeof(char *));
- if (!header_argv)
- return -ENOMEM;
-
- /*
- * must copy argv contents because it gets moved
- * around during option parsing
- */
- for (i = 0; i < argc ; i++)
- header_argv[i] = argv[i];
-
- return 0;
-}
-
static int write_tracing_data(int fd, struct perf_header *h __maybe_unused,
struct perf_evlist *evlist)
{
@@ -402,8 +371,8 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
{
char buf[MAXPATHLEN];
char proc[32];
- u32 i, n;
- int ret;
+ u32 n;
+ int i, ret;
/*
* actual atual path to perf binary
@@ -417,7 +386,7 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
buf[ret] = '\0';
/* account for binary path */
- n = header_argc + 1;
+ n = perf_env.nr_cmdline + 1;
ret = do_write(fd, &n, sizeof(n));
if (ret < 0)
@@ -427,8 +396,8 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
if (ret < 0)
return ret;
- for (i = 0 ; i < header_argc; i++) {
- ret = do_write_string(fd, header_argv[i]);
+ for (i = 0 ; i < perf_env.nr_cmdline; i++) {
+ ret = do_write_string(fd, perf_env.cmdline_argv[i]);
if (ret < 0)
return ret;
}
@@ -441,6 +410,7 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
"/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list"
struct cpu_topo {
+ u32 cpu_nr;
u32 core_sib;
u32 thread_sib;
char **core_siblings;
@@ -551,7 +521,7 @@ static struct cpu_topo *build_cpu_topology(void)
return NULL;
tp = addr;
-
+ tp->cpu_nr = nr;
addr += sizeof(*tp);
tp->core_siblings = addr;
addr += sz;
@@ -574,7 +544,7 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused,
{
struct cpu_topo *tp;
u32 i;
- int ret;
+ int ret, j;
tp = build_cpu_topology();
if (!tp)
@@ -598,6 +568,21 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused,
if (ret < 0)
break;
}
+
+ ret = perf_env__read_cpu_topology_map(&perf_env);
+ if (ret < 0)
+ goto done;
+
+ for (j = 0; j < perf_env.nr_cpus_avail; j++) {
+ ret = do_write(fd, &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,
+ sizeof(perf_env.cpu[j].socket_id));
+ if (ret < 0)
+ return ret;
+ }
done:
free_cpu_topo(tp);
return ret;
@@ -869,6 +854,20 @@ static int write_branch_stack(int fd __maybe_unused,
return 0;
}
+static int write_auxtrace(int fd, struct perf_header *h,
+ struct perf_evlist *evlist __maybe_unused)
+{
+ struct perf_session *session;
+ int err;
+
+ session = container_of(h, struct perf_session, header);
+
+ err = auxtrace_index__write(fd, &session->auxtrace_index);
+ if (err < 0)
+ pr_err("Failed to write auxtrace index\n");
+ return err;
+}
+
static void print_hostname(struct perf_header *ph, int fd __maybe_unused,
FILE *fp)
{
@@ -909,17 +908,13 @@ static void print_cmdline(struct perf_header *ph, int fd __maybe_unused,
FILE *fp)
{
int nr, i;
- char *str;
nr = ph->env.nr_cmdline;
- str = ph->env.cmdline;
fprintf(fp, "# cmdline : ");
- for (i = 0; i < nr; i++) {
- fprintf(fp, "%s ", str);
- str += strlen(str) + 1;
- }
+ for (i = 0; i < nr; i++)
+ fprintf(fp, "%s ", ph->env.cmdline_argv[i]);
fputc('\n', fp);
}
@@ -928,6 +923,7 @@ static void print_cpu_topology(struct perf_header *ph, int fd __maybe_unused,
{
int nr, i;
char *str;
+ int cpu_nr = ph->env.nr_cpus_online;
nr = ph->env.nr_sibling_cores;
str = ph->env.sibling_cores;
@@ -944,6 +940,13 @@ static void print_cpu_topology(struct perf_header *ph, int fd __maybe_unused,
fprintf(fp, "# sibling threads : %s\n", str);
str += strlen(str) + 1;
}
+
+ if (ph->env.cpu != NULL) {
+ for (i = 0; i < cpu_nr; i++)
+ fprintf(fp, "# CPU %d: Core ID %d, Socket ID %d\n", i,
+ ph->env.cpu[i].core_id, ph->env.cpu[i].socket_id);
+ } else
+ fprintf(fp, "# Core ID and Socket ID information is not available\n");
}
static void free_event_desc(struct perf_evsel *events)
@@ -1049,8 +1052,7 @@ out:
free(buf);
return events;
error:
- if (events)
- free_event_desc(events);
+ free_event_desc(events);
events = NULL;
goto out;
}
@@ -1151,6 +1153,12 @@ static void print_branch_stack(struct perf_header *ph __maybe_unused,
fprintf(fp, "# contains samples with branch stack\n");
}
+static void print_auxtrace(struct perf_header *ph __maybe_unused,
+ int fd __maybe_unused, FILE *fp)
+{
+ fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n");
+}
+
static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
FILE *fp)
{
@@ -1218,9 +1226,8 @@ static int __event_process_build_id(struct build_id_event *bev,
struct perf_session *session)
{
int err = -1;
- struct dsos *dsos;
struct machine *machine;
- u16 misc;
+ u16 cpumode;
struct dso *dso;
enum dso_kernel_type dso_type;
@@ -1228,39 +1235,37 @@ static int __event_process_build_id(struct build_id_event *bev,
if (!machine)
goto out;
- misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+ cpumode = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
- switch (misc) {
+ switch (cpumode) {
case PERF_RECORD_MISC_KERNEL:
dso_type = DSO_TYPE_KERNEL;
- dsos = &machine->kernel_dsos;
break;
case PERF_RECORD_MISC_GUEST_KERNEL:
dso_type = DSO_TYPE_GUEST_KERNEL;
- dsos = &machine->kernel_dsos;
break;
case PERF_RECORD_MISC_USER:
case PERF_RECORD_MISC_GUEST_USER:
dso_type = DSO_TYPE_USER;
- dsos = &machine->user_dsos;
break;
default:
goto out;
}
- dso = __dsos__findnew(dsos, filename);
+ dso = machine__findnew_dso(machine, filename);
if (dso != NULL) {
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
dso__set_build_id(dso, &bev->build_id);
- if (!is_kernel_module(filename))
+ if (!is_kernel_module(filename, cpumode))
dso->kernel = dso_type;
build_id__sprintf(dso->build_id, sizeof(dso->build_id),
sbuild_id);
pr_debug("build id event received for %s: %s\n",
dso->long_name, sbuild_id);
+ dso__put(dso);
}
err = 0;
@@ -1426,7 +1431,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
if (ph->needs_swap)
nr = bswap_32(nr);
- ph->env.nr_cpus_online = nr;
+ ph->env.nr_cpus_avail = nr;
ret = readn(fd, &nr, sizeof(nr));
if (ret != sizeof(nr))
@@ -1435,7 +1440,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
if (ph->needs_swap)
nr = bswap_32(nr);
- ph->env.nr_cpus_avail = nr;
+ ph->env.nr_cpus_online = nr;
return 0;
}
@@ -1525,14 +1530,13 @@ process_event_desc(struct perf_file_section *section __maybe_unused,
return 0;
}
-static int process_cmdline(struct perf_file_section *section __maybe_unused,
+static int process_cmdline(struct perf_file_section *section,
struct perf_header *ph, int fd,
void *data __maybe_unused)
{
ssize_t ret;
- char *str;
- u32 nr, i;
- struct strbuf sb;
+ char *str, *cmdline = NULL, **argv = NULL;
+ u32 nr, i, len = 0;
ret = readn(fd, &nr, sizeof(nr));
if (ret != sizeof(nr))
@@ -1542,26 +1546,36 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
nr = bswap_32(nr);
ph->env.nr_cmdline = nr;
- strbuf_init(&sb, 128);
+
+ cmdline = zalloc(section->size + nr + 1);
+ if (!cmdline)
+ return -1;
+
+ argv = zalloc(sizeof(char *) * (nr + 1));
+ if (!argv)
+ goto error;
for (i = 0; i < nr; i++) {
str = do_read_string(fd, ph);
if (!str)
goto error;
- /* include a NULL character at the end */
- strbuf_add(&sb, str, strlen(str) + 1);
+ argv[i] = cmdline + len;
+ memcpy(argv[i], str, strlen(str) + 1);
+ len += strlen(str) + 1;
free(str);
}
- ph->env.cmdline = strbuf_detach(&sb, NULL);
+ ph->env.cmdline = cmdline;
+ ph->env.cmdline_argv = (const char **) argv;
return 0;
error:
- strbuf_release(&sb);
+ free(argv);
+ free(cmdline);
return -1;
}
-static int process_cpu_topology(struct perf_file_section *section __maybe_unused,
+static int process_cpu_topology(struct perf_file_section *section,
struct perf_header *ph, int fd,
void *data __maybe_unused)
{
@@ -1569,15 +1583,22 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
u32 nr, i;
char *str;
struct strbuf sb;
+ int cpu_nr = ph->env.nr_cpus_online;
+ u64 size = 0;
+
+ 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))
- return -1;
+ goto free_cpu;
if (ph->needs_swap)
nr = bswap_32(nr);
ph->env.nr_sibling_cores = nr;
+ size += sizeof(u32);
strbuf_init(&sb, 128);
for (i = 0; i < nr; i++) {
@@ -1587,6 +1608,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
/* include a NULL character at the end */
strbuf_add(&sb, str, strlen(str) + 1);
+ size += string_size(str);
free(str);
}
ph->env.sibling_cores = strbuf_detach(&sb, NULL);
@@ -1599,6 +1621,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
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);
@@ -1607,13 +1630,57 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
/* include a NULL character at the end */
strbuf_add(&sb, str, strlen(str) + 1);
+ size += string_size(str);
free(str);
}
ph->env.sibling_threads = strbuf_detach(&sb, NULL);
+
+ /*
+ * The header may be from old perf,
+ * which doesn't include core id and socket id information.
+ */
+ if (section->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))
+ goto free_cpu;
+
+ if (ph->needs_swap)
+ nr = bswap_32(nr);
+
+ if (nr > (u32)cpu_nr) {
+ pr_debug("core_id number is too big."
+ "You may need to upgrade the perf tool.\n");
+ goto free_cpu;
+ }
+ ph->env.cpu[i].core_id = nr;
+
+ ret = readn(fd, &nr, sizeof(nr));
+ if (ret != sizeof(nr))
+ goto free_cpu;
+
+ if (ph->needs_swap)
+ nr = bswap_32(nr);
+
+ if (nr > (u32)cpu_nr) {
+ pr_debug("socket_id number is too big."
+ "You may need to upgrade the perf tool.\n");
+ goto free_cpu;
+ }
+
+ ph->env.cpu[i].socket_id = nr;
+ }
+
return 0;
error:
strbuf_release(&sb);
+free_cpu:
+ zfree(&ph->env.cpu);
return -1;
}
@@ -1716,6 +1783,9 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
/* include a NULL character at the end */
strbuf_add(&sb, "", 1);
+ if (!strcmp(name, "msr"))
+ ph->env.msr_pmu_type = type;
+
free(name);
pmu_num--;
}
@@ -1821,6 +1891,22 @@ out_free:
return ret;
}
+static int process_auxtrace(struct perf_file_section *section,
+ struct perf_header *ph, int fd,
+ void *data __maybe_unused)
+{
+ struct perf_session *session;
+ int err;
+
+ session = container_of(ph, struct perf_session, header);
+
+ err = auxtrace_index__process(fd, section->size, session,
+ ph->needs_swap);
+ if (err < 0)
+ pr_err("Failed to process auxtrace index\n");
+ return err;
+}
+
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);
@@ -1861,6 +1947,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
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),
};
struct header_print_data {
@@ -2476,6 +2563,8 @@ int perf_session__read_header(struct perf_session *session)
if (session->evlist == NULL)
return -ENOMEM;
+ session->evlist->env = &header->env;
+ session->machines.host.env = &header->env;
if (perf_data_file__is_pipe(file))
return perf_header__read_pipe(session);