Skip to content

Commit 9f6f941

Browse files
author
Ingo Molnar
committed
Merge tag 'perf-core-for-mingo-4.11-20170117' 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: - Account thread wait time (off CPU time) separately: sleep, iowait and preempt, based on the prev_state of the last event, show the breakdown when using "perf sched timehist --state" (Namhyumg Kim) Infrastructure changes: - Factor out PMU scale conversion code (Andi Kleen) - Remove unnecessary feature-dwarf warning (David Carrillo-Cisneros) - Add missing member name in OPT_() macros (Soramichi AKIYAMA) - Move variables referenced in libperf.a object files from perf's main() file, so that other tools can use libperf.a with a different main() (Soramichi AKIYAMA) Documentation changes: - Fix 'perf script' man page about --dump-raw-trace option (Michael Petlan) - Also allow forcing reading of non-root owned files by root in 'perf script' (Yannick Brosseau) Signed-off-by: Arnaldo Carvalho de Melo <[email protected]> Signed-off-by: Ingo Molnar <[email protected]>
2 parents 5b48562 + d94386f commit 9f6f941

File tree

13 files changed

+177
-60
lines changed

13 files changed

+177
-60
lines changed

tools/lib/subcmd/parse-options.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,32 +133,32 @@ struct option {
133133
#define OPT_UINTEGER(s, l, v, h) { .type = OPTION_UINTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h) }
134134
#define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) }
135135
#define OPT_U64(s, l, v, h) { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) }
136-
#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h) }
136+
#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), .argh = (a), .help = (h) }
137137
#define OPT_STRING_OPTARG(s, l, v, a, h, d) \
138138
{ .type = OPTION_STRING, .short_name = (s), .long_name = (l), \
139-
.value = check_vtype(v, const char **), (a), .help = (h), \
139+
.value = check_vtype(v, const char **), .argh =(a), .help = (h), \
140140
.flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d) }
141141
#define OPT_STRING_OPTARG_SET(s, l, v, os, a, h, d) \
142142
{ .type = OPTION_STRING, .short_name = (s), .long_name = (l), \
143-
.value = check_vtype(v, const char **), (a), .help = (h), \
143+
.value = check_vtype(v, const char **), .argh = (a), .help = (h), \
144144
.flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d), \
145145
.set = check_vtype(os, bool *)}
146-
#define OPT_STRING_NOEMPTY(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h), .flags = PARSE_OPT_NOEMPTY}
146+
#define OPT_STRING_NOEMPTY(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), .argh = (a), .help = (h), .flags = PARSE_OPT_NOEMPTY}
147147
#define OPT_DATE(s, l, v, h) \
148148
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
149149
#define OPT_CALLBACK(s, l, v, a, h, f) \
150-
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f) }
150+
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f) }
151151
#define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \
152-
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG }
152+
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG }
153153
#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
154-
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
154+
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
155155
#define OPT_CALLBACK_DEFAULT_NOOPT(s, l, v, a, h, f, d) \
156156
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\
157-
.value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
157+
.value = (v), .arg = (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
158158
.flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG}
159159
#define OPT_CALLBACK_OPTARG(s, l, v, d, a, h, f) \
160160
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \
161-
.value = (v), (a), .help = (h), .callback = (f), \
161+
.value = (v), .argh = (a), .help = (h), .callback = (f), \
162162
.flags = PARSE_OPT_OPTARG, .data = (d) }
163163

