aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2010-02-17 15:35:56 -0500
committerSteven Rostedt <rostedt@goodmis.org>2010-02-17 15:35:56 -0500
commit85da60357f4b515af1c7be362cf0465f65672fd6 (patch)
treedb68bdbd6d4fdb09c860e1f3c11410b7d4dae359
parent4991c35c3bab5e000917ad41a0277008f18c4ab3 (diff)
trace-cmd: Add trace-cmd read -w to show wakeup latencies
Add the -w option to trace-cmd read to record and display wakeup latencies. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--trace-cmd.c1
-rw-r--r--trace-hash-local.h52
-rw-r--r--trace-hash.c28
-rw-r--r--trace-hash.h3
-rw-r--r--trace-read.c207
5 files changed, 260 insertions, 31 deletions
diff --git a/trace-cmd.c b/trace-cmd.c
index c8e507a..d91e212 100644
--- a/trace-cmd.c
+++ b/trace-cmd.c
@@ -1043,6 +1043,7 @@ void usage(char **argv)
1043 " -E show event files stored\n" 1043 " -E show event files stored\n"
1044 " -F filter to filter output on\n" 1044 " -F filter to filter output on\n"
1045 " -v will negate all -F after it (Not show matches)\n" 1045 " -v will negate all -F after it (Not show matches)\n"
1046 " -w show wakeup latencies\n"
1046 " -l show latency format (default with latency tracers)\n" 1047 " -l show latency format (default with latency tracers)\n"
1047 "\n" 1048 "\n"
1048 " %s split [options] -o file [start [end]]\n" 1049 " %s split [options] -o file [start [end]]\n"
diff --git a/trace-hash-local.h b/trace-hash-local.h
new file mode 100644
index 0000000..9ddd5ae
--- /dev/null
+++ b/trace-hash-local.h
@@ -0,0 +1,52 @@
1/*
2 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#ifndef _TRACE_HASH_LOCAL_H
22#define _TRACE_HASH_LOCAL_H
23
24static inline unsigned int trace_hash(int val)
25{
26 int hash, tmp;
27
28 hash = 12546869; /* random prime */
29
30 /*
31 * The following hash is based off of Paul Hsieh's super fast hash:
32 * http://www.azillionmonkeys.com/qed/hash.html
33 * Note, he released this code unde the GPL 2.0 license, which
34 * is the same as the license for the programs that use it here.
35 */
36
37 hash += (val & 0xffff);
38 tmp = (val >> 16) ^ hash;
39 hash = (hash << 16) ^ tmp;
40 hash += hash >> 11;
41
42 hash ^= hash << 3;
43 hash += hash >> 5;
44 hash ^= hash << 4;
45 hash += hash >> 17;
46 hash ^= hash << 25;
47 hash += hash >> 6;
48
49 return hash;
50}
51
52#endif /* _TRACE_HASH_LOCAL_H */
diff --git a/trace-hash.c b/trace-hash.c
index 93da360..1197913 100644
--- a/trace-hash.c
+++ b/trace-hash.c
@@ -26,34 +26,6 @@
26 26
27#define FILTER_TASK_HASH_SIZE 256 27#define FILTER_TASK_HASH_SIZE 256
28 28
29guint trace_hash(gint val)
30{
31 gint hash, tmp;
32
33 hash = 12546869; /* random prime */
34
35 /*
36 * The following hash is based off of Paul Hsieh's super fast hash:
37 * http://www.azillionmonkeys.com/qed/hash.html
38 * Note, he released this code unde the GPL 2.0 license, which
39 * is the same as the license for the programs that use it here.
40 */
41
42 hash += (val & 0xffff);
43 tmp = (val >> 16) ^ hash;
44 hash = (hash << 16) ^ tmp;
45 hash += hash >> 11;
46
47 hash ^= hash << 3;
48 hash += hash >> 5;
49 hash ^= hash << 4;
50 hash += hash >> 17;
51 hash ^= hash << 25;
52 hash += hash >> 6;
53
54 return hash;
55}
56
57struct filter_task_item * 29struct filter_task_item *
58filter_task_find_pid(struct filter_task *hash, gint pid) 30filter_task_find_pid(struct filter_task *hash, gint pid)
59{ 31{
diff --git a/trace-hash.h b/trace-hash.h
index b766073..1aaa828 100644
--- a/trace-hash.h
+++ b/trace-hash.h
@@ -22,6 +22,7 @@
22#define _TRACE_HASH_H 22#define _TRACE_HASH_H
23 23
24#include <glib.h> 24#include <glib.h>
25#include "trace-hash-local.h"
25 26
26struct filter_task_item { 27struct filter_task_item {
27 struct filter_task_item *next; 28 struct filter_task_item *next;
@@ -33,8 +34,6 @@ struct filter_task {
33 gint count; 34 gint count;
34}; 35};
35 36
36guint trace_hash(gint val);
37
38struct filter_task_item * 37struct filter_task_item *
39filter_task_find_pid(struct filter_task *hash, gint pid); 38filter_task_find_pid(struct filter_task *hash, gint pid);
40void filter_task_add_pid(struct filter_task *hash, gint pid); 39void filter_task_add_pid(struct filter_task *hash, gint pid);
diff --git a/trace-read.c b/trace-read.c
index ee56530..0a1fd0a 100644
--- a/trace-read.c
+++ b/trace-read.c
@@ -37,6 +37,7 @@
37#include <errno.h> 37#include <errno.h>
38 38
39#include "trace-local.h" 39#include "trace-local.h"
40#include "trace-hash-local.h"
40 41
41static struct filter { 42static struct filter {
42 struct filter *next; 43 struct filter *next;
@@ -54,6 +55,29 @@ const char *input_file = "trace.dat";
54 55
55static int filter_cpu = -1; 56static int filter_cpu = -1;
56 57
58static int show_wakeup;
59static int wakeup_id;
60static int wakeup_new_id;
61static int sched_id;
62
63static struct format_field *wakeup_task;
64static struct format_field *wakeup_success;
65static struct format_field *wakeup_new_task;
66static struct format_field *wakeup_new_success;
67static struct format_field *sched_task;
68
69static unsigned long long total_wakeup_lat;
70static unsigned long wakeup_lat_count;
71
72struct wakeup_info {
73 struct wakeup_info *next;
74 unsigned long long start;
75 int pid;
76};
77
78#define WAKEUP_HASH_SIZE 1024
79static struct wakeup_info *wakeup_hash[WAKEUP_HASH_SIZE];
80
57/* Debug variables for testing tracecmd_read_at */ 81/* Debug variables for testing tracecmd_read_at */
58#define TEST_READ_AT 0 82#define TEST_READ_AT 0
59#if TEST_READ_AT 83#if TEST_READ_AT
@@ -250,6 +274,178 @@ static int filter_record(struct tracecmd_input *handle,
250 return 0; 274 return 0;
251} 275}
252 276
277static void init_wakeup(struct tracecmd_input *handle)
278{
279 struct event_format *event;
280 struct pevent *pevent;
281
282 if (!show_wakeup)
283 return;
284
285 pevent = tracecmd_get_pevent(handle);
286
287 event = pevent_find_event_by_name(pevent, "sched", "sched_wakeup");
288 if (!event)
289 goto fail;
290 wakeup_id = event->id;
291 wakeup_task = pevent_find_field(event, "pid");
292 if (!wakeup_task)
293 goto fail;
294 wakeup_success = pevent_find_field(event, "success");
295 if (!wakeup_success)
296 goto fail;
297
298
299 event = pevent_find_event_by_name(pevent, "sched", "sched_switch");
300 if (!event)
301 goto fail;
302 sched_id = event->id;
303 sched_task = pevent_find_field(event, "next_pid");
304 if (!sched_task)
305 goto fail;
306
307
308 wakeup_new_id = -1;
309
310 event = pevent_find_event_by_name(pevent, "sched", "sched_wakeup_new");
311 if (!event)
312 goto skip;
313 wakeup_new_id = event->id;
314 wakeup_new_task = pevent_find_field(event, "pid");
315 if (!wakeup_new_task)
316 goto fail;
317 wakeup_new_success = pevent_find_field(event, "success");
318 if (!wakeup_new_success)
319 goto fail;
320
321 skip:
322 return;
323
324 fail:
325 show_wakeup = 0;
326}
327
328static unsigned int calc_wakeup_key(unsigned long val)
329{
330 return trace_hash(val) % WAKEUP_HASH_SIZE;
331}
332
333static struct wakeup_info *
334__find_wakeup(unsigned int key, unsigned int val)
335{
336 struct wakeup_info *info = wakeup_hash[key];
337
338 while (info) {
339 if (info->pid == val)
340 return info;
341 }
342
343 return NULL;
344}
345
346static void add_wakeup(unsigned int val, unsigned long long start)
347{
348 unsigned int key = calc_wakeup_key(val);
349 struct wakeup_info *info;
350
351 info = __find_wakeup(key, val);
352 if (info) {
353 /* Hmm, double wakeup? */
354 info->start = start;
355 return;
356 }
357
358 info = malloc_or_die(sizeof(*info));
359 info->pid = val;
360 info->start = start;
361 info->next = wakeup_hash[key];
362 wakeup_hash[key] = info;
363}
364
365static void add_sched(unsigned int val, unsigned long long end)
366{
367 unsigned int key = calc_wakeup_key(val);
368 struct wakeup_info *info;
369 struct wakeup_info **next;
370 unsigned long long cal;
371
372 info = __find_wakeup(key, val);
373 if (!info)
374 return;
375
376 cal = end - info->start;
377
378 printf(" Latency: %llu.%03llu usecs", cal / 1000, cal % 1000);
379
380 total_wakeup_lat += cal;
381 wakeup_lat_count++;
382
383 next = &wakeup_hash[key];
384 while (*next) {
385 if (*next == info) {
386 *next = info->next;
387 break;
388 }
389 next = &(*next)->next;
390 }
391 free(info);
392}
393
394static void process_wakeup(struct pevent *pevent, struct record *record)
395{
396 unsigned long long val;
397 int id;
398
399 if (!show_wakeup)
400 return;
401
402 id = pevent_data_type(pevent, record);
403 if (id == wakeup_id) {
404 if (pevent_read_number_field(wakeup_success, record->data, &val))
405 return;
406 if (!val)
407 return;
408 if (pevent_read_number_field(wakeup_task, record->data, &val))
409 return;
410 add_wakeup(val, record->ts);
411 } else if (id == wakeup_new_id) {
412 if (pevent_read_number_field(wakeup_new_success, record->data, &val))
413 return;
414 if (!val)
415 return;
416 if (pevent_read_number_field(wakeup_new_task, record->data, &val))
417 return;
418 add_wakeup(val, record->ts);
419 } else if (id == sched_id) {
420 if (pevent_read_number_field(sched_task, record->data, &val))
421 return;
422 add_sched(val, record->ts);
423 }
424}
425
426static void finish_wakeup(void)
427{
428 struct wakeup_info *info;
429 int i;
430
431 if (!show_wakeup || !wakeup_lat_count)
432 return;
433
434 total_wakeup_lat /= wakeup_lat_count;
435
436 printf("\nAverage wakeup latency: %llu.%03llu usecs\n\n",
437 total_wakeup_lat / 1000,
438 total_wakeup_lat % 1000);
439
440 for (i = 0; i < WAKEUP_HASH_SIZE; i++) {
441 while (wakeup_hash[i]) {
442 info = wakeup_hash[i];
443 wakeup_hash[i] = info->next;
444 free(info);
445 }
446 }
447}
448
253static void show_data(struct tracecmd_input *handle, 449static void show_data(struct tracecmd_input *handle,
254 struct record *record, int cpu) 450 struct record *record, int cpu)
255{ 451{
@@ -266,6 +462,9 @@ static void show_data(struct tracecmd_input *handle,
266 trace_seq_init(&s); 462 trace_seq_init(&s);
267 pevent_print_event(pevent, &s, record); 463 pevent_print_event(pevent, &s, record);
268 trace_seq_do_printf(&s); 464 trace_seq_do_printf(&s);
465
466 process_wakeup(pevent, record);
467
269 printf("\n"); 468 printf("\n");
270} 469}
271 470
@@ -305,6 +504,7 @@ static void read_data_info(struct tracecmd_input *handle)
305 return; 504 return;
306 } 505 }
307 506
507 init_wakeup(handle);
308 process_filters(handle); 508 process_filters(handle);
309 509
310 do { 510 do {
@@ -374,7 +574,7 @@ void trace_report (int argc, char **argv)
374 {NULL, 0, NULL, 0} 574 {NULL, 0, NULL, 0}
375 }; 575 };
376 576
377 c = getopt_long (argc-1, argv+1, "+hi:fepPlEF:v", 577 c = getopt_long (argc-1, argv+1, "+hi:fepPlEwF:v",
378 long_options, &option_index); 578 long_options, &option_index);
379 if (c == -1) 579 if (c == -1)
380 break; 580 break;
@@ -403,6 +603,9 @@ void trace_report (int argc, char **argv)
403 case 'E': 603 case 'E':
404 show_events = 1; 604 show_events = 1;
405 break; 605 break;
606 case 'w':
607 show_wakeup = 1;
608 break;
406 case 'l': 609 case 'l':
407 latency_format = 1; 610 latency_format = 1;
408 break; 611 break;
@@ -489,5 +692,7 @@ void trace_report (int argc, char **argv)
489 692
490 tracecmd_close(handle); 693 tracecmd_close(handle);
491 694
695 finish_wakeup();
696
492 return; 697 return;
493} 698}