Commit ffa86c2f authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge tag 'perf-core-for-mingo-4.12-20170314' of...

Merge tag 'perf-core-for-mingo-4.12-20170314' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux

 into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

New features:

- Add PERF_RECORD_NAMESPACES so that the kernel can record information
  required to associate samples to namespaces, helping in container
  problem characterization.

  Now the 'perf record has a --namespace' option to ask for such info,
  and when present, it can be used, initially, via a new sort order,
  'cgroup_id', allowing histogram entry bucketization by a (device, inode)
  based cgroup identifier (Hari Bathini)

- Add --next option to 'perf sched timehist', showing what is the next
  thread to run (Brendan Gregg)

Fixes:

- Fix segfault with basic block 'cycles' sort dimension (Changbin Du)

- Add c2c to command-list.txt, making it appear in the 'perf help'
  output (Changbin Du)

- Fix zeroing of 'abs_path' variable in the perf hists browser switch
  file code (Changbin Du)

- Hide tips messages when -q/--quiet is given to 'perf report' (Namhyung Kim)

Infrastructure changes:

- Use ref_reloc_sym + offset to setup kretprobes (Naveen Rao)

- Ignore generated files pmu-events/{jevents,pmu-events.c} for git (Changbin Du)

Documentation changes:

- Document +field style argument support for --field option (Changbin Du)