164164
/* parse_options() will filter out the processed options and leave the

tools/perf/Build

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ CFLAGS_builtin-help.o += $(paths)
4040
CFLAGS_builtin-timechart.o += $(paths)
4141
CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" \
4242
-DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" \
43-
-DPREFIX="BUILD_STR($(prefix_SQ))" \
44-
-include $(OUTPUT)PERF-VERSION-FILE
43+
-DPREFIX="BUILD_STR($(prefix_SQ))"
4544
CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))"
4645
CFLAGS_builtin-report.o += -DTIPDIR="BUILD_STR($(tipdir_SQ))"
4746
CFLAGS_builtin-report.o += -DDOCDIR="BUILD_STR($(srcdir_SQ)/Documentation)"

tools/perf/Documentation/perf-sched.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ OPTIONS for 'perf sched timehist'
143143
stop time is not given (i.e, time string is 'x.y,') then analysis goes
144144
to end of file.
145145

146+
--state::
147+
Show task state when it switched out.
146148

147149
SEE ALSO
148150
--------

tools/perf/Documentation/perf-script.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ There are several variants of perf script:
3636

3737
'perf script report <script> [args]' to run and display the results
3838
of <script>. <script> is the name displayed in the output of 'perf
39-
trace --list' i.e. the actual script name minus any language
39+
script --list' i.e. the actual script name minus any language
4040
extension. The perf.data output from a previous run of 'perf script
4141
record <script>' is used and should be present for this command to
4242
succeed. [args] refers to the (mainly optional) args expected by
@@ -76,7 +76,7 @@ OPTIONS
7676
Any command you can specify in a shell.
7777

7878
-D::
79-
--dump-raw-script=::
79+
--dump-raw-trace=::
8080
Display verbose dump of the trace data.
8181

8282
-L::

tools/perf/Makefile.config

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,10 @@ else
291291
endif
292292
endif
293293
ifneq ($(feature-dwarf), 1)
294-
msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
295-
NO_DWARF := 1
294+
ifndef NO_DWARF
295+
msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
296+
NO_DWARF := 1
297+
endif
296298
else
297299
ifneq ($(feature-dwarf_getlocations), 1)
298300
msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157);

tools/perf/builtin-sched.c

Lines changed: 118 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,22 @@ struct sched_atom {
7777

7878
#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKWP"
7979

80+
/* task state bitmask, copied from include/linux/sched.h */
81+
#define TASK_RUNNING 0
82+
#define TASK_INTERRUPTIBLE 1
83+
#define TASK_UNINTERRUPTIBLE 2
84+
#define __TASK_STOPPED 4
85+
#define __TASK_TRACED 8
86+
/* in tsk->exit_state */
87+
#define EXIT_DEAD 16
88+
#define EXIT_ZOMBIE 32
89+
#define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)
90+
/* in tsk->state again */
91+
#define TASK_DEAD 64
92+
#define TASK_WAKEKILL 128
93+
#define TASK_WAKING 256
94+
#define TASK_PARKED 512
95+
8096
enum thread_state {
8197
THREAD_SLEEPING = 0,
8298
THREAD_WAIT_CPU,
@@ -206,6 +222,7 @@ struct perf_sched {
206222
bool show_cpu_visual;
207223
bool show_wakeups;
208224
bool show_migrations;
225+
bool show_state;
209226
u64 skipped_samples;
210227
const char *time_str;
211228
struct perf_time_interval ptime;
@@ -216,13 +233,20 @@ struct perf_sched {
216233
struct thread_runtime {
217234
u64 last_time; /* time of previous sched in/out event */
218235
u64 dt_run; /* run time */
219-
u64 dt_wait; /* time between CPU access (off cpu) */
236+
u64 dt_sleep; /* time between CPU access by sleep (off cpu) */
237+
u64 dt_iowait; /* time between CPU access by iowait (off cpu) */
238+
u64 dt_preempt; /* time between CPU access by preempt (off cpu) */
220239
u64 dt_delay; /* time between wakeup and sched-in */
221240
u64 ready_to_run; /* time of wakeup */
222241

223242
struct stats run_stats;
224243
u64 total_run_time;
244+
u64 total_sleep_time;
245+
u64 total_iowait_time;
246+
u64 total_preempt_time;
247+
u64 total_delay_time;
225248

249+
int last_state;
226250
u64 migrations;
227251
};
228252

@@ -1821,6 +1845,9 @@ static void timehist_header(struct perf_sched *sched)
18211845
printf(" %-*s %9s %9s %9s", comm_width,
18221846
"task name", "wait time", "sch delay", "run time");
18231847

1848+
if (sched->show_state)
1849+
printf(" %s", "state");
1850+
18241851
printf("\n");
18251852

18261853
/*
@@ -1831,9 +1858,14 @@ static void timehist_header(struct perf_sched *sched)
18311858
if (sched->show_cpu_visual)
18321859
printf(" %*s ", ncpus, "");
18331860

1834-
printf(" %-*s %9s %9s %9s\n", comm_width,
1861+
printf(" %-*s %9s %9s %9s", comm_width,
18351862
"[tid/pid]", "(msec)", "(msec)", "(msec)");
18361863

1864+
if (sched->show_state)
1865+
printf(" %5s", "");
1866+
1867+
printf("\n");
1868+
18371869
/*
18381870
* separator
18391871
*/
@@ -1846,18 +1878,34 @@ static void timehist_header(struct perf_sched *sched)
18461878
graph_dotted_line, graph_dotted_line, graph_dotted_line,
18471879
graph_dotted_line);
18481880

1881+
if (sched->show_state)
1882+
printf(" %.5s", graph_dotted_line);
1883+
18491884
printf("\n");
18501885
}
18511886

1887+
static char task_state_char(struct thread *thread, int state)
1888+
{
1889+
static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;
1890+
unsigned bit = state ? ffs(state) : 0;
1891+
1892+
/* 'I' for idle */
1893+
if (thread->tid == 0)
1894+
return 'I';
1895+
1896+
return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?';
1897+
}
1898+
18521899
static void timehist_print_sample(struct perf_sched *sched,
18531900
struct perf_sample *sample,
18541901
struct addr_location *al,
18551902
struct thread *thread,
1856-
u64 t)
1903+
u64 t, int state)
18571904
{
18581905
struct thread_runtime *tr = thread__priv(thread);
18591906
u32 max_cpus = sched->max_cpu + 1;
18601907
char tstr[64];
1908+
u64 wait_time;
18611909

18621910
timestamp__scnprintf_usec(t, tstr, sizeof(tstr));
18631911
printf("%15s [%04d] ", tstr, sample->cpu);
@@ -1880,10 +1928,15 @@ static void timehist_print_sample(struct perf_sched *sched,
18801928

18811929
printf(" %-*s ", comm_width, timehist_get_commstr(thread));
18821930

1883-
print_sched_time(tr->dt_wait, 6);
1931+
wait_time = tr->dt_sleep + tr->dt_iowait + tr->dt_preempt;
1932+
print_sched_time(wait_time, 6);
1933+
18841934
print_sched_time(tr->dt_delay, 6);
18851935
print_sched_time(tr->dt_run, 6);
18861936

1937+
if (sched->show_state)
1938+
printf(" %5c ", task_state_char(thread, state));
1939+
18871940
if (sched->show_wakeups)
18881941
printf(" %-*s", comm_width, "");
18891942

@@ -1930,8 +1983,11 @@ static void timehist_update_runtime_stats(struct thread_runtime *r,
19301983
u64 t, u64 tprev)
19311984
{
19321985
r->dt_delay = 0;
1933-
r->dt_wait = 0;
1986+
r->dt_sleep = 0;
1987+
r->dt_iowait = 0;
1988+
r->dt_preempt = 0;
19341989
r->dt_run = 0;
1990+
19351991
if (tprev) {
19361992
r->dt_run = t - tprev;
19371993
if (r->ready_to_run) {
@@ -1943,12 +1999,25 @@ static void timehist_update_runtime_stats(struct thread_runtime *r,
19431999

19442000
if (r->last_time > tprev)
19452001
pr_debug("time travel: last sched out time for task > previous sched_switch event\n");
1946-
else if (r->last_time)
1947-
r->dt_wait = tprev - r->last_time;
2002+
else if (r->last_time) {
2003+
u64 dt_wait = tprev - r->last_time;
2004+
2005+
if (r->last_state == TASK_RUNNING)
2006+
r->dt_preempt = dt_wait;
2007+
else if (r->last_state == TASK_UNINTERRUPTIBLE)
2008+
r->dt_iowait = dt_wait;
2009+
else
2010+
r->dt_sleep = dt_wait;
2011+
}
19482012
}
19492013

19502014
update_stats(&r->run_stats, r->dt_run);
1951-
r->total_run_time += r->dt_run;
2015+
2016+
r->total_run_time += r->dt_run;
2017+
r->total_delay_time += r->dt_delay;
2018+
r->total_sleep_time += r->dt_sleep;
2019+
r->total_iowait_time += r->dt_iowait;
2020+
r->total_preempt_time += r->dt_preempt;
19522021
}
19532022

19542023
static bool is_idle_sample(struct perf_sample *sample,
@@ -2373,6 +2442,8 @@ static int timehist_sched_change_event(struct perf_tool *tool,
23732442
struct thread_runtime *tr = NULL;
23742443
u64 tprev, t = sample->time;
23752444
int rc = 0;
2445+
int state = perf_evsel__intval(evsel, sample, "prev_state");
2446+
23762447

23772448
if (machine__resolve(machine, &al, sample) < 0) {
23782449
pr_err("problem processing %d event. skipping it\n",
@@ -2447,8 +2518,10 @@ static int timehist_sched_change_event(struct perf_tool *tool,
24472518
* time. we only care total run time and run stat.
24482519
*/
24492520
last_tr->dt_run = 0;
2450-
last_tr->dt_wait = 0;
24512521
last_tr->dt_delay = 0;
2522+
last_tr->dt_sleep = 0;
2523+
last_tr->dt_iowait = 0;
2524+
last_tr->dt_preempt = 0;
24522525

24532526
if (itr->cursor.nr)
24542527
callchain_append(&itr->callchain, &itr->cursor, t - tprev);
@@ -2458,7 +2531,7 @@ static int timehist_sched_change_event(struct perf_tool *tool,
24582531
}
24592532

24602533
if (!sched->summary_only)
2461-
timehist_print_sample(sched, sample, &al, thread, t);
2534+
timehist_print_sample(sched, sample, &al, thread, t, state);
24622535

24632536
out:
24642537
if (sched->hist_time.start == 0 && t >= ptime->start)
@@ -2470,6 +2543,9 @@ static int timehist_sched_change_event(struct perf_tool *tool,
24702543
/* time of this sched_switch event becomes last time task seen */
24712544
tr->last_time = sample->time;
24722545

2546+
/* last state is used to determine where to account wait time */
2547+
tr->last_state = state;
2548+
24732549
/* sched out event for task so reset ready to run time */
24742550
tr->ready_to_run = 0;
24752551
}
@@ -2526,7 +2602,26 @@ static void print_thread_runtime(struct thread *t,
25262602
printf("\n");
25272603
}
25282604

2605+
static void print_thread_waittime(struct thread *t,
2606+
struct thread_runtime *r)
2607+
{
2608+
printf("%*s %5d %9" PRIu64 " ",
2609+
comm_width, timehist_get_commstr(t), t->ppid,
2610+
(u64) r->run_stats.n);
2611+
2612+
print_sched_time(r->total_run_time, 8);
2613+
print_sched_time(r->total_sleep_time, 6);
2614+
printf(" ");
2615+
print_sched_time(r->total_iowait_time, 6);
2616+
printf(" ");
2617+
print_sched_time(r->total_preempt_time, 6);
2618+
printf(" ");
2619+
print_sched_time(r->total_delay_time, 6);
2620+
printf("\n");
2621+
}
2622+
25292623
struct total_run_stats {
2624+
struct perf_sched *sched;
25302625
u64 sched_count;
25312626
u64 task_count;
25322627
u64 total_run_time;
@@ -2545,7 +2640,11 @@ static int __show_thread_runtime(struct thread *t, void *priv)
25452640
stats->task_count++;
25462641
stats->sched_count += r->run_stats.n;
25472642
stats->total_run_time += r->total_run_time;
2548-
print_thread_runtime(t, r);
2643+
2644+
if (stats->sched->show_state)
2645+
print_thread_waittime(t, r);
2646+
else
2647+
print_thread_runtime(t, r);
25492648
}
25502649

25512650
return 0;
@@ -2633,18 +2732,24 @@ static void timehist_print_summary(struct perf_sched *sched,
26332732
u64 hist_time = sched->hist_time.end - sched->hist_time.start;
26342733

26352734
memset(&totals, 0, sizeof(totals));
2735+
totals.sched = sched;
26362736

26372737
if (sched->idle_hist) {
26382738
printf("\nIdle-time summary\n");
26392739
printf("%*s parent sched-out ", comm_width, "comm");
26402740
printf(" idle-time min-idle avg-idle max-idle stddev migrations\n");
2741+
} else if (sched->show_state) {
2742+
printf("\nWait-time summary\n");
2743+
printf("%*s parent sched-in ", comm_width, "comm");
2744+
printf(" run-time sleep iowait preempt delay\n");
26412745
} else {
26422746
printf("\nRuntime summary\n");
26432747
printf("%*s parent sched-in ", comm_width, "comm");
26442748
printf(" run-time min-run avg-run max-run stddev migrations\n");
26452749
}
26462750
printf("%*s (count) ", comm_width, "");
2647-
printf(" (msec) (msec) (msec) (msec) %%\n");
2751+
printf(" (msec) (msec) (msec) (msec) %s\n",
2752+
sched->show_state ? "(msec)" : "%");
26482753
printf("%.117s\n", graph_dotted_line);
26492754

26502755
machine__for_each_thread(m, show_thread_runtime, &totals);
@@ -3240,6 +3345,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
32403345
OPT_BOOLEAN('I', "idle-hist", &sched.idle_hist, "Show idle events only"),
32413346
OPT_STRING(0, "time", &sched.time_str, "str",
32423347
"Time span for analysis (start,stop)"),
3348+
OPT_BOOLEAN(0, "state", &sched.show_state, "Show task state when sched-out"),
32433349
OPT_PARENT(sched_options)
32443350
};
32453351

tools/perf/builtin-script.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2180,7 +2180,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
21802180
"Show the mmap events"),
21812181
OPT_BOOLEAN('\0', "show-switch-events", &script.show_switch_events,
21822182
"Show context switch events (if recorded)"),
2183-
OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
2183+
OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
21842184
OPT_BOOLEAN(0, "ns", &nanosecs,
21852185
"Use 9 decimal places when displaying time"),
21862186
OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
@@ -2212,6 +2212,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
22122212
PARSE_OPT_STOP_AT_NON_OPTION);
22132213

22142214
file.path = input_name;
2215+
file.force = symbol_conf.force;
22152216

22162217
if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
22172218
rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);

0 commit comments

Comments
 (0)