diff options
| author | Ingo Molnar <mingo@kernel.org> | 2016-12-02 10:08:03 +0100 | 
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2016-12-02 10:08:03 +0100 | 
| commit | e7af7b15121ca08c31a0ab9df71a41b4c53365b4 (patch) | |
| tree | 3c4ee7bd52c8cc41642efee0b5549b573d69268a /tools/perf/builtin-sched.c | |
| parent | 3782746a08f6b0a8e385058b6748a5a0f166f3a7 (diff) | |
| parent | 0fcb1da4aba6e6c7b32de5e0948b740b31ad822d (diff) | |
Merge tag 'perf-core-for-mingo-20161201' 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:
 - Support AArch64 in the 'annotate' code, native/local and
   cross-arch/remote (Kim Phillips)
 - Allow considering just events in a given time interval, via the
   '--time start.s.ms,end.s.ms' command line, added to 'perf kmem',
   'perf report', 'perf sched timehist' and 'perf script' (David Ahern)
 - Add option to stop printing a callchain at one of a given group of
   symbol names (David Ahern)
 - Handle CPU migration events in 'perf sched timehist' (David Ahern)
 - Track memory freed in 'perf kmem stat' (David Ahern)
Infrastructure:
 - Add initial support (and perf test entry) for tooling hooks, starting with
   'record_start' and 'record_end', that will have as its initial user the
   eBPF infrastructure, where perf_ prefixed functions will be JITed and
   run when such hooks are called (Wang Nan)
 - Remove redundant "test" and similar strings from 'perf test' descriptions
   (Arnaldo Carvalho de Melo)
 - Implement assorted libbpf improvements (Wang Nan)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/builtin-sched.c')
