aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-inject.c
diff options
context:
space:
mode:
authorAndrew Vagin <avagin@openvz.org>2012-08-07 08:56:04 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2012-10-26 09:22:25 -0400
commit26a031e136f4f8dc82c64df48cca0eb3b5d3eb4f (patch)
tree539d505f3a84f64cc430f87a40205be11c3c93af /tools/perf/builtin-inject.c
parente558a5bd8b74aff4690a8c55b08a1dc91ef50d7c (diff)
perf inject: Merge sched_stat_* and sched_switch events
You may want to know where and how long a task is sleeping. A callchain may be found in sched_switch and a time slice in stat_iowait, so I add handler in perf inject for merging this events. My code saves sched_switch event for each process and when it meets stat_iowait, it reports the sched_switch event, because this event contains a correct callchain. By another words it replaces all stat_iowait events on proper sched_switch events. I use the next sequence of commands for testing: perf record -e sched:sched_stat_sleep -e sched:sched_switch \ -e sched:sched_process_exit -g -o ~/perf.data.raw \ ~/test-program perf inject -v -s -i ~/perf.data.raw -o ~/perf.data perf report --stdio -i ~/perf.data 100.00% foo [kernel.kallsyms] [k] __schedule | --- __schedule schedule | |--79.75%-- schedule_hrtimeout_range_clock | schedule_hrtimeout_range | poll_schedule_timeout | do_select | core_sys_select | sys_select | system_call_fastpath | __select | __libc_start_main | --20.25%-- do_nanosleep hrtimer_nanosleep sys_nanosleep system_call_fastpath __GI___libc_nanosleep __libc_start_main And here is test-program.c: #include<unistd.h> #include<time.h> #include<sys/select.h> int main() { struct timespec ts1; struct timeval tv1; int i; long s; for (i = 0; i < 10; i++) { ts1.tv_sec = 0; ts1.tv_nsec = 10000000; nanosleep(&ts1, NULL); tv1.tv_sec = 0; tv1.tv_usec = 40000; select(0, NULL, NULL, NULL,&tv1); } return 1; } Signed-off-by: Andrew Vagin <avagin@openvz.org> Acked-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1344344165-369636-4-git-send-email-avagin@openvz.org [ committer note: Made it use evsel->handler ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-inject.c')
-rw-r--r--tools/perf/builtin-inject.c142
1 files changed, 139 insertions, 3 deletions
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index a706ed57f94e..a4a307258fa3 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -8,19 +8,32 @@
8#include "builtin.h" 8#include "builtin.h"
9 9
10#include "perf.h" 10#include "perf.h"
11#include "util/color.h"
12#include "util/evlist.h"
13#include "util/evsel.h"
11#include "util/session.h" 14#include "util/session.h"
12#include "util/tool.h" 15#include "util/tool.h"
13#include "util/debug.h" 16#include "util/debug.h"
14 17
15#include "util/parse-options.h" 18#include "util/parse-options.h"
16 19
20#include <linux/list.h>
21
17struct perf_inject { 22struct perf_inject {
18 struct perf_tool tool; 23 struct perf_tool tool;
19 bool build_ids; 24 bool build_ids;
25 bool sched_stat;
20 const char *input_name; 26 const char *input_name;
21 int pipe_output, 27 int pipe_output,
22 output; 28 output;
23 u64 bytes_written; 29 u64 bytes_written;
30 struct list_head samples;
31};
32
33struct event_entry {
34 struct list_head node;
35 u32 tid;
36 union perf_event event[0];
24}; 37};
25 38
26static int perf_event__repipe_synth(struct perf_tool *tool, 39static int perf_event__repipe_synth(struct perf_tool *tool,
@@ -86,12 +99,23 @@ static int perf_event__repipe(struct perf_tool *tool,
86 return perf_event__repipe_synth(tool, event, machine); 99 return perf_event__repipe_synth(tool, event, machine);
87} 100}
88 101
102typedef int (*inject_handler)(struct perf_tool *tool,
103 union perf_event *event,
104 struct perf_sample *sample,
105 struct perf_evsel *evsel,
106 struct machine *machine);
107
89static int perf_event__repipe_sample(struct perf_tool *tool, 108static int perf_event__repipe_sample(struct perf_tool *tool,
90 union perf_event *event, 109 union perf_event *event,
91 struct perf_sample *sample __maybe_unused, 110 struct perf_sample *sample,
92 struct perf_evsel *evsel __maybe_unused, 111 struct perf_evsel *evsel,
93 struct machine *machine) 112 struct machine *machine)
94{ 113{
114 if (evsel->handler.func) {
115 inject_handler f = evsel->handler.func;
116 return f(tool, event, sample, evsel, machine);
117 }
118
95 return perf_event__repipe_synth(tool, event, machine); 119 return perf_event__repipe_synth(tool, event, machine);
96} 120}
97 121
@@ -216,6 +240,79 @@ repipe:
216 return 0; 240 return 0;
217} 241}
218 242
243static int perf_inject__sched_process_exit(struct perf_tool *tool,
244 union perf_event *event __maybe_unused,
245 struct perf_sample *sample,
246 struct perf_evsel *evsel __maybe_unused,
247 struct machine *machine __maybe_unused)
248{
249 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
250 struct event_entry *ent;
251
252 list_for_each_entry(ent, &inject->samples, node) {
253 if (sample->tid == ent->tid) {
254 list_del_init(&ent->node);
255 free(ent);
256 break;
257 }
258 }
259
260 return 0;
261}
262
263static int perf_inject__sched_switch(struct perf_tool *tool,
264 union perf_event *event,
265 struct perf_sample *sample,
266 struct perf_evsel *evsel,
267 struct machine *machine)
268{
269 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
270 struct event_entry *ent;
271
272 perf_inject__sched_process_exit(tool, event, sample, evsel, machine);
273
274 ent = malloc(event->header.size + sizeof(struct event_entry));
275 if (ent == NULL) {
276 color_fprintf(stderr, PERF_COLOR_RED,
277 "Not enough memory to process sched switch event!");
278 return -1;
279 }
280
281 ent->tid = sample->tid;
282 memcpy(&ent->event, event, event->header.size);
283 list_add(&ent->node, &inject->samples);
284 return 0;
285}
286
287static int perf_inject__sched_stat(struct perf_tool *tool,
288 union perf_event *event __maybe_unused,
289 struct perf_sample *sample,
290 struct perf_evsel *evsel,
291 struct machine *machine)
292{
293 struct event_entry *ent;
294 union perf_event *event_sw;
295 struct perf_sample sample_sw;
296 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
297 u32 pid = perf_evsel__intval(evsel, sample, "pid");
298
299 list_for_each_entry(ent, &inject->samples, node) {
300 if (pid == ent->tid)
301 goto found;
302 }
303
304 return 0;
305found:
306 event_sw = &ent->event[0];
307 perf_evsel__parse_sample(evsel, event_sw, &sample_sw);
308
309 sample_sw.period = sample->period;
310 sample_sw.time = sample->time;
311 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
312 &sample_sw, false);
313 return perf_event__repipe(tool, event_sw, &sample_sw, machine);
314}
315
219extern volatile int session_done; 316extern volatile int session_done;
220 317
221static void sig_handler(int sig __maybe_unused) 318static void sig_handler(int sig __maybe_unused)
@@ -223,6 +320,21 @@ static void sig_handler(int sig __maybe_unused)
223 session_done = 1; 320 session_done = 1;
224} 321}
225 322
323static int perf_evsel__check_stype(struct perf_evsel *evsel,
324 u64 sample_type, const char *sample_msg)
325{
326 struct perf_event_attr *attr = &evsel->attr;
327 const char *name = perf_evsel__name(evsel);
328
329 if (!(attr->sample_type & sample_type)) {
330 pr_err("Samples for %s event do not have %s attribute set.",
331 name, sample_msg);
332 return -EINVAL;
333 }
334
335 return 0;
336}
337
226static int __cmd_inject(struct perf_inject *inject) 338static int __cmd_inject(struct perf_inject *inject)
227{ 339{
228 struct perf_session *session; 340 struct perf_session *session;
@@ -241,6 +353,26 @@ static int __cmd_inject(struct perf_inject *inject)
241 if (session == NULL) 353 if (session == NULL)
242 return -ENOMEM; 354 return -ENOMEM;
243 355
356 if (inject->sched_stat) {
357 struct perf_evsel *evsel;
358
359 inject->tool.ordered_samples = true;
360
361 list_for_each_entry(evsel, &session->evlist->entries, node) {
362 const char *name = perf_evsel__name(evsel);
363
364 if (!strcmp(name, "sched:sched_switch")) {
365 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
366 return -EINVAL;
367
368 evsel->handler.func = perf_inject__sched_switch;
369 } else if (!strcmp(name, "sched:sched_process_exit"))
370 evsel->handler.func = perf_inject__sched_process_exit;
371 else if (!strncmp(name, "sched:sched_stat_", 17))
372 evsel->handler.func = perf_inject__sched_stat;
373 }
374 }
375
244 if (!inject->pipe_output) 376 if (!inject->pipe_output)
245 lseek(inject->output, session->header.data_offset, SEEK_SET); 377 lseek(inject->output, session->header.data_offset, SEEK_SET);
246 378
@@ -275,6 +407,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
275 .build_id = perf_event__repipe_op2_synth, 407 .build_id = perf_event__repipe_op2_synth,
276 }, 408 },
277 .input_name = "-", 409 .input_name = "-",
410 .samples = LIST_HEAD_INIT(inject.samples),
278 }; 411 };
279 const char *output_name = "-"; 412 const char *output_name = "-";
280 const struct option options[] = { 413 const struct option options[] = {
@@ -284,6 +417,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
284 "input file name"), 417 "input file name"),
285 OPT_STRING('o', "output", &output_name, "file", 418 OPT_STRING('o', "output", &output_name, "file",
286 "output file name"), 419 "output file name"),
420 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
421 "Merge sched-stat and sched-switch for getting events "
422 "where and how long tasks slept"),
287 OPT_INCR('v', "verbose", &verbose, 423 OPT_INCR('v', "verbose", &verbose,
288 "be more verbose (show build ids, etc)"), 424 "be more verbose (show build ids, etc)"),
289 OPT_END() 425 OPT_END()