aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/builtin-lock.c210
1 files changed, 82 insertions, 128 deletions
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 2b5f88754c26..fb9ab2ad3f92 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -32,37 +32,37 @@ static struct list_head lockhash_table[LOCKHASH_SIZE];
32#define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS) 32#define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS)
33#define lockhashentry(key) (lockhash_table + __lockhashfn((key))) 33#define lockhashentry(key) (lockhash_table + __lockhashfn((key)))
34 34
35#define LOCK_STATE_UNLOCKED 0 /* initial state */ 35#define LOCK_STATE_UNLOCKED 0 /* initial state */
36#define LOCK_STATE_LOCKED 1 36#define LOCK_STATE_LOCKED 1
37 37
38struct lock_stat { 38struct lock_stat {
39 struct list_head hash_entry; 39 struct list_head hash_entry;
40 struct rb_node rb; /* used for sorting */ 40 struct rb_node rb; /* used for sorting */
41 41
42 /* FIXME: raw_field_value() returns unsigned long long, 42 /*
43 * FIXME: raw_field_value() returns unsigned long long,
43 * so address of lockdep_map should be dealed as 64bit. 44 * so address of lockdep_map should be dealed as 64bit.
44 * Is there more better solution? */ 45 * Is there more better solution?
45 void *addr; /* address of lockdep_map, used as ID */ 46 */
46 char *name; /* for strcpy(), we cannot use const */ 47 void *addr; /* address of lockdep_map, used as ID */
47 char *file; 48 char *name; /* for strcpy(), we cannot use const */
48 unsigned int line;
49 49
50 int state; 50 int state;
51 u64 prev_event_time; /* timestamp of previous event */ 51 u64 prev_event_time; /* timestamp of previous event */
52 52
53 unsigned int nr_acquired; 53 unsigned int nr_acquired;
54 unsigned int nr_acquire; 54 unsigned int nr_acquire;
55 unsigned int nr_contended; 55 unsigned int nr_contended;
56 unsigned int nr_release; 56 unsigned int nr_release;
57 57
58 /* these times are in nano sec. */ 58 /* these times are in nano sec. */
59 u64 wait_time_total; 59 u64 wait_time_total;
60 u64 wait_time_min; 60 u64 wait_time_min;
61 u64 wait_time_max; 61 u64 wait_time_max;
62}; 62};
63 63
64/* build simple key function one is bigger than two */ 64/* build simple key function one is bigger than two */
65#define SINGLE_KEY(member) \ 65#define SINGLE_KEY(member) \
66 static int lock_stat_key_ ## member(struct lock_stat *one, \ 66 static int lock_stat_key_ ## member(struct lock_stat *one, \
67 struct lock_stat *two) \ 67 struct lock_stat *two) \
68 { \ 68 { \
@@ -81,12 +81,15 @@ struct lock_key {
81 * this should be simpler than raw name of member 81 * this should be simpler than raw name of member
82 * e.g. nr_acquired -> acquired, wait_time_total -> wait_total 82 * e.g. nr_acquired -> acquired, wait_time_total -> wait_total
83 */ 83 */
84 const char *name; 84 const char *name;
85 int (*key)(struct lock_stat*, struct lock_stat*); 85 int (*key)(struct lock_stat*, struct lock_stat*);
86}; 86};
87 87
88static const char *sort_key = "acquired"; 88static const char *sort_key = "acquired";
89static int (*compare)(struct lock_stat *, struct lock_stat *); 89
90static int (*compare)(struct lock_stat *, struct lock_stat *);
91
92static struct rb_root result; /* place to store sorted data */
90 93
91#define DEF_KEY_LOCK(name, fn_suffix) \ 94#define DEF_KEY_LOCK(name, fn_suffix) \
92 { #name, lock_stat_key_ ## fn_suffix } 95 { #name, lock_stat_key_ ## fn_suffix }
@@ -116,11 +119,8 @@ static void select_key(void)
116 die("Unknown compare key:%s\n", sort_key); 119 die("Unknown compare key:%s\n", sort_key);
117} 120}
118 121
119static struct rb_root result; /* place to store sorted data */
120
121static void insert_to_result(struct lock_stat *st, 122static void insert_to_result(struct lock_stat *st,
122 int (*bigger)(struct lock_stat *, 123 int (*bigger)(struct lock_stat *, struct lock_stat *))
123 struct lock_stat *))
124{ 124{
125 struct rb_node **rb = &result.rb_node; 125 struct rb_node **rb = &result.rb_node;
126 struct rb_node *parent = NULL; 126 struct rb_node *parent = NULL;
@@ -155,8 +155,7 @@ static struct lock_stat *pop_from_result(void)
155 return container_of(node, struct lock_stat, rb); 155 return container_of(node, struct lock_stat, rb);
156} 156}
157 157
158static struct lock_stat *lock_stat_findnew(void *addr, const char *name, 158static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
159 const char *file, unsigned int line)
160{ 159{
161 struct list_head *entry = lockhashentry(addr); 160 struct list_head *entry = lockhashentry(addr);
162 struct lock_stat *ret, *new; 161 struct lock_stat *ret, *new;
@@ -175,11 +174,6 @@ static struct lock_stat *lock_stat_findnew(void *addr, const char *name,
175 if (!new->name) 174 if (!new->name)
176 goto alloc_failed; 175 goto alloc_failed;
177 strcpy(new->name, name); 176 strcpy(new->name, name);
178 new->file = zalloc(sizeof(char) * strlen(file) + 1);
179 if (!new->file)
180 goto alloc_failed;
181 strcpy(new->file, file);
182 new->line = line;
183 177
184 /* LOCK_STATE_UNLOCKED == 0 isn't guaranteed forever */ 178 /* LOCK_STATE_UNLOCKED == 0 isn't guaranteed forever */
185 new->state = LOCK_STATE_UNLOCKED; 179 new->state = LOCK_STATE_UNLOCKED;
@@ -197,36 +191,28 @@ static char const *input_name = "perf.data";
197static int profile_cpu = -1; 191static int profile_cpu = -1;
198 192
199struct raw_event_sample { 193struct raw_event_sample {
200 u32 size; 194 u32 size;
201 char data[0]; 195 char data[0];
202}; 196};
203 197
204struct trace_acquire_event { 198struct trace_acquire_event {
205 void *addr; 199 void *addr;
206 const char *name; 200 const char *name;
207 const char *file;
208 unsigned int line;
209}; 201};
210 202
211struct trace_acquired_event { 203struct trace_acquired_event {
212 void *addr; 204 void *addr;
213 const char *name; 205 const char *name;
214 const char *file;
215 unsigned int line;
216}; 206};
217 207
218struct trace_contended_event { 208struct trace_contended_event {
219 void *addr; 209 void *addr;
220 const char *name; 210 const char *name;
221 const char *file;
222 unsigned int line;
223}; 211};
224 212
225struct trace_release_event { 213struct trace_release_event {
226 void *addr; 214 void *addr;
227 const char *name; 215 const char *name;
228 const char *file;
229 unsigned int line;
230}; 216};
231 217
232struct trace_lock_handler { 218struct trace_lock_handler {
@@ -255,7 +241,8 @@ struct trace_lock_handler {
255 struct thread *thread); 241 struct thread *thread);
256}; 242};
257 243
258static void prof_lock_acquire_event(struct trace_acquire_event *acquire_event, 244static void
245report_lock_acquire_event(struct trace_acquire_event *acquire_event,
259 struct event *__event __used, 246 struct event *__event __used,
260 int cpu __used, 247 int cpu __used,
261 u64 timestamp, 248 u64 timestamp,
@@ -263,8 +250,7 @@ static void prof_lock_acquire_event(struct trace_acquire_event *acquire_event,
263{ 250{
264 struct lock_stat *st; 251 struct lock_stat *st;
265 252
266 st = lock_stat_findnew(acquire_event->addr, acquire_event->name, 253 st = lock_stat_findnew(acquire_event->addr, acquire_event->name);
267 acquire_event->file, acquire_event->line);
268 254
269 switch (st->state) { 255 switch (st->state) {
270 case LOCK_STATE_UNLOCKED: 256 case LOCK_STATE_UNLOCKED:
@@ -279,7 +265,8 @@ static void prof_lock_acquire_event(struct trace_acquire_event *acquire_event,
279 st->prev_event_time = timestamp; 265 st->prev_event_time = timestamp;
280} 266}
281 267
282static void prof_lock_acquired_event(struct trace_acquired_event *acquired_event, 268static void
269report_lock_acquired_event(struct trace_acquired_event *acquired_event,
283 struct event *__event __used, 270 struct event *__event __used,
284 int cpu __used, 271 int cpu __used,
285 u64 timestamp, 272 u64 timestamp,
@@ -287,8 +274,7 @@ static void prof_lock_acquired_event(struct trace_acquired_event *acquired_event
287{ 274{
288 struct lock_stat *st; 275 struct lock_stat *st;
289 276
290 st = lock_stat_findnew(acquired_event->addr, acquired_event->name, 277 st = lock_stat_findnew(acquired_event->addr, acquired_event->name);
291 acquired_event->file, acquired_event->line);
292 278
293 switch (st->state) { 279 switch (st->state) {
294 case LOCK_STATE_UNLOCKED: 280 case LOCK_STATE_UNLOCKED:
@@ -305,7 +291,8 @@ static void prof_lock_acquired_event(struct trace_acquired_event *acquired_event
305 st->prev_event_time = timestamp; 291 st->prev_event_time = timestamp;
306} 292}
307 293
308static void prof_lock_contended_event(struct trace_contended_event *contended_event, 294static void
295report_lock_contended_event(struct trace_contended_event *contended_event,
309 struct event *__event __used, 296 struct event *__event __used,
310 int cpu __used, 297 int cpu __used,
311 u64 timestamp, 298 u64 timestamp,
@@ -313,8 +300,7 @@ static void prof_lock_contended_event(struct trace_contended_event *contended_ev
313{ 300{
314 struct lock_stat *st; 301 struct lock_stat *st;
315 302
316 st = lock_stat_findnew(contended_event->addr, contended_event->name, 303 st = lock_stat_findnew(contended_event->addr, contended_event->name);
317 contended_event->file, contended_event->line);
318 304
319 switch (st->state) { 305 switch (st->state) {
320 case LOCK_STATE_UNLOCKED: 306 case LOCK_STATE_UNLOCKED:
@@ -330,7 +316,8 @@ static void prof_lock_contended_event(struct trace_contended_event *contended_ev
330 st->prev_event_time = timestamp; 316 st->prev_event_time = timestamp;
331} 317}
332 318
333static void prof_lock_release_event(struct trace_release_event *release_event, 319static void
320report_lock_release_event(struct trace_release_event *release_event,
334 struct event *__event __used, 321 struct event *__event __used,
335 int cpu __used, 322 int cpu __used,
336 u64 timestamp, 323 u64 timestamp,
@@ -339,8 +326,7 @@ static void prof_lock_release_event(struct trace_release_event *release_event,
339 struct lock_stat *st; 326 struct lock_stat *st;
340 u64 hold_time; 327 u64 hold_time;
341 328
342 st = lock_stat_findnew(release_event->addr, release_event->name, 329 st = lock_stat_findnew(release_event->addr, release_event->name);
343 release_event->file, release_event->line);
344 330
345 switch (st->state) { 331 switch (st->state) {
346 case LOCK_STATE_UNLOCKED: 332 case LOCK_STATE_UNLOCKED:
@@ -373,11 +359,11 @@ end:
373 359
374/* lock oriented handlers */ 360/* lock oriented handlers */
375/* TODO: handlers for CPU oriented, thread oriented */ 361/* TODO: handlers for CPU oriented, thread oriented */
376static struct trace_lock_handler prof_lock_ops = { 362static struct trace_lock_handler report_lock_ops = {
377 .acquire_event = prof_lock_acquire_event, 363 .acquire_event = report_lock_acquire_event,
378 .acquired_event = prof_lock_acquired_event, 364 .acquired_event = report_lock_acquired_event,
379 .contended_event = prof_lock_contended_event, 365 .contended_event = report_lock_contended_event,
380 .release_event = prof_lock_release_event, 366 .release_event = report_lock_release_event,
381}; 367};
382 368
383static struct trace_lock_handler *trace_handler; 369static struct trace_lock_handler *trace_handler;
@@ -395,14 +381,9 @@ process_lock_acquire_event(void *data,
395 tmp = raw_field_value(event, "lockdep_addr", data); 381 tmp = raw_field_value(event, "lockdep_addr", data);
396 memcpy(&acquire_event.addr, &tmp, sizeof(void *)); 382 memcpy(&acquire_event.addr, &tmp, sizeof(void *));
397 acquire_event.name = (char *)raw_field_ptr(event, "name", data); 383 acquire_event.name = (char *)raw_field_ptr(event, "name", data);
398 acquire_event.file = (char *)raw_field_ptr(event, "file", data);
399 acquire_event.line =
400 (unsigned int)raw_field_value(event, "line", data);
401 384
402 if (trace_handler->acquire_event) { 385 if (trace_handler->acquire_event)
403 trace_handler->acquire_event(&acquire_event, 386 trace_handler->acquire_event(&acquire_event, event, cpu, timestamp, thread);
404 event, cpu, timestamp, thread);
405 }
406} 387}
407 388
408static void 389static void
@@ -418,14 +399,9 @@ process_lock_acquired_event(void *data,
418 tmp = raw_field_value(event, "lockdep_addr", data); 399 tmp = raw_field_value(event, "lockdep_addr", data);
419 memcpy(&acquired_event.addr, &tmp, sizeof(void *)); 400 memcpy(&acquired_event.addr, &tmp, sizeof(void *));
420 acquired_event.name = (char *)raw_field_ptr(event, "name", data); 401 acquired_event.name = (char *)raw_field_ptr(event, "name", data);
421 acquired_event.file = (char *)raw_field_ptr(event, "file", data);
422 acquired_event.line =
423 (unsigned int)raw_field_value(event, "line", data);
424 402
425 if (trace_handler->acquire_event) { 403 if (trace_handler->acquire_event)
426 trace_handler->acquired_event(&acquired_event, 404 trace_handler->acquired_event(&acquired_event, event, cpu, timestamp, thread);
427 event, cpu, timestamp, thread);
428 }
429} 405}
430 406
431static void 407static void
@@ -441,14 +417,9 @@ process_lock_contended_event(void *data,
441 tmp = raw_field_value(event, "lockdep_addr", data); 417 tmp = raw_field_value(event, "lockdep_addr", data);
442 memcpy(&contended_event.addr, &tmp, sizeof(void *)); 418 memcpy(&contended_event.addr, &tmp, sizeof(void *));
443 contended_event.name = (char *)raw_field_ptr(event, "name", data); 419 contended_event.name = (char *)raw_field_ptr(event, "name", data);
444 contended_event.file = (char *)raw_field_ptr(event, "file", data);
445 contended_event.line =
446 (unsigned int)raw_field_value(event, "line", data);
447 420
448 if (trace_handler->acquire_event) { 421 if (trace_handler->acquire_event)
449 trace_handler->contended_event(&contended_event, 422 trace_handler->contended_event(&contended_event, event, cpu, timestamp, thread);
450 event, cpu, timestamp, thread);
451 }
452} 423}
453 424
454static void 425static void
@@ -464,14 +435,9 @@ process_lock_release_event(void *data,
464 tmp = raw_field_value(event, "lockdep_addr", data); 435 tmp = raw_field_value(event, "lockdep_addr", data);
465 memcpy(&release_event.addr, &tmp, sizeof(void *)); 436 memcpy(&release_event.addr, &tmp, sizeof(void *));
466 release_event.name = (char *)raw_field_ptr(event, "name", data); 437 release_event.name = (char *)raw_field_ptr(event, "name", data);
467 release_event.file = (char *)raw_field_ptr(event, "file", data);
468 release_event.line =
469 (unsigned int)raw_field_value(event, "line", data);
470 438
471 if (trace_handler->acquire_event) { 439 if (trace_handler->acquire_event)
472 trace_handler->release_event(&release_event, 440 trace_handler->release_event(&release_event, event, cpu, timestamp, thread);
473 event, cpu, timestamp, thread);
474 }
475} 441}
476 442
477static void 443static void
@@ -503,14 +469,6 @@ static int process_sample_event(event_t *event, struct perf_session *session)
503 event__parse_sample(event, session->sample_type, &data); 469 event__parse_sample(event, session->sample_type, &data);
504 thread = perf_session__findnew(session, data.pid); 470 thread = perf_session__findnew(session, data.pid);
505 471
506 /*
507 * FIXME: this causes warn on 32bit environment
508 * because of (void *)data.ip (type of data.ip is u64)
509 */
510/* dump_printf("(IP, %d): %d/%d: %p period: %llu\n", */
511/* event->header.misc, */
512/* data.pid, data.tid, (void *)data.ip, data.period); */
513
514 if (thread == NULL) { 472 if (thread == NULL) {
515 pr_debug("problem processing %d event, skipping it.\n", 473 pr_debug("problem processing %d event, skipping it.\n",
516 event->header.type); 474 event->header.type);
@@ -580,15 +538,14 @@ static void dump_map(void)
580 538
581 for (i = 0; i < LOCKHASH_SIZE; i++) { 539 for (i = 0; i < LOCKHASH_SIZE; i++) {
582 list_for_each_entry(st, &lockhash_table[i], hash_entry) { 540 list_for_each_entry(st, &lockhash_table[i], hash_entry) {
583 printf("%p: %s (src: %s, line: %u)\n", 541 printf("%p: %s\n", st->addr, st->name);
584 st->addr, st->name, st->file, st->line);
585 } 542 }
586 } 543 }
587} 544}
588 545
589static struct perf_event_ops eops = { 546static struct perf_event_ops eops = {
590 .sample = process_sample_event, 547 .sample = process_sample_event,
591 .comm = event__process_comm, 548 .comm = event__process_comm,
592}; 549};
593 550
594static struct perf_session *session; 551static struct perf_session *session;
@@ -614,7 +571,7 @@ static void sort_result(void)
614 } 571 }
615} 572}
616 573
617static void __cmd_prof(void) 574static void __cmd_report(void)
618{ 575{
619 setup_pager(); 576 setup_pager();
620 select_key(); 577 select_key();
@@ -623,12 +580,12 @@ static void __cmd_prof(void)
623 print_result(); 580 print_result();
624} 581}
625 582
626static const char * const prof_usage[] = { 583static const char * const report_usage[] = {
627 "perf sched prof [<options>]", 584 "perf lock report [<options>]",
628 NULL 585 NULL
629}; 586};
630 587
631static const struct option prof_options[] = { 588static const struct option report_options[] = {
632 OPT_STRING('k', "key", &sort_key, "acquired", 589 OPT_STRING('k', "key", &sort_key, "acquired",
633 "key for sorting"), 590 "key for sorting"),
634 /* TODO: type */ 591 /* TODO: type */
@@ -636,17 +593,14 @@ static const struct option prof_options[] = {
636}; 593};
637 594
638static const char * const lock_usage[] = { 595static const char * const lock_usage[] = {
639 "perf lock [<options>] {record|trace|prof}", 596 "perf lock [<options>] {record|trace|report}",
640 NULL 597 NULL
641}; 598};
642 599
643static const struct option lock_options[] = { 600static const struct option lock_options[] = {
644 OPT_STRING('i', "input", &input_name, "file", 601 OPT_STRING('i', "input", &input_name, "file", "input file name"),
645 "input file name"), 602 OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
646 OPT_BOOLEAN('v', "verbose", &verbose, 603 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
647 "be more verbose (show symbol address, etc)"),
648 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
649 "dump raw trace in ASCII"),
650 OPT_END() 604 OPT_END()
651}; 605};
652 606
@@ -698,21 +652,21 @@ int cmd_lock(int argc, const char **argv, const char *prefix __used)
698 652
699 if (!strncmp(argv[0], "rec", 3)) { 653 if (!strncmp(argv[0], "rec", 3)) {
700 return __cmd_record(argc, argv); 654 return __cmd_record(argc, argv);
701 } else if (!strncmp(argv[0], "prof", 4)) { 655 } else if (!strncmp(argv[0], "report", 6)) {
702 trace_handler = &prof_lock_ops; 656 trace_handler = &report_lock_ops;
703 if (argc) { 657 if (argc) {
704 argc = parse_options(argc, argv, 658 argc = parse_options(argc, argv,
705 prof_options, prof_usage, 0); 659 report_options, report_usage, 0);
706 if (argc) 660 if (argc)
707 usage_with_options(prof_usage, prof_options); 661 usage_with_options(report_usage, report_options);
708 } 662 }
709 __cmd_prof(); 663 __cmd_report();
710 } else if (!strcmp(argv[0], "trace")) { 664 } else if (!strcmp(argv[0], "trace")) {
711 /* Aliased to 'perf trace' */ 665 /* Aliased to 'perf trace' */
712 return cmd_trace(argc, argv, prefix); 666 return cmd_trace(argc, argv, prefix);
713 } else if (!strcmp(argv[0], "map")) { 667 } else if (!strcmp(argv[0], "map")) {
714 /* recycling prof_lock_ops */ 668 /* recycling report_lock_ops */
715 trace_handler = &prof_lock_ops; 669 trace_handler = &report_lock_ops;
716 setup_pager(); 670 setup_pager();
717 read_events(); 671 read_events();
718 dump_map(); 672 dump_map();