| -rw-r--r-- | tools/perf/builtin-sched.c | 148 | 
1 files changed, 140 insertions, 8 deletions
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index a49a032f5b15..870d94cd20ba 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -15,6 +15,7 @@  #include "util/color.h"  #include "util/stat.h"  #include "util/callchain.h" +#include "util/time-utils.h"  #include <subcmd/parse-options.h>  #include "util/trace-event.h" @@ -203,7 +204,10 @@ struct perf_sched {  	unsigned int	max_stack;  	bool		show_cpu_visual;  	bool		show_wakeups; +	bool		show_migrations;  	u64		skipped_samples; +	const char	*time_str; +	struct perf_time_interval ptime;  };  /* per thread run time data */ @@ -216,6 +220,8 @@ struct thread_runtime {  	struct stats run_stats;  	u64 total_run_time; + +	u64 migrations;  };  /* per event run time data */ @@ -1834,13 +1840,14 @@ static void timehist_header(struct perf_sched *sched)  static void timehist_print_sample(struct perf_sched *sched,  				  struct perf_sample *sample,  				  struct addr_location *al, -				  struct thread *thread) +				  struct thread *thread, +				  u64 t)  {  	struct thread_runtime *tr = thread__priv(thread);  	u32 max_cpus = sched->max_cpu + 1;  	char tstr[64]; -	timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr)); +	timestamp__scnprintf_usec(t, tstr, sizeof(tstr));  	printf("%15s [%04d] ", tstr, sample->cpu);  	if (sched->show_cpu_visual) { @@ -2191,12 +2198,94 @@ static int timehist_sched_wakeup_event(struct perf_tool *tool,  		tr->ready_to_run = sample->time;  	/* show wakeups if requested */ -	if (sched->show_wakeups) +	if (sched->show_wakeups && +	    !perf_time__skip_sample(&sched->ptime, sample->time))  		timehist_print_wakeup_event(sched, sample, machine, thread);  	return 0;  } +static void timehist_print_migration_event(struct perf_sched *sched, +					struct perf_evsel *evsel, +					struct perf_sample *sample, +					struct machine *machine, +					struct thread *migrated) +{ +	struct thread *thread; +	char tstr[64]; +	u32 max_cpus = sched->max_cpu + 1; +	u32 ocpu, dcpu; + +	if (sched->summary_only) +		return; + +	max_cpus = sched->max_cpu + 1; +	ocpu = perf_evsel__intval(evsel, sample, "orig_cpu"); +	dcpu = perf_evsel__intval(evsel, sample, "dest_cpu"); + +	thread = machine__findnew_thread(machine, sample->pid, sample->tid); +	if (thread == NULL) +		return; + +	if (timehist_skip_sample(sched, thread) && +	    timehist_skip_sample(sched, migrated)) { +		return; +	} + +	timestamp__scnprintf_usec(sample->time, tstr, sizeof(tstr)); +	printf("%15s [%04d] ", tstr, sample->cpu); + +	if (sched->show_cpu_visual) { +		u32 i; +		char c; + +		printf("  "); +		for (i = 0; i < max_cpus; ++i) { +			c = (i == sample->cpu) ? 'm' : ' '; +			printf("%c", c); +		} +		printf("  "); +	} + +	printf(" %-*s ", comm_width, timehist_get_commstr(thread)); + +	/* dt spacer */ +	printf("  %9s  %9s  %9s ", "", "", ""); + +	printf("migrated: %s", timehist_get_commstr(migrated)); +	printf(" cpu %d => %d", ocpu, dcpu); + +	printf("\n"); +} + +static int timehist_migrate_task_event(struct perf_tool *tool, +				       union perf_event *event __maybe_unused, +				       struct perf_evsel *evsel, +				       struct perf_sample *sample, +				       struct machine *machine) +{ +	struct perf_sched *sched = container_of(tool, struct perf_sched, tool); +	struct thread *thread; +	struct thread_runtime *tr = NULL; +	/* want pid of migrated task not pid in sample */ +	const u32 pid = perf_evsel__intval(evsel, sample, "pid"); + +	thread = machine__findnew_thread(machine, 0, pid); +	if (thread == NULL) +		return -1; + +	tr = thread__get_runtime(thread); +	if (tr == NULL) +		return -1; + +	tr->migrations++; + +	/* show migrations if requested */ +	timehist_print_migration_event(sched, evsel, sample, machine, thread); + +	return 0; +} +  static int timehist_sched_change_event(struct perf_tool *tool,  				       union perf_event *event,  				       struct perf_evsel *evsel, @@ -2204,10 +2293,11 @@ static int timehist_sched_change_event(struct perf_tool *tool,  				       struct machine *machine)  {  	struct perf_sched *sched = container_of(tool, struct perf_sched, tool); +	struct perf_time_interval *ptime = &sched->ptime;  	struct addr_location al;  	struct thread *thread;  	struct thread_runtime *tr = NULL; -	u64 tprev; +	u64 tprev, t = sample->time;  	int rc = 0;  	if (machine__resolve(machine, &al, sample) < 0) { @@ -2234,9 +2324,35 @@ static int timehist_sched_change_event(struct perf_tool *tool,  	tprev = perf_evsel__get_time(evsel, sample->cpu); -	timehist_update_runtime_stats(tr, sample->time, tprev); +	/* +	 * If start time given: +	 * - sample time is under window user cares about - skip sample +	 * - tprev is under window user cares about  - reset to start of window +	 */ +	if (ptime->start && ptime->start > t) +		goto out; + +	if (ptime->start > tprev) +		tprev = ptime->start; + +	/* +	 * If end time given: +	 * - previous sched event is out of window - we are done +	 * - sample time is beyond window user cares about - reset it +	 *   to close out stats for time window interest +	 */ +	if (ptime->end) { +		if (tprev > ptime->end) +			goto out; + +		if (t > ptime->end) +			t = ptime->end; +	} + +	timehist_update_runtime_stats(tr, t, tprev); +  	if (!sched->summary_only) -		timehist_print_sample(sched, sample, &al, thread); +		timehist_print_sample(sched, sample, &al, thread, t);  out:  	if (tr) { @@ -2295,6 +2411,7 @@ static void print_thread_runtime(struct thread *t,  	print_sched_time(r->run_stats.max, 6);  	printf("  ");  	printf("%5.2f", stddev); +	printf("   %5" PRIu64, r->migrations);  	printf("\n");  } @@ -2356,10 +2473,10 @@ static void timehist_print_summary(struct perf_sched *sched,  	printf("\nRuntime summary\n");  	printf("%*s  parent   sched-in  ", comm_width, "comm"); -	printf("   run-time    min-run     avg-run     max-run  stddev\n"); +	printf("   run-time    min-run     avg-run     max-run  stddev  migrations\n");  	printf("%*s            (count)  ", comm_width, "");  	printf("     (msec)     (msec)      (msec)      (msec)       %%\n"); -	printf("%.105s\n", graph_dotted_line); +	printf("%.117s\n", graph_dotted_line);  	machine__for_each_thread(m, show_thread_runtime, &totals);  	task_count = totals.task_count; @@ -2460,6 +2577,9 @@ static int perf_sched__timehist(struct perf_sched *sched)  		{ "sched:sched_wakeup",	      timehist_sched_wakeup_event, },  		{ "sched:sched_wakeup_new",   timehist_sched_wakeup_event, },  	}; +	const struct perf_evsel_str_handler migrate_handlers[] = { +		{ "sched:sched_migrate_task", timehist_migrate_task_event, }, +	};  	struct perf_data_file file = {  		.path = input_name,  		.mode = PERF_DATA_MODE_READ, @@ -2495,6 +2615,11 @@ static int perf_sched__timehist(struct perf_sched *sched)  	symbol__init(&session->header.env); +	if (perf_time__parse_str(&sched->ptime, sched->time_str) != 0) { +		pr_err("Invalid time string\n"); +		return -EINVAL; +	} +  	if (timehist_check_attr(sched, evlist) != 0)  		goto out; @@ -2507,6 +2632,10 @@ static int perf_sched__timehist(struct perf_sched *sched)  	if (!perf_session__has_traces(session, "record -R"))  		goto out; +	if (sched->show_migrations && +	    perf_session__set_tracepoints_handlers(session, migrate_handlers)) +		goto out; +  	/* pre-allocate struct for per-CPU idle stats */  	sched->max_cpu = session->header.env.nr_cpus_online;  	if (sched->max_cpu == 0) @@ -2903,7 +3032,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)  	OPT_BOOLEAN('S', "with-summary", &sched.summary,  		    "Show all syscalls and summary with statistics"),  	OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"), +	OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"),  	OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"), +	OPT_STRING(0, "time", &sched.time_str, "str", +		   "Time span for analysis (start,stop)"),  	OPT_PARENT(sched_options)  	};  | 