- Clarify 'perf c2c --stats' help message (Namhyung Kim)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 84e5b549 5f6bee34
...@@ -858,6 +858,7 @@ static int __cmd_report(bool display_info) ...@@ -858,6 +858,7 @@ static int __cmd_report(bool display_info)
struct perf_tool eops = { struct perf_tool eops = {
.sample = process_sample_event, .sample = process_sample_event,
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.namespaces = perf_event__process_namespaces,
.ordered_events = true, .ordered_events = true,
}; };
struct perf_data_file file = { struct perf_data_file file = {
......
...@@ -342,6 +342,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -342,6 +342,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
.lost = perf_event__process_lost, .lost = perf_event__process_lost,
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.build_id = perf_event__process_build_id, .build_id = perf_event__process_build_id,
.namespaces = perf_event__process_namespaces,
.ordered_events = true, .ordered_events = true,
}, },
.input_name = "perf.data", .input_name = "perf.data",
......
...@@ -876,6 +876,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) ...@@ -876,6 +876,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
signal(SIGTERM, sig_handler); signal(SIGTERM, sig_handler);
signal(SIGSEGV, sigsegv_handler); signal(SIGSEGV, sigsegv_handler);
if (rec->opts.record_namespaces)
tool->namespace_events = true;
if (rec->opts.auxtrace_snapshot_mode || rec->switch_output.enabled) { if (rec->opts.auxtrace_snapshot_mode || rec->switch_output.enabled) {
signal(SIGUSR2, snapshot_sig_handler); signal(SIGUSR2, snapshot_sig_handler);
if (rec->opts.auxtrace_snapshot_mode) if (rec->opts.auxtrace_snapshot_mode)
...@@ -983,6 +986,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) ...@@ -983,6 +986,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
*/ */
if (forks) { if (forks) {
union perf_event *event; union perf_event *event;
pid_t tgid;
event = malloc(sizeof(event->comm) + machine->id_hdr_size); event = malloc(sizeof(event->comm) + machine->id_hdr_size);
if (event == NULL) { if (event == NULL) {
...@@ -996,10 +1000,30 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) ...@@ -996,10 +1000,30 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
* cannot see a correct process name for those events. * cannot see a correct process name for those events.
* Synthesize COMM event to prevent it. * Synthesize COMM event to prevent it.
*/ */
perf_event__synthesize_comm(tool, event, tgid = perf_event__synthesize_comm(tool, event,
rec->evlist->workload.pid, rec->evlist->workload.pid,
process_synthesized_event, process_synthesized_event,
machine); machine);
free(event);
if (tgid == -1)
goto out_child;
event = malloc(sizeof(event->namespaces) +
(NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
machine->id_hdr_size);
if (event == NULL) {
err = -ENOMEM;
goto out_child;
}
/*
* Synthesize NAMESPACES event for the command specified.
*/
perf_event__synthesize_namespaces(tool, event,
rec->evlist->workload.pid,
tgid, process_synthesized_event,
machine);
free(event); free(event);
perf_evlist__start_workload(rec->evlist); perf_evlist__start_workload(rec->evlist);
...@@ -1497,6 +1521,7 @@ static struct record record = { ...@@ -1497,6 +1521,7 @@ static struct record record = {
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.exit = perf_event__process_exit, .exit = perf_event__process_exit,
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.namespaces = perf_event__process_namespaces,
.mmap = perf_event__process_mmap, .mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2, .mmap2 = perf_event__process_mmap2,
.ordered_events = true, .ordered_events = true,
...@@ -1611,6 +1636,8 @@ static struct option __record_options[] = { ...@@ -1611,6 +1636,8 @@ static struct option __record_options[] = {
"opts", "AUX area tracing Snapshot Mode", ""), "opts", "AUX area tracing Snapshot Mode", ""),
OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout, OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout,
"per thread proc mmap processing timeout in ms"), "per thread proc mmap processing timeout in ms"),
OPT_BOOLEAN(0, "namespaces", &record.opts.record_namespaces,
"Record namespaces events"),
OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
"Record context switch events"), "Record context switch events"),
OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel, OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel,
......
...@@ -394,8 +394,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, ...@@ -394,8 +394,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
fprintf(stdout, "\n\n"); fprintf(stdout, "\n\n");
} }
if (sort_order == NULL && if (!quiet)
parent_pattern == default_parent_pattern)
fprintf(stdout, "#\n# (%s)\n#\n", help); fprintf(stdout, "#\n# (%s)\n#\n", help);
if (rep->show_threads) { if (rep->show_threads) {
...@@ -701,6 +700,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -701,6 +700,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
.mmap = perf_event__process_mmap, .mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2, .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.namespaces = perf_event__process_namespaces,
.exit = perf_event__process_exit, .exit = perf_event__process_exit,
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.lost = perf_event__process_lost, .lost = perf_event__process_lost,
......
...@@ -221,6 +221,7 @@ struct perf_sched { ...@@ -221,6 +221,7 @@ struct perf_sched {
unsigned int max_stack; unsigned int max_stack;
bool show_cpu_visual; bool show_cpu_visual;
bool show_wakeups; bool show_wakeups;
bool show_next;
bool show_migrations; bool show_migrations;
bool show_state; bool show_state;
u64 skipped_samples; u64 skipped_samples;
...@@ -1897,14 +1898,18 @@ static char task_state_char(struct thread *thread, int state) ...@@ -1897,14 +1898,18 @@ static char task_state_char(struct thread *thread, int state)
} }
static void timehist_print_sample(struct perf_sched *sched, static void timehist_print_sample(struct perf_sched *sched,
struct perf_evsel *evsel,
struct perf_sample *sample, struct perf_sample *sample,
struct addr_location *al, struct addr_location *al,
struct thread *thread, struct thread *thread,
u64 t, int state) u64 t, int state)
{ {
struct thread_runtime *tr = thread__priv(thread); struct thread_runtime *tr = thread__priv(thread);
const char *next_comm = perf_evsel__strval(evsel, sample, "next_comm");
const u32 next_pid = perf_evsel__intval(evsel, sample, "next_pid");
u32 max_cpus = sched->max_cpu + 1; u32 max_cpus = sched->max_cpu + 1;
char tstr[64]; char tstr[64];
char nstr[30];
u64 wait_time; u64 wait_time;
timestamp__scnprintf_usec(t, tstr, sizeof(tstr)); timestamp__scnprintf_usec(t, tstr, sizeof(tstr));
...@@ -1937,7 +1942,12 @@ static void timehist_print_sample(struct perf_sched *sched, ...@@ -1937,7 +1942,12 @@ static void timehist_print_sample(struct perf_sched *sched,
if (sched->show_state) if (sched->show_state)
printf(" %5c ", task_state_char(thread, state)); printf(" %5c ", task_state_char(thread, state));
if (sched->show_wakeups) if (sched->show_next) {
snprintf(nstr, sizeof(nstr), "next: %s[%d]", next_comm, next_pid);
printf(" %-*s", comm_width, nstr);
}
if (sched->show_wakeups && !sched->show_next)
printf(" %-*s", comm_width, ""); printf(" %-*s", comm_width, "");
if (thread->tid == 0) if (thread->tid == 0)
...@@ -2531,7 +2541,7 @@ static int timehist_sched_change_event(struct perf_tool *tool, ...@@ -2531,7 +2541,7 @@ static int timehist_sched_change_event(struct perf_tool *tool,
} }
if (!sched->summary_only) if (!sched->summary_only)
timehist_print_sample(sched, sample, &al, thread, t, state); timehist_print_sample(sched, evsel, sample, &al, thread, t, state);
out: out:
if (sched->hist_time.start == 0 && t >= ptime->start) if (sched->hist_time.start == 0 && t >= ptime->start)
...@@ -3272,6 +3282,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -3272,6 +3282,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
.tool = { .tool = {
.sample = perf_sched__process_tracepoint_sample, .sample = perf_sched__process_tracepoint_sample,
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.namespaces = perf_event__process_namespaces,
.lost = perf_event__process_lost, .lost = perf_event__process_lost,
.fork = perf_sched__process_fork_event, .fork = perf_sched__process_fork_event,
.ordered_events = true, .ordered_events = true,
...@@ -3340,6 +3351,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -3340,6 +3351,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_BOOLEAN('S', "with-summary", &sched.summary, OPT_BOOLEAN('S', "with-summary", &sched.summary,
"Show all syscalls and summary with statistics"), "Show all syscalls and summary with statistics"),
OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"), OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"),
OPT_BOOLEAN('n', "next", &sched.show_next, "Show next task"),
OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"), OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"),
OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"), OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"),
OPT_BOOLEAN('I', "idle-hist", &sched.idle_hist, "Show idle events only"), OPT_BOOLEAN('I', "idle-hist", &sched.idle_hist, "Show idle events only"),
...@@ -3437,10 +3449,14 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -3437,10 +3449,14 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
if (argc) if (argc)
usage_with_options(timehist_usage, timehist_options); usage_with_options(timehist_usage, timehist_options);
} }
if (sched.show_wakeups && sched.summary_only) { if ((sched.show_wakeups || sched.show_next) &&
pr_err(" Error: -s and -w are mutually exclusive.\n"); sched.summary_only) {
pr_err(" Error: -s and -[n|w] are mutually exclusive.\n");
parse_options_usage(timehist_usage, timehist_options, "s", true); parse_options_usage(timehist_usage, timehist_options, "s", true);
parse_options_usage(NULL, timehist_options, "w", true); if (sched.show_wakeups)
parse_options_usage(NULL, timehist_options, "w", true);
if (sched.show_next)
parse_options_usage(NULL, timehist_options, "n", true);
return -EINVAL; return -EINVAL;
} }
......
...@@ -830,6 +830,7 @@ struct perf_script { ...@@ -830,6 +830,7 @@ struct perf_script {
bool show_task_events; bool show_task_events;
bool show_mmap_events; bool show_mmap_events;
bool show_switch_events; bool show_switch_events;
bool show_namespace_events;
bool allocated; bool allocated;
struct cpu_map *cpus; struct cpu_map *cpus;
struct thread_map *threads; struct thread_map *threads;
...@@ -1118,6 +1119,41 @@ static int process_comm_event(struct perf_tool *tool, ...@@ -1118,6 +1119,41 @@ static int process_comm_event(struct perf_tool *tool,
return ret; return ret;
} }
static int process_namespaces_event(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct machine *machine)
{
struct thread *thread;
struct perf_script *script = container_of(tool, struct perf_script, tool);
struct perf_session *session = script->session;
struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id);
int ret = -1;
thread = machine__findnew_thread(machine, event->namespaces.pid,
event->namespaces.tid);
if (thread == NULL) {
pr_debug("problem processing NAMESPACES event, skipping it.\n");
return -1;
}
if (perf_event__process_namespaces(tool, event, sample, machine) < 0)
goto out;
if (!evsel->attr.sample_id_all) {
sample->cpu = 0;
sample->time = 0;
sample->tid = event->namespaces.tid;
sample->pid = event->namespaces.pid;
}
print_sample_start(sample, thread, evsel);
perf_event__fprintf(event, stdout);
ret = 0;
out:
thread__put(thread);
return ret;
}
static int process_fork_event(struct perf_tool *tool, static int process_fork_event(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
...@@ -1293,6 +1329,8 @@ static int __cmd_script(struct perf_script *script) ...@@ -1293,6 +1329,8 @@ static int __cmd_script(struct perf_script *script)
} }
if (script->show_switch_events) if (script->show_switch_events)
script->tool.context_switch = process_switch_event; script->tool.context_switch = process_switch_event;
if (script->show_namespace_events)
script->tool.namespaces = process_namespaces_event;
ret = perf_session__process_events(script->session); ret = perf_session__process_events(script->session);
...@@ -2097,6 +2135,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -2097,6 +2135,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
.mmap = perf_event__process_mmap, .mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2, .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.namespaces = perf_event__process_namespaces,
.exit = perf_event__process_exit, .exit = perf_event__process_exit,
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.attr = process_attr, .attr = process_attr,
...@@ -2180,6 +2219,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -2180,6 +2219,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
"Show the mmap events"), "Show the mmap events"),
OPT_BOOLEAN('\0', "show-switch-events", &script.show_switch_events, OPT_BOOLEAN('\0', "show-switch-events", &script.show_switch_events,
"Show context switch events (if recorded)"), "Show context switch events (if recorded)"),
OPT_BOOLEAN('\0', "show-namespace-events", &script.show_namespace_events,
"Show namespace events (if recorded)"),
OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
OPT_BOOLEAN(0, "ns", &nanosecs, OPT_BOOLEAN(0, "ns", &nanosecs,
"Use 9 decimal places when displaying time"), "Use 9 decimal places when displaying time"),
......
...@@ -2415,8 +2415,9 @@ static int trace__replay(struct trace *trace) ...@@ -2415,8 +2415,9 @@ static int trace__replay(struct trace *trace)
trace->tool.exit = perf_event__process_exit; trace->tool.exit = perf_event__process_exit;
trace->tool.fork = perf_event__process_fork; trace->tool.fork = perf_event__process_fork;
trace->tool.attr = perf_event__process_attr; trace->tool.attr = perf_event__process_attr;
trace->tool.tracing_data = perf_event__process_tracing_data; trace->tool.tracing_data = perf_event__process_tracing_data;
trace->tool.build_id = perf_event__process_build_id; trace->tool.build_id = perf_event__process_build_id;
trace->tool.namespaces = perf_event__process_namespaces;
trace->tool.ordered_events = true; trace->tool.ordered_events = true;
trace->tool.ordering_requires_timestamps = true; trace->tool.ordering_requires_timestamps = true;
......
...@@ -9,6 +9,7 @@ perf-buildid-cache mainporcelain common ...@@ -9,6 +9,7 @@ perf-buildid-cache mainporcelain common
perf-buildid-list mainporcelain common perf-buildid-list mainporcelain common
perf-data mainporcelain common perf-data mainporcelain common
perf-diff mainporcelain common perf-diff mainporcelain common
perf-c2c mainporcelain common
perf-config mainporcelain common perf-config mainporcelain common
perf-evlist mainporcelain common perf-evlist mainporcelain common
perf-ftrace mainporcelain common perf-ftrace mainporcelain common
......
...@@ -50,6 +50,7 @@ struct record_opts { ...@@ -50,6 +50,7 @@ struct record_opts {
bool running_time; bool running_time;
bool full_auxtrace; bool full_auxtrace;
bool auxtrace_snapshot_mode; bool auxtrace_snapshot_mode;
bool record_namespaces;
bool record_switch_events; bool record_switch_events;
bool all_kernel; bool all_kernel;
bool all_user; bool all_user;
......
...@@ -2308,7 +2308,7 @@ static int switch_data_file(void) ...@@ -2308,7 +2308,7 @@ static int switch_data_file(void)
return ret; return ret;
memset(options, 0, sizeof(options)); memset(options, 0, sizeof(options));
memset(options, 0, sizeof(abs_path)); memset(abs_path, 0, sizeof(abs_path));
while ((dent = readdir(pwd_dir))) { while ((dent = readdir(pwd_dir))) {
char path[PATH_MAX]; char path[PATH_MAX];
......
...@@ -42,6 +42,7 @@ libperf-y += pstack.o ...@@ -42,6 +42,7 @@ libperf-y += pstack.o
libperf-y += session.o libperf-y += session.o
libperf-$(CONFIG_AUDIT) += syscalltbl.o libperf-$(CONFIG_AUDIT) += syscalltbl.o
libperf-y += ordered-events.o libperf-y += ordered-events.o
libperf-y += namespaces.o
libperf-y += comm.o libperf-y += comm.o
libperf-y += thread.o libperf-y += thread.o
libperf-y += thread_map.o libperf-y += thread_map.o
......
...@@ -1468,6 +1468,7 @@ int bt_convert__perf2ctf(const char *input, const char *path, ...@@ -1468,6 +1468,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
.lost = perf_event__process_lost, .lost = perf_event__process_lost,
.tracing_data = perf_event__process_tracing_data, .tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id, .build_id = perf_event__process_build_id,
.namespaces = perf_event__process_namespaces,
.ordered_events = true, .ordered_events = true,
.ordering_requires_timestamps = true, .ordering_requires_timestamps = true,
}, },
......
...@@ -31,6 +31,7 @@ static const char *perf_event__names[] = { ...@@ -31,6 +31,7 @@ static const char *perf_event__names[] = {
[PERF_RECORD_LOST_SAMPLES] = "LOST_SAMPLES", [PERF_RECORD_LOST_SAMPLES] = "LOST_SAMPLES",
[PERF_RECORD_SWITCH] = "SWITCH", [PERF_RECORD_SWITCH] = "SWITCH",
[PERF_RECORD_SWITCH_CPU_WIDE] = "SWITCH_CPU_WIDE", [PERF_RECORD_SWITCH_CPU_WIDE] = "SWITCH_CPU_WIDE",
[PERF_RECORD_NAMESPACES] = "NAMESPACES",
[PERF_RECORD_HEADER_ATTR] = "ATTR", [PERF_RECORD_HEADER_ATTR] = "ATTR",
[PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
[PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
...@@ -49,6 +50,16 @@ static const char *perf_event__names[] = { ...@@ -49,6 +50,16 @@ static const char *perf_event__names[] = {
[PERF_RECORD_TIME_CONV] = "TIME_CONV", [PERF_RECORD_TIME_CONV] = "TIME_CONV",
}; };
static const char *perf_ns__names[] = {
[NET_NS_INDEX] = "net",
[UTS_NS_INDEX] = "uts",
[IPC_NS_INDEX] = "ipc",
[PID_NS_INDEX] = "pid",
[USER_NS_INDEX] = "user",
[MNT_NS_INDEX] = "mnt",
[CGROUP_NS_INDEX] = "cgroup",
};
const char *perf_event__name(unsigned int id) const char *perf_event__name(unsigned int id)
{ {
if (id >= ARRAY_SIZE(perf_event__names)) if (id >= ARRAY_SIZE(perf_event__names))
...@@ -58,6 +69,13 @@ const char *perf_event__name(unsigned int id) ...@@ -58,6 +69,13 @@ const char *perf_event__name(unsigned int id)
return perf_event__names[id]; return perf_event__names[id];
} }
static const char *perf_ns__name(unsigned int id)
{
if (id >= ARRAY_SIZE(perf_ns__names))
return "UNKNOWN";
return perf_ns__names[id];
}
static int perf_tool__process_synth_event(struct perf_tool *tool, static int perf_tool__process_synth_event(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct machine *machine, struct machine *machine,
...@@ -203,6 +221,58 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool, ...@@ -203,6 +221,58 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
return tgid; return tgid;
} }
static void perf_event__get_ns_link_info(pid_t pid, const char *ns,
struct perf_ns_link_info *ns_link_info)
{
struct stat64 st;
char proc_ns[128];
sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns);
if (stat64(proc_ns, &st) == 0) {
ns_link_info->dev = st.st_dev;
ns_link_info->ino = st.st_ino;
}
}
int perf_event__synthesize_namespaces(struct perf_tool *tool,
union perf_event *event,
pid_t pid, pid_t tgid,
perf_event__handler_t process,
struct machine *machine)
{
u32 idx;
struct perf_ns_link_info *ns_link_info;
if (!tool || !tool->namespace_events)
return 0;
memset(&event->namespaces, 0, (sizeof(event->namespaces) +
(NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
machine->id_hdr_size));
event->namespaces.pid = tgid;
event->namespaces.tid = pid;
event->namespaces.nr_namespaces = NR_NAMESPACES;
ns_link_info = event->namespaces.link_info;
for (idx = 0; idx < event->namespaces.nr_namespaces; idx++)
perf_event__get_ns_link_info(pid, perf_ns__name(idx),
&ns_link_info[idx]);
event->namespaces.header.type = PERF_RECORD_NAMESPACES;
event->namespaces.header.size = (sizeof(event->namespaces) +
(NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
machine->id_hdr_size);
if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
return -1;
return 0;
}
static int perf_event__synthesize_fork(struct perf_tool *tool, static int perf_event__synthesize_fork(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
pid_t pid, pid_t tgid, pid_t ppid, pid_t pid, pid_t tgid, pid_t ppid,
...@@ -434,8 +504,9 @@ int perf_event__synthesize_modules(struct perf_tool *tool, ...@@ -434,8 +504,9 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
static int __event__synthesize_thread(union perf_event *comm_event, static int __event__synthesize_thread(union perf_event *comm_event,
union perf_event *mmap_event, union perf_event *mmap_event,
union perf_event *fork_event, union perf_event *fork_event,
union perf_event *namespaces_event,
pid_t pid, int full, pid_t pid, int full,
perf_event__handler_t process, perf_event__handler_t process,
struct perf_tool *tool, struct perf_tool *tool,
struct machine *machine, struct machine *machine,
bool mmap_data, bool mmap_data,
...@@ -455,6 +526,11 @@ static int __event__synthesize_thread(union perf_event *comm_event, ...@@ -455,6 +526,11 @@ static int __event__synthesize_thread(union perf_event *comm_event,
if (tgid == -1) if (tgid == -1)
return -1; return -1;
if (perf_event__synthesize_namespaces(tool, namespaces_event, pid,
tgid, process, machine) < 0)
return -1;
return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
process, machine, mmap_data, process, machine, mmap_data,
proc_map_timeout); proc_map_timeout);
...@@ -488,6 +564,11 @@ static int __event__synthesize_thread(union perf_event *comm_event, ...@@ -488,6 +564,11 @@ static int __event__synthesize_thread(union perf_event *comm_event,
if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid, if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
ppid, process, machine) < 0) ppid, process, machine) < 0)
break; break;
if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid,
tgid, process, machine) < 0)
break;
/* /*
* Send the prepared comm event * Send the prepared comm event
*/ */
...@@ -516,6 +597,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, ...@@ -516,6 +597,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
unsigned int proc_map_timeout) unsigned int proc_map_timeout)
{ {
union perf_event *comm_event, *mmap_event, *fork_event; union perf_event *comm_event, *mmap_event, *fork_event;
union perf_event *namespaces_event;
int err = -1, thread, j; int err = -1, thread, j;
comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
...@@ -530,10 +612,16 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, ...@@ -530,10 +612,16 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
if (fork_event == NULL) if (fork_event == NULL)
goto out_free_mmap; goto out_free_mmap;
namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
(NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
machine->id_hdr_size);
if (namespaces_event == NULL)
goto out_free_fork;
err = 0; err = 0;
for (thread = 0; thread < threads->nr; ++thread) { for (thread = 0; thread < threads->nr; ++thread) {
if (__event__synthesize_thread(comm_event, mmap_event, if (__event__synthesize_thread(comm_event, mmap_event,
fork_event, fork_event, namespaces_event,
thread_map__pid(threads, thread), 0, thread_map__pid(threads, thread), 0,
process, tool, machine, process, tool, machine,
mmap_data, proc_map_timeout)) { mmap_data, proc_map_timeout)) {
...@@ -559,7 +647,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, ...@@ -559,7 +647,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
/* if not, generate events for it */ /* if not, generate events for it */
if (need_leader && if (need_leader &&
__event__synthesize_thread(comm_event, mmap_event, __event__synthesize_thread(comm_event, mmap_event,
fork_event, fork_event, namespaces_event,
comm_event->comm.pid, 0, comm_event->comm.pid, 0,
process, tool, machine, process, tool, machine,
mmap_data, proc_map_timeout)) { mmap_data, proc_map_timeout)) {
...@@ -568,6 +656,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, ...@@ -568,6 +656,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
} }
} }
} }
free(namespaces_event);
out_free_fork:
free(fork_event); free(fork_event);
out_free_mmap: out_free_mmap:
free(mmap_event); free(mmap_event);
...@@ -587,6 +677,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, ...@@ -587,6 +677,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
char proc_path[PATH_MAX]; char proc_path[PATH_MAX];
struct dirent *dirent; struct dirent *dirent;
union perf_event *comm_event, *mmap_event, *fork_event; union perf_event *comm_event, *mmap_event, *fork_event;
union perf_event *namespaces_event;
int err = -1; int err = -1;
if (machine__is_default_guest(machine)) if (machine__is_default_guest(machine))
...@@ -604,11 +695,17 @@ int perf_event__synthesize_threads(struct perf_tool *tool, ...@@ -604,11 +695,17 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
if (fork_event == NULL) if (fork_event == NULL)
goto out_free_mmap; goto out_free_mmap;
namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
(NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
machine->id_hdr_size);
if (namespaces_event == NULL)
goto out_free_fork;
snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
proc = opendir(proc_path); proc = opendir(proc_path);
if (proc == NULL) if (proc == NULL)
goto out_free_fork; goto out_free_namespaces;
while ((dirent = readdir(proc)) != NULL) { while ((dirent = readdir(proc)) != NULL) {
char *end; char *end;
...@@ -620,13 +717,16 @@ int perf_event__synthesize_threads(struct perf_tool *tool, ...@@ -620,13 +717,16 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
* We may race with exiting thread, so don't stop just because * We may race with exiting thread, so don't stop just because
* one thread couldn't be synthesized. * one thread couldn't be synthesized.
*/ */
__event__synthesize_thread(comm_event, mmap_event, fork_event, pid, __event__synthesize_thread(comm_event, mmap_event, fork_event,
1, process, tool, machine, mmap_data, namespaces_event, pid, 1, process,
tool, machine, mmap_data,
proc_map_timeout); proc_map_timeout);
} }
err = 0; err = 0;
closedir(proc); closedir(proc);
out_free_namespaces:
free(namespaces_event);
out_free_fork: out_free_fork:
free(fork_event); free(fork_event);
out_free_mmap: out_free_mmap:
...@@ -1008,6 +1108,33 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) ...@@ -1008,6 +1108,33 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid); return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid);
} }
size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp)
{
size_t ret = 0;
struct perf_ns_link_info *ns_link_info;
u32 nr_namespaces, idx;
ns_link_info = event->namespaces.link_info;
nr_namespaces = event->namespaces.nr_namespaces;
ret += fprintf(fp, " %d/%d - nr_namespaces: %u\n\t\t[",
event->namespaces.pid,
event->namespaces.tid,
nr_namespaces);
for (idx = 0; idx < nr_namespaces; idx++) {
if (idx && (idx % 4 == 0))
ret += fprintf(fp, "\n\t\t ");
ret += fprintf(fp, "%u/%s: %" PRIu64 "/%#" PRIx64 "%s", idx,
perf_ns__name(idx), (u64)ns_link_info[idx].dev,
(u64)ns_link_info[idx].ino,
((idx + 1) != nr_namespaces) ? ", " : "]\n");
}
return ret;
}
int perf_event__process_comm(struct perf_tool *tool __maybe_unused, int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
...@@ -1016,6 +1143,14 @@ int perf_event__process_comm(struct perf_tool *tool __maybe_unused, ...@@ -1016,6 +1143,14 @@ int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
return machine__process_comm_event(machine, event, sample); return machine__process_comm_event(machine, event, sample);
} }
int perf_event__process_namespaces(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample,
struct machine *machine)
{
return machine__process_namespaces_event(machine, event, sample);
}
int perf_event__process_lost(struct perf_tool *tool __maybe_unused, int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
...@@ -1196,6 +1331,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp) ...@@ -1196,6 +1331,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
case PERF_RECORD_MMAP: case PERF_RECORD_MMAP:
ret += perf_event__fprintf_mmap(event, fp); ret += perf_event__fprintf_mmap(event, fp);
break; break;
case PERF_RECORD_NAMESPACES:
ret += perf_event__fprintf_namespaces(event, fp);
break;
case PERF_RECORD_MMAP2: case PERF_RECORD_MMAP2:
ret += perf_event__fprintf_mmap2(event, fp); ret += perf_event__fprintf_mmap2(event, fp);
break; break;
......
...@@ -39,6 +39,13 @@ struct comm_event { ...@@ -39,6 +39,13 @@ struct comm_event {
char comm[16]; char comm[16];
}; };
struct namespaces_event {
struct perf_event_header header;
u32 pid, tid;
u64 nr_namespaces;
struct perf_ns_link_info link_info[];
};
struct fork_event { struct fork_event {
struct perf_event_header header; struct perf_event_header header;
u32 pid, ppid; u32 pid, ppid;
...@@ -485,6 +492,7 @@ union perf_event { ...@@ -485,6 +492,7 @@ union perf_event {
struct mmap_event mmap; struct mmap_event mmap;
struct mmap2_event mmap2; struct mmap2_event mmap2;
struct comm_event comm; struct comm_event comm;
struct namespaces_event namespaces;
struct fork_event fork; struct fork_event fork;
struct lost_event lost; struct lost_event lost;
struct lost_samples_event lost_samples; struct lost_samples_event lost_samples;
...@@ -587,6 +595,10 @@ int perf_event__process_switch(struct perf_tool *tool, ...@@ -587,6 +595,10 @@ int perf_event__process_switch(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
struct machine *machine); struct machine *machine);
int perf_event__process_namespaces(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct machine *machine);
int perf_event__process_mmap(struct perf_tool *tool, int perf_event__process_mmap(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
...@@ -636,6 +648,12 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool, ...@@ -636,6 +648,12 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
perf_event__handler_t process, perf_event__handler_t process,
struct machine *machine); struct machine *machine);
int perf_event__synthesize_namespaces(struct perf_tool *tool,
union perf_event *event,
pid_t pid, pid_t tgid,
perf_event__handler_t process,
struct machine *machine);
int perf_event__synthesize_mmap_events(struct perf_tool *tool, int perf_event__synthesize_mmap_events(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
pid_t pid, pid_t tgid, pid_t pid, pid_t tgid,
...@@ -653,6 +671,7 @@ size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp); ...@@ -653,6 +671,7 @@ size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp); size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp); size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp); size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp);
size_t perf_event__fprintf(union perf_event *event, FILE *fp); size_t perf_event__fprintf(union perf_event *event, FILE *fp);
u64 kallsyms__get_function_start(const char *kallsyms_filename, u64 kallsyms__get_function_start(const char *kallsyms_filename,
......
...@@ -932,6 +932,9 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, ...@@ -932,6 +932,9 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
attr->mmap2 = track && !perf_missing_features.mmap2; attr->mmap2 = track && !perf_missing_features.mmap2;
attr->comm = track; attr->comm = track;
if (opts->record_namespaces)
attr->namespaces = track;
if (opts->record_switch_events) if (opts->record_switch_events)
attr->context_switch = track; attr->context_switch = track;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "hist.h" #include "hist.h"
#include "map.h" #include "map.h"
#include "session.h" #include "session.h"
#include "namespaces.h"
#include "sort.h" #include "sort.h"
#include "evlist.h" #include "evlist.h"
#include "evsel.h" #include "evsel.h"
...@@ -169,6 +170,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) ...@@ -169,6 +170,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO); hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
} }
hists__new_col_len(hists, HISTC_CGROUP_ID, 20);
hists__new_col_len(hists, HISTC_CPU, 3); hists__new_col_len(hists, HISTC_CPU, 3);
hists__new_col_len(hists, HISTC_SOCKET, 6); hists__new_col_len(hists, HISTC_SOCKET, 6);
hists__new_col_len(hists, HISTC_MEM_LOCKED, 6); hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
...@@ -574,9 +576,14 @@ __hists__add_entry(struct hists *hists, ...@@ -574,9 +576,14 @@ __hists__add_entry(struct hists *hists,
bool sample_self, bool sample_self,
struct hist_entry_ops *ops) struct hist_entry_ops *ops)
{ {
struct namespaces *ns = thread__namespaces(al->thread);
struct hist_entry entry = { struct hist_entry entry = {
.thread = al->thread, .thread = al->thread,
.comm = thread__comm(al->thread), .comm = thread__comm(al->thread),
.cgroup_id = {
.dev = ns ? ns->link_info[CGROUP_NS_INDEX].dev : 0,
.ino = ns ? ns->link_info[CGROUP_NS_INDEX].ino : 0,
},
.ms = { .ms = {
.map = al->map, .map = al->map,
.sym = al->sym, .sym = al->sym,
......
...@@ -30,6 +30,7 @@ enum hist_column { ...@@ -30,6 +30,7 @@ enum hist_column {
HISTC_DSO, HISTC_DSO,
HISTC_THREAD, HISTC_THREAD,
HISTC_COMM, HISTC_COMM,
HISTC_CGROUP_ID,
HISTC_PARENT, HISTC_PARENT,
HISTC_CPU, HISTC_CPU,
HISTC_SOCKET, HISTC_SOCKET,
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <symbol/kallsyms.h> #include <symbol/kallsyms.h>
#include "unwind.h" #include "unwind.h"
#include "linux/hash.h" #include "linux/hash.h"
#include "asm/bug.h"
static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock); static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock);
...@@ -501,6 +502,37 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event ...@@ -501,6 +502,37 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
return err; return err;
} }
int machine__process_namespaces_event(struct machine *machine __maybe_unused,
union perf_event *event,
struct perf_sample *sample __maybe_unused)
{
struct thread *thread = machine__findnew_thread(machine,
event->namespaces.pid,
event->namespaces.tid);
int err = 0;
WARN_ONCE(event->namespaces.nr_namespaces > NR_NAMESPACES,
"\nWARNING: kernel seems to support more namespaces than perf"
" tool.\nTry updating the perf tool..\n\n");
WARN_ONCE(event->namespaces.nr_namespaces < NR_NAMESPACES,
"\nWARNING: perf tool seems to support more namespaces than"
" the kernel.\nTry updating the kernel..\n\n");
if (dump_trace)
perf_event__fprintf_namespaces(event, stdout);
if (thread == NULL ||
thread__set_namespaces(thread, sample->time, &event->namespaces)) {
dump_printf("problem processing PERF_RECORD_NAMESPACES, skipping event.\n");
err = -1;
}
thread__put(thread);
return err;
}
int machine__process_lost_event(struct machine *machine __maybe_unused, int machine__process_lost_event(struct machine *machine __maybe_unused,
union perf_event *event, struct perf_sample *sample __maybe_unused) union perf_event *event, struct perf_sample *sample __maybe_unused)
{ {
...@@ -1538,6 +1570,8 @@ int machine__process_event(struct machine *machine, union perf_event *event, ...@@ -1538,6 +1570,8 @@ int machine__process_event(struct machine *machine, union perf_event *event,
ret = machine__process_comm_event(machine, event, sample); break; ret = machine__process_comm_event(machine, event, sample); break;
case PERF_RECORD_MMAP: case PERF_RECORD_MMAP:
ret = machine__process_mmap_event(machine, event, sample); break; ret = machine__process_mmap_event(machine, event, sample); break;
case PERF_RECORD_NAMESPACES:
ret = machine__process_namespaces_event(machine, event, sample); break;
case PERF_RECORD_MMAP2: case PERF_RECORD_MMAP2:
ret = machine__process_mmap2_event(machine, event, sample); break; ret = machine__process_mmap2_event(machine, event, sample); break;
case PERF_RECORD_FORK: case PERF_RECORD_FORK:
......
...@@ -97,6 +97,9 @@ int machine__process_itrace_start_event(struct machine *machine, ...@@ -97,6 +97,9 @@ int machine__process_itrace_start_event(struct machine *machine,
union perf_event *event); union perf_event *event);
int machine__process_switch_event(struct machine *machine, int machine__process_switch_event(struct machine *machine,
union perf_event *event); union perf_event *event);
int machine__process_namespaces_event(struct machine *machine,
union perf_event *event,
struct perf_sample *sample);
int machine__process_mmap_event(struct machine *machine, union perf_event *event, int machine__process_mmap_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample); struct perf_sample *sample);
int machine__process_mmap2_event(struct machine *machine, union perf_event *event, int machine__process_mmap2_event(struct machine *machine, union perf_event *event,
......
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* Copyright (C) 2017 Hari Bathini, IBM Corporation
*/
#include "namespaces.h"
#include "util.h"
#include "event.h"
#include <stdlib.h>
#include <stdio.h>
struct namespaces *namespaces__new(struct namespaces_event *event)
{
struct namespaces *namespaces;
u64 link_info_size = ((event ? event->nr_namespaces : NR_NAMESPACES) *
sizeof(struct perf_ns_link_info));
namespaces = zalloc(sizeof(struct namespaces) + link_info_size);
if (!namespaces)
return NULL;
namespaces->end_time = -1;
if (event)
memcpy(namespaces->link_info, event->link_info, link_info_size);
return namespaces;
}
void namespaces__free(struct namespaces *namespaces)
{
free(namespaces);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment