aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-lock.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-lock.c')
-rw-r--r--tools/perf/builtin-lock.c414
1 files changed, 203 insertions, 211 deletions
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index b3c428548868..7d6e09949880 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -1,6 +1,8 @@
1#include "builtin.h" 1#include "builtin.h"
2#include "perf.h" 2#include "perf.h"
3 3
4#include "util/evlist.h"
5#include "util/evsel.h"
4#include "util/util.h" 6#include "util/util.h"
5#include "util/cache.h" 7#include "util/cache.h"
6#include "util/symbol.h" 8#include "util/symbol.h"
@@ -40,7 +42,7 @@ struct lock_stat {
40 struct rb_node rb; /* used for sorting */ 42 struct rb_node rb; /* used for sorting */
41 43
42 /* 44 /*
43 * FIXME: raw_field_value() returns unsigned long long, 45 * FIXME: perf_evsel__intval() returns u64,
44 * so address of lockdep_map should be dealed as 64bit. 46 * so address of lockdep_map should be dealed as 64bit.
45 * Is there more better solution? 47 * Is there more better solution?
46 */ 48 */
@@ -160,8 +162,10 @@ static struct thread_stat *thread_stat_findnew_after_first(u32 tid)
160 return st; 162 return st;
161 163
162 st = zalloc(sizeof(struct thread_stat)); 164 st = zalloc(sizeof(struct thread_stat));
163 if (!st) 165 if (!st) {
164 die("memory allocation failed\n"); 166 pr_err("memory allocation failed\n");
167 return NULL;
168 }
165 169
166 st->tid = tid; 170 st->tid = tid;
167 INIT_LIST_HEAD(&st->seq_list); 171 INIT_LIST_HEAD(&st->seq_list);
@@ -180,8 +184,10 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid)
180 struct thread_stat *st; 184 struct thread_stat *st;
181 185
182 st = zalloc(sizeof(struct thread_stat)); 186 st = zalloc(sizeof(struct thread_stat));
183 if (!st) 187 if (!st) {
184 die("memory allocation failed\n"); 188 pr_err("memory allocation failed\n");
189 return NULL;
190 }
185 st->tid = tid; 191 st->tid = tid;
186 INIT_LIST_HEAD(&st->seq_list); 192 INIT_LIST_HEAD(&st->seq_list);
187 193
@@ -247,18 +253,20 @@ struct lock_key keys[] = {
247 { NULL, NULL } 253 { NULL, NULL }
248}; 254};
249 255
250static void select_key(void) 256static int select_key(void)
251{ 257{
252 int i; 258 int i;
253 259
254 for (i = 0; keys[i].name; i++) { 260 for (i = 0; keys[i].name; i++) {
255 if (!strcmp(keys[i].name, sort_key)) { 261 if (!strcmp(keys[i].name, sort_key)) {
256 compare = keys[i].key; 262 compare = keys[i].key;
257 return; 263 return 0;
258 } 264 }
259 } 265 }
260 266
261 die("Unknown compare key:%s\n", sort_key); 267 pr_err("Unknown compare key: %s\n", sort_key);
268
269 return -1;
262} 270}
263 271
264static void insert_to_result(struct lock_stat *st, 272static void insert_to_result(struct lock_stat *st,
@@ -323,61 +331,24 @@ static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
323 return new; 331 return new;
324 332
325alloc_failed: 333alloc_failed:
326 die("memory allocation failed\n"); 334 pr_err("memory allocation failed\n");
335 return NULL;
327} 336}
328 337
329static const char *input_name; 338static const char *input_name;
330 339
331struct raw_event_sample { 340struct trace_lock_handler {
332 u32 size; 341 int (*acquire_event)(struct perf_evsel *evsel,
333 char data[0]; 342 struct perf_sample *sample);
334};
335
336struct trace_acquire_event {
337 void *addr;
338 const char *name;
339 int flag;
340};
341
342struct trace_acquired_event {
343 void *addr;
344 const char *name;
345};
346 343
347struct trace_contended_event { 344 int (*acquired_event)(struct perf_evsel *evsel,
348 void *addr; 345 struct perf_sample *sample);
349 const char *name;
350};
351 346
352struct trace_release_event { 347 int (*contended_event)(struct perf_evsel *evsel,
353 void *addr; 348 struct perf_sample *sample);
354 const char *name;
355};
356 349
357struct trace_lock_handler { 350 int (*release_event)(struct perf_evsel *evsel,
358 void (*acquire_event)(struct trace_acquire_event *, 351 struct perf_sample *sample);
359 struct event_format *,
360 int cpu,
361 u64 timestamp,
362 struct thread *thread);
363
364 void (*acquired_event)(struct trace_acquired_event *,
365 struct event_format *,
366 int cpu,
367 u64 timestamp,
368 struct thread *thread);
369
370 void (*contended_event)(struct trace_contended_event *,
371 struct event_format *,
372 int cpu,
373 u64 timestamp,
374 struct thread *thread);
375
376 void (*release_event)(struct trace_release_event *,
377 struct event_format *,
378 int cpu,
379 u64 timestamp,
380 struct thread *thread);
381}; 352};
382 353
383static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr) 354static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr)
@@ -390,8 +361,10 @@ static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr)
390 } 361 }
391 362
392 seq = zalloc(sizeof(struct lock_seq_stat)); 363 seq = zalloc(sizeof(struct lock_seq_stat));
393 if (!seq) 364 if (!seq) {
394 die("Not enough memory\n"); 365 pr_err("memory allocation failed\n");
366 return NULL;
367 }
395 seq->state = SEQ_STATE_UNINITIALIZED; 368 seq->state = SEQ_STATE_UNINITIALIZED;
396 seq->addr = addr; 369 seq->addr = addr;
397 370
@@ -414,33 +387,42 @@ enum acquire_flags {
414 READ_LOCK = 2, 387 READ_LOCK = 2,
415}; 388};
416 389
417static void 390static int report_lock_acquire_event(struct perf_evsel *evsel,
418report_lock_acquire_event(struct trace_acquire_event *acquire_event, 391 struct perf_sample *sample)
419 struct event_format *__event __used,
420 int cpu __used,
421 u64 timestamp __used,
422 struct thread *thread __used)
423{ 392{
393 void *addr;
424 struct lock_stat *ls; 394 struct lock_stat *ls;
425 struct thread_stat *ts; 395 struct thread_stat *ts;
426 struct lock_seq_stat *seq; 396 struct lock_seq_stat *seq;
397 const char *name = perf_evsel__strval(evsel, sample, "name");
398 u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
399 int flag = perf_evsel__intval(evsel, sample, "flag");
400
401 memcpy(&addr, &tmp, sizeof(void *));
427 402
428 ls = lock_stat_findnew(acquire_event->addr, acquire_event->name); 403 ls = lock_stat_findnew(addr, name);
404 if (!ls)
405 return -1;
429 if (ls->discard) 406 if (ls->discard)
430 return; 407 return 0;
431 408
432 ts = thread_stat_findnew(thread->pid); 409 ts = thread_stat_findnew(sample->tid);
433 seq = get_seq(ts, acquire_event->addr); 410 if (!ts)
411 return -1;
412
413 seq = get_seq(ts, addr);
414 if (!seq)
415 return -1;
434 416
435 switch (seq->state) { 417 switch (seq->state) {
436 case SEQ_STATE_UNINITIALIZED: 418 case SEQ_STATE_UNINITIALIZED:
437 case SEQ_STATE_RELEASED: 419 case SEQ_STATE_RELEASED:
438 if (!acquire_event->flag) { 420 if (!flag) {
439 seq->state = SEQ_STATE_ACQUIRING; 421 seq->state = SEQ_STATE_ACQUIRING;
440 } else { 422 } else {
441 if (acquire_event->flag & TRY_LOCK) 423 if (flag & TRY_LOCK)
442 ls->nr_trylock++; 424 ls->nr_trylock++;
443 if (acquire_event->flag & READ_LOCK) 425 if (flag & READ_LOCK)
444 ls->nr_readlock++; 426 ls->nr_readlock++;
445 seq->state = SEQ_STATE_READ_ACQUIRED; 427 seq->state = SEQ_STATE_READ_ACQUIRED;
446 seq->read_count = 1; 428 seq->read_count = 1;
@@ -448,7 +430,7 @@ report_lock_acquire_event(struct trace_acquire_event *acquire_event,
448 } 430 }
449 break; 431 break;
450 case SEQ_STATE_READ_ACQUIRED: 432 case SEQ_STATE_READ_ACQUIRED:
451 if (acquire_event->flag & READ_LOCK) { 433 if (flag & READ_LOCK) {
452 seq->read_count++; 434 seq->read_count++;
453 ls->nr_acquired++; 435 ls->nr_acquired++;
454 goto end; 436 goto end;
@@ -473,38 +455,46 @@ broken:
473 } 455 }
474 456
475 ls->nr_acquire++; 457 ls->nr_acquire++;
476 seq->prev_event_time = timestamp; 458 seq->prev_event_time = sample->time;
477end: 459end:
478 return; 460 return 0;
479} 461}
480 462
481static void 463static int report_lock_acquired_event(struct perf_evsel *evsel,
482report_lock_acquired_event(struct trace_acquired_event *acquired_event, 464 struct perf_sample *sample)
483 struct event_format *__event __used,
484 int cpu __used,
485 u64 timestamp __used,
486 struct thread *thread __used)
487{ 465{
466 void *addr;
488 struct lock_stat *ls; 467 struct lock_stat *ls;
489 struct thread_stat *ts; 468 struct thread_stat *ts;
490 struct lock_seq_stat *seq; 469 struct lock_seq_stat *seq;
491 u64 contended_term; 470 u64 contended_term;
471 const char *name = perf_evsel__strval(evsel, sample, "name");
472 u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
473
474 memcpy(&addr, &tmp, sizeof(void *));
492 475
493 ls = lock_stat_findnew(acquired_event->addr, acquired_event->name); 476 ls = lock_stat_findnew(addr, name);
477 if (!ls)
478 return -1;
494 if (ls->discard) 479 if (ls->discard)
495 return; 480 return 0;
481
482 ts = thread_stat_findnew(sample->tid);
483 if (!ts)
484 return -1;
496 485
497 ts = thread_stat_findnew(thread->pid); 486 seq = get_seq(ts, addr);
498 seq = get_seq(ts, acquired_event->addr); 487 if (!seq)
488 return -1;
499 489
500 switch (seq->state) { 490 switch (seq->state) {
501 case SEQ_STATE_UNINITIALIZED: 491 case SEQ_STATE_UNINITIALIZED:
502 /* orphan event, do nothing */ 492 /* orphan event, do nothing */
503 return; 493 return 0;
504 case SEQ_STATE_ACQUIRING: 494 case SEQ_STATE_ACQUIRING:
505 break; 495 break;
506 case SEQ_STATE_CONTENDED: 496 case SEQ_STATE_CONTENDED:
507 contended_term = timestamp - seq->prev_event_time; 497 contended_term = sample->time - seq->prev_event_time;
508 ls->wait_time_total += contended_term; 498 ls->wait_time_total += contended_term;
509 if (contended_term < ls->wait_time_min) 499 if (contended_term < ls->wait_time_min)
510 ls->wait_time_min = contended_term; 500 ls->wait_time_min = contended_term;
@@ -529,33 +519,41 @@ report_lock_acquired_event(struct trace_acquired_event *acquired_event,
529 519
530 seq->state = SEQ_STATE_ACQUIRED; 520 seq->state = SEQ_STATE_ACQUIRED;
531 ls->nr_acquired++; 521 ls->nr_acquired++;
532 seq->prev_event_time = timestamp; 522 seq->prev_event_time = sample->time;
533end: 523end:
534 return; 524 return 0;
535} 525}
536 526
537static void 527static int report_lock_contended_event(struct perf_evsel *evsel,
538report_lock_contended_event(struct trace_contended_event *contended_event, 528 struct perf_sample *sample)
539 struct event_format *__event __used,
540 int cpu __used,
541 u64 timestamp __used,
542 struct thread *thread __used)
543{ 529{
530 void *addr;
544 struct lock_stat *ls; 531 struct lock_stat *ls;
545 struct thread_stat *ts; 532 struct thread_stat *ts;
546 struct lock_seq_stat *seq; 533 struct lock_seq_stat *seq;
534 const char *name = perf_evsel__strval(evsel, sample, "name");
535 u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
547 536
548 ls = lock_stat_findnew(contended_event->addr, contended_event->name); 537 memcpy(&addr, &tmp, sizeof(void *));
538
539 ls = lock_stat_findnew(addr, name);
540 if (!ls)
541 return -1;
549 if (ls->discard) 542 if (ls->discard)
550 return; 543 return 0;
544
545 ts = thread_stat_findnew(sample->tid);
546 if (!ts)
547 return -1;
551 548
552 ts = thread_stat_findnew(thread->pid); 549 seq = get_seq(ts, addr);
553 seq = get_seq(ts, contended_event->addr); 550 if (!seq)
551 return -1;
554 552
555 switch (seq->state) { 553 switch (seq->state) {
556 case SEQ_STATE_UNINITIALIZED: 554 case SEQ_STATE_UNINITIALIZED:
557 /* orphan event, do nothing */ 555 /* orphan event, do nothing */
558 return; 556 return 0;
559 case SEQ_STATE_ACQUIRING: 557 case SEQ_STATE_ACQUIRING:
560 break; 558 break;
561 case SEQ_STATE_RELEASED: 559 case SEQ_STATE_RELEASED:
@@ -576,28 +574,36 @@ report_lock_contended_event(struct trace_contended_event *contended_event,
576 574
577 seq->state = SEQ_STATE_CONTENDED; 575 seq->state = SEQ_STATE_CONTENDED;
578 ls->nr_contended++; 576 ls->nr_contended++;
579 seq->prev_event_time = timestamp; 577 seq->prev_event_time = sample->time;
580end: 578end:
581 return; 579 return 0;
582} 580}
583 581
584static void 582static int report_lock_release_event(struct perf_evsel *evsel,
585report_lock_release_event(struct trace_release_event *release_event, 583 struct perf_sample *sample)
586 struct event_format *__event __used,
587 int cpu __used,
588 u64 timestamp __used,
589 struct thread *thread __used)
590{ 584{
585 void *addr;
591 struct lock_stat *ls; 586 struct lock_stat *ls;
592 struct thread_stat *ts; 587 struct thread_stat *ts;
593 struct lock_seq_stat *seq; 588 struct lock_seq_stat *seq;
589 const char *name = perf_evsel__strval(evsel, sample, "name");
590 u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
591
592 memcpy(&addr, &tmp, sizeof(void *));
594 593
595 ls = lock_stat_findnew(release_event->addr, release_event->name); 594 ls = lock_stat_findnew(addr, name);
595 if (!ls)
596 return -1;
596 if (ls->discard) 597 if (ls->discard)
597 return; 598 return 0;
599
600 ts = thread_stat_findnew(sample->tid);
601 if (!ts)
602 return -1;
598 603
599 ts = thread_stat_findnew(thread->pid); 604 seq = get_seq(ts, addr);
600 seq = get_seq(ts, release_event->addr); 605 if (!seq)
606 return -1;
601 607
602 switch (seq->state) { 608 switch (seq->state) {
603 case SEQ_STATE_UNINITIALIZED: 609 case SEQ_STATE_UNINITIALIZED:
@@ -631,7 +637,7 @@ free_seq:
631 list_del(&seq->list); 637 list_del(&seq->list);
632 free(seq); 638 free(seq);
633end: 639end:
634 return; 640 return 0;
635} 641}
636 642
637/* lock oriented handlers */ 643/* lock oriented handlers */
@@ -645,96 +651,36 @@ static struct trace_lock_handler report_lock_ops = {
645 651
646static struct trace_lock_handler *trace_handler; 652static struct trace_lock_handler *trace_handler;
647 653
648static void 654static int perf_evsel__process_lock_acquire(struct perf_evsel *evsel,
649process_lock_acquire_event(void *data, 655 struct perf_sample *sample)
650 struct event_format *event __used,
651 int cpu __used,
652 u64 timestamp __used,
653 struct thread *thread __used)
654{
655 struct trace_acquire_event acquire_event;
656 u64 tmp; /* this is required for casting... */
657
658 tmp = raw_field_value(event, "lockdep_addr", data);
659 memcpy(&acquire_event.addr, &tmp, sizeof(void *));
660 acquire_event.name = (char *)raw_field_ptr(event, "name", data);
661 acquire_event.flag = (int)raw_field_value(event, "flag", data);
662
663 if (trace_handler->acquire_event)
664 trace_handler->acquire_event(&acquire_event, event, cpu, timestamp, thread);
665}
666
667static void
668process_lock_acquired_event(void *data,
669 struct event_format *event __used,
670 int cpu __used,
671 u64 timestamp __used,
672 struct thread *thread __used)
673{ 656{
674 struct trace_acquired_event acquired_event;
675 u64 tmp; /* this is required for casting... */
676
677 tmp = raw_field_value(event, "lockdep_addr", data);
678 memcpy(&acquired_event.addr, &tmp, sizeof(void *));
679 acquired_event.name = (char *)raw_field_ptr(event, "name", data);
680
681 if (trace_handler->acquire_event) 657 if (trace_handler->acquire_event)
682 trace_handler->acquired_event(&acquired_event, event, cpu, timestamp, thread); 658 return trace_handler->acquire_event(evsel, sample);
659 return 0;
683} 660}
684 661
685static void 662static int perf_evsel__process_lock_acquired(struct perf_evsel *evsel,
686process_lock_contended_event(void *data, 663 struct perf_sample *sample)
687 struct event_format *event __used,
688 int cpu __used,
689 u64 timestamp __used,
690 struct thread *thread __used)
691{ 664{
692 struct trace_contended_event contended_event; 665 if (trace_handler->acquired_event)
693 u64 tmp; /* this is required for casting... */ 666 return trace_handler->acquired_event(evsel, sample);
694 667 return 0;
695 tmp = raw_field_value(event, "lockdep_addr", data);
696 memcpy(&contended_event.addr, &tmp, sizeof(void *));
697 contended_event.name = (char *)raw_field_ptr(event, "name", data);
698
699 if (trace_handler->acquire_event)
700 trace_handler->contended_event(&contended_event, event, cpu, timestamp, thread);
701} 668}
702 669
703static void 670static int perf_evsel__process_lock_contended(struct perf_evsel *evsel,
704process_lock_release_event(void *data, 671 struct perf_sample *sample)
705 struct event_format *event __used,
706 int cpu __used,
707 u64 timestamp __used,
708 struct thread *thread __used)
709{ 672{
710 struct trace_release_event release_event; 673 if (trace_handler->contended_event)
711 u64 tmp; /* this is required for casting... */ 674 return trace_handler->contended_event(evsel, sample);
712 675 return 0;
713 tmp = raw_field_value(event, "lockdep_addr", data);
714 memcpy(&release_event.addr, &tmp, sizeof(void *));
715 release_event.name = (char *)raw_field_ptr(event, "name", data);
716
717 if (trace_handler->acquire_event)
718 trace_handler->release_event(&release_event, event, cpu, timestamp, thread);
719} 676}
720 677
721static void 678static int perf_evsel__process_lock_release(struct perf_evsel *evsel,
722process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread) 679 struct perf_sample *sample)
723{ 680{
724 struct event_format *event; 681 if (trace_handler->release_event)
725 int type; 682 return trace_handler->release_event(evsel, sample);
726 683 return 0;
727 type = trace_parse_common_type(session->pevent, data);
728 event = pevent_find_event(session->pevent, type);
729
730 if (!strcmp(event->name, "lock_acquire"))
731 process_lock_acquire_event(data, event, cpu, timestamp, thread);
732 if (!strcmp(event->name, "lock_acquired"))
733 process_lock_acquired_event(data, event, cpu, timestamp, thread);
734 if (!strcmp(event->name, "lock_contended"))
735 process_lock_contended_event(data, event, cpu, timestamp, thread);
736 if (!strcmp(event->name, "lock_release"))
737 process_lock_release_event(data, event, cpu, timestamp, thread);
738} 684}
739 685
740static void print_bad_events(int bad, int total) 686static void print_bad_events(int bad, int total)
@@ -836,20 +782,29 @@ static void dump_map(void)
836 } 782 }
837} 783}
838 784
839static void dump_info(void) 785static int dump_info(void)
840{ 786{
787 int rc = 0;
788
841 if (info_threads) 789 if (info_threads)
842 dump_threads(); 790 dump_threads();
843 else if (info_map) 791 else if (info_map)
844 dump_map(); 792 dump_map();
845 else 793 else {
846 die("Unknown type of information\n"); 794 rc = -1;
795 pr_err("Unknown type of information\n");
796 }
797
798 return rc;
847} 799}
848 800
849static int process_sample_event(struct perf_tool *tool __used, 801typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
802 struct perf_sample *sample);
803
804static int process_sample_event(struct perf_tool *tool __maybe_unused,
850 union perf_event *event, 805 union perf_event *event,
851 struct perf_sample *sample, 806 struct perf_sample *sample,
852 struct perf_evsel *evsel __used, 807 struct perf_evsel *evsel,
853 struct machine *machine) 808 struct machine *machine)
854{ 809{
855 struct thread *thread = machine__findnew_thread(machine, sample->tid); 810 struct thread *thread = machine__findnew_thread(machine, sample->tid);
@@ -860,7 +815,10 @@ static int process_sample_event(struct perf_tool *tool __used,
860 return -1; 815 return -1;
861 } 816 }
862 817
863 process_raw_event(sample->raw_data, sample->cpu, sample->time, thread); 818 if (evsel->handler.func != NULL) {
819 tracepoint_handler f = evsel->handler.func;
820 return f(evsel, sample);
821 }
864 822
865 return 0; 823 return 0;
866} 824}
@@ -871,11 +829,25 @@ static struct perf_tool eops = {
871 .ordered_samples = true, 829 .ordered_samples = true,
872}; 830};
873 831
832static const struct perf_evsel_str_handler lock_tracepoints[] = {
833 { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */
834 { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
835 { "lock:lock_contended", perf_evsel__process_lock_contended, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
836 { "lock:lock_release", perf_evsel__process_lock_release, }, /* CONFIG_LOCKDEP */
837};
838
874static int read_events(void) 839static int read_events(void)
875{ 840{
876 session = perf_session__new(input_name, O_RDONLY, 0, false, &eops); 841 session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
877 if (!session) 842 if (!session) {
878 die("Initializing perf session failed\n"); 843 pr_err("Initializing perf session failed\n");
844 return -1;
845 }
846
847 if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) {
848 pr_err("Initializing perf session tracepoint handlers failed\n");
849 return -1;
850 }
879 851
880 return perf_session__process_events(session, &eops); 852 return perf_session__process_events(session, &eops);
881} 853}
@@ -892,13 +864,18 @@ static void sort_result(void)
892 } 864 }
893} 865}
894 866
895static void __cmd_report(void) 867static int __cmd_report(void)
896{ 868{
897 setup_pager(); 869 setup_pager();
898 select_key(); 870
899 read_events(); 871 if ((select_key() != 0) ||
872 (read_events() != 0))
873 return -1;
874
900 sort_result(); 875 sort_result();
901 print_result(); 876 print_result();
877
878 return 0;
902} 879}
903 880
904static const char * const report_usage[] = { 881static const char * const report_usage[] = {
@@ -944,10 +921,6 @@ static const char *record_args[] = {
944 "-f", 921 "-f",
945 "-m", "1024", 922 "-m", "1024",
946 "-c", "1", 923 "-c", "1",
947 "-e", "lock:lock_acquire",
948 "-e", "lock:lock_acquired",
949 "-e", "lock:lock_contended",
950 "-e", "lock:lock_release",
951}; 924};
952 925
953static int __cmd_record(int argc, const char **argv) 926static int __cmd_record(int argc, const char **argv)
@@ -955,15 +928,31 @@ static int __cmd_record(int argc, const char **argv)
955 unsigned int rec_argc, i, j; 928 unsigned int rec_argc, i, j;
956 const char **rec_argv; 929 const char **rec_argv;
957 930
931 for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) {
932 if (!is_valid_tracepoint(lock_tracepoints[i].name)) {
933 pr_err("tracepoint %s is not enabled. "
934 "Are CONFIG_LOCKDEP and CONFIG_LOCK_STAT enabled?\n",
935 lock_tracepoints[i].name);
936 return 1;
937 }
938 }
939
958 rec_argc = ARRAY_SIZE(record_args) + argc - 1; 940 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
959 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 941 /* factor of 2 is for -e in front of each tracepoint */
942 rec_argc += 2 * ARRAY_SIZE(lock_tracepoints);
960 943
944 rec_argv = calloc(rec_argc + 1, sizeof(char *));
961 if (rec_argv == NULL) 945 if (rec_argv == NULL)
962 return -ENOMEM; 946 return -ENOMEM;
963 947
964 for (i = 0; i < ARRAY_SIZE(record_args); i++) 948 for (i = 0; i < ARRAY_SIZE(record_args); i++)
965 rec_argv[i] = strdup(record_args[i]); 949 rec_argv[i] = strdup(record_args[i]);
966 950
951 for (j = 0; j < ARRAY_SIZE(lock_tracepoints); j++) {
952 rec_argv[i++] = "-e";
953 rec_argv[i++] = strdup(lock_tracepoints[j].name);
954 }
955
967 for (j = 1; j < (unsigned int)argc; j++, i++) 956 for (j = 1; j < (unsigned int)argc; j++, i++)
968 rec_argv[i] = argv[j]; 957 rec_argv[i] = argv[j];
969 958
@@ -972,9 +961,10 @@ static int __cmd_record(int argc, const char **argv)
972 return cmd_record(i, rec_argv, NULL); 961 return cmd_record(i, rec_argv, NULL);
973} 962}
974 963
975int cmd_lock(int argc, const char **argv, const char *prefix __used) 964int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
976{ 965{
977 unsigned int i; 966 unsigned int i;
967 int rc = 0;
978 968
979 symbol__init(); 969 symbol__init();
980 for (i = 0; i < LOCKHASH_SIZE; i++) 970 for (i = 0; i < LOCKHASH_SIZE; i++)
@@ -1009,11 +999,13 @@ int cmd_lock(int argc, const char **argv, const char *prefix __used)
1009 /* recycling report_lock_ops */ 999 /* recycling report_lock_ops */
1010 trace_handler = &report_lock_ops; 1000 trace_handler = &report_lock_ops;
1011 setup_pager(); 1001 setup_pager();
1012 read_events(); 1002 if (read_events() != 0)
1013 dump_info(); 1003 rc = -1;
1004 else
1005 rc = dump_info();
1014 } else { 1006 } else {
1015 usage_with_options(lock_usage, lock_options); 1007 usage_with_options(lock_usage, lock_options);
1016 } 1008 }
1017 1009
1018 return 0; 1010 return rc;
1019} 1011}