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.c137
1 files changed, 76 insertions, 61 deletions
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index ee33ba2f05dd..c852c7a85d32 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -15,6 +15,7 @@
15#include "util/debug.h" 15#include "util/debug.h"
16#include "util/session.h" 16#include "util/session.h"
17#include "util/tool.h" 17#include "util/tool.h"
18#include "util/data.h"
18 19
19#include <sys/types.h> 20#include <sys/types.h>
20#include <sys/prctl.h> 21#include <sys/prctl.h>
@@ -56,7 +57,9 @@ struct lock_stat {
56 57
57 unsigned int nr_readlock; 58 unsigned int nr_readlock;
58 unsigned int nr_trylock; 59 unsigned int nr_trylock;
60
59 /* these times are in nano sec. */ 61 /* these times are in nano sec. */
62 u64 avg_wait_time;
60 u64 wait_time_total; 63 u64 wait_time_total;
61 u64 wait_time_min; 64 u64 wait_time_min;
62 u64 wait_time_max; 65 u64 wait_time_max;
@@ -208,6 +211,7 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid)
208 211
209SINGLE_KEY(nr_acquired) 212SINGLE_KEY(nr_acquired)
210SINGLE_KEY(nr_contended) 213SINGLE_KEY(nr_contended)
214SINGLE_KEY(avg_wait_time)
211SINGLE_KEY(wait_time_total) 215SINGLE_KEY(wait_time_total)
212SINGLE_KEY(wait_time_max) 216SINGLE_KEY(wait_time_max)
213 217
@@ -244,6 +248,7 @@ static struct rb_root result; /* place to store sorted data */
244struct lock_key keys[] = { 248struct lock_key keys[] = {
245 DEF_KEY_LOCK(acquired, nr_acquired), 249 DEF_KEY_LOCK(acquired, nr_acquired),
246 DEF_KEY_LOCK(contended, nr_contended), 250 DEF_KEY_LOCK(contended, nr_contended),
251 DEF_KEY_LOCK(avg_wait, avg_wait_time),
247 DEF_KEY_LOCK(wait_total, wait_time_total), 252 DEF_KEY_LOCK(wait_total, wait_time_total),
248 DEF_KEY_LOCK(wait_min, wait_time_min), 253 DEF_KEY_LOCK(wait_min, wait_time_min),
249 DEF_KEY_LOCK(wait_max, wait_time_max), 254 DEF_KEY_LOCK(wait_max, wait_time_max),
@@ -321,10 +326,12 @@ static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
321 326
322 new->addr = addr; 327 new->addr = addr;
323 new->name = zalloc(sizeof(char) * strlen(name) + 1); 328 new->name = zalloc(sizeof(char) * strlen(name) + 1);
324 if (!new->name) 329 if (!new->name) {
330 free(new);
325 goto alloc_failed; 331 goto alloc_failed;
326 strcpy(new->name, name); 332 }
327 333
334 strcpy(new->name, name);
328 new->wait_time_min = ULLONG_MAX; 335 new->wait_time_min = ULLONG_MAX;
329 336
330 list_add(&new->hash_entry, entry); 337 list_add(&new->hash_entry, entry);
@@ -400,17 +407,17 @@ static int report_lock_acquire_event(struct perf_evsel *evsel,
400 407
401 ls = lock_stat_findnew(addr, name); 408 ls = lock_stat_findnew(addr, name);
402 if (!ls) 409 if (!ls)
403 return -1; 410 return -ENOMEM;
404 if (ls->discard) 411 if (ls->discard)
405 return 0; 412 return 0;
406 413
407 ts = thread_stat_findnew(sample->tid); 414 ts = thread_stat_findnew(sample->tid);
408 if (!ts) 415 if (!ts)
409 return -1; 416 return -ENOMEM;
410 417
411 seq = get_seq(ts, addr); 418 seq = get_seq(ts, addr);
412 if (!seq) 419 if (!seq)
413 return -1; 420 return -ENOMEM;
414 421
415 switch (seq->state) { 422 switch (seq->state) {
416 case SEQ_STATE_UNINITIALIZED: 423 case SEQ_STATE_UNINITIALIZED:
@@ -446,7 +453,6 @@ broken:
446 list_del(&seq->list); 453 list_del(&seq->list);
447 free(seq); 454 free(seq);
448 goto end; 455 goto end;
449 break;
450 default: 456 default:
451 BUG_ON("Unknown state of lock sequence found!\n"); 457 BUG_ON("Unknown state of lock sequence found!\n");
452 break; 458 break;
@@ -473,17 +479,17 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
473 479
474 ls = lock_stat_findnew(addr, name); 480 ls = lock_stat_findnew(addr, name);
475 if (!ls) 481 if (!ls)
476 return -1; 482 return -ENOMEM;
477 if (ls->discard) 483 if (ls->discard)
478 return 0; 484 return 0;
479 485
480 ts = thread_stat_findnew(sample->tid); 486 ts = thread_stat_findnew(sample->tid);
481 if (!ts) 487 if (!ts)
482 return -1; 488 return -ENOMEM;
483 489
484 seq = get_seq(ts, addr); 490 seq = get_seq(ts, addr);
485 if (!seq) 491 if (!seq)
486 return -1; 492 return -ENOMEM;
487 493
488 switch (seq->state) { 494 switch (seq->state) {
489 case SEQ_STATE_UNINITIALIZED: 495 case SEQ_STATE_UNINITIALIZED:
@@ -508,8 +514,6 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
508 list_del(&seq->list); 514 list_del(&seq->list);
509 free(seq); 515 free(seq);
510 goto end; 516 goto end;
511 break;
512
513 default: 517 default:
514 BUG_ON("Unknown state of lock sequence found!\n"); 518 BUG_ON("Unknown state of lock sequence found!\n");
515 break; 519 break;
@@ -517,6 +521,7 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
517 521
518 seq->state = SEQ_STATE_ACQUIRED; 522 seq->state = SEQ_STATE_ACQUIRED;
519 ls->nr_acquired++; 523 ls->nr_acquired++;
524 ls->avg_wait_time = ls->nr_contended ? ls->wait_time_total/ls->nr_contended : 0;
520 seq->prev_event_time = sample->time; 525 seq->prev_event_time = sample->time;
521end: 526end:
522 return 0; 527 return 0;
@@ -536,17 +541,17 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
536 541
537 ls = lock_stat_findnew(addr, name); 542 ls = lock_stat_findnew(addr, name);
538 if (!ls) 543 if (!ls)
539 return -1; 544 return -ENOMEM;
540 if (ls->discard) 545 if (ls->discard)
541 return 0; 546 return 0;
542 547
543 ts = thread_stat_findnew(sample->tid); 548 ts = thread_stat_findnew(sample->tid);
544 if (!ts) 549 if (!ts)
545 return -1; 550 return -ENOMEM;
546 551
547 seq = get_seq(ts, addr); 552 seq = get_seq(ts, addr);
548 if (!seq) 553 if (!seq)
549 return -1; 554 return -ENOMEM;
550 555
551 switch (seq->state) { 556 switch (seq->state) {
552 case SEQ_STATE_UNINITIALIZED: 557 case SEQ_STATE_UNINITIALIZED:
@@ -564,7 +569,6 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
564 list_del(&seq->list); 569 list_del(&seq->list);
565 free(seq); 570 free(seq);
566 goto end; 571 goto end;
567 break;
568 default: 572 default:
569 BUG_ON("Unknown state of lock sequence found!\n"); 573 BUG_ON("Unknown state of lock sequence found!\n");
570 break; 574 break;
@@ -572,6 +576,7 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
572 576
573 seq->state = SEQ_STATE_CONTENDED; 577 seq->state = SEQ_STATE_CONTENDED;
574 ls->nr_contended++; 578 ls->nr_contended++;
579 ls->avg_wait_time = ls->wait_time_total/ls->nr_contended;
575 seq->prev_event_time = sample->time; 580 seq->prev_event_time = sample->time;
576end: 581end:
577 return 0; 582 return 0;
@@ -591,22 +596,21 @@ static int report_lock_release_event(struct perf_evsel *evsel,
591 596
592 ls = lock_stat_findnew(addr, name); 597 ls = lock_stat_findnew(addr, name);
593 if (!ls) 598 if (!ls)
594 return -1; 599 return -ENOMEM;
595 if (ls->discard) 600 if (ls->discard)
596 return 0; 601 return 0;
597 602
598 ts = thread_stat_findnew(sample->tid); 603 ts = thread_stat_findnew(sample->tid);
599 if (!ts) 604 if (!ts)
600 return -1; 605 return -ENOMEM;
601 606
602 seq = get_seq(ts, addr); 607 seq = get_seq(ts, addr);
603 if (!seq) 608 if (!seq)
604 return -1; 609 return -ENOMEM;
605 610
606 switch (seq->state) { 611 switch (seq->state) {
607 case SEQ_STATE_UNINITIALIZED: 612 case SEQ_STATE_UNINITIALIZED:
608 goto end; 613 goto end;
609 break;
610 case SEQ_STATE_ACQUIRED: 614 case SEQ_STATE_ACQUIRED:
611 break; 615 break;
612 case SEQ_STATE_READ_ACQUIRED: 616 case SEQ_STATE_READ_ACQUIRED:
@@ -624,7 +628,6 @@ static int report_lock_release_event(struct perf_evsel *evsel,
624 ls->discard = 1; 628 ls->discard = 1;
625 bad_hist[BROKEN_RELEASE]++; 629 bad_hist[BROKEN_RELEASE]++;
626 goto free_seq; 630 goto free_seq;
627 break;
628 default: 631 default:
629 BUG_ON("Unknown state of lock sequence found!\n"); 632 BUG_ON("Unknown state of lock sequence found!\n");
630 break; 633 break;
@@ -690,7 +693,7 @@ static void print_bad_events(int bad, int total)
690 693
691 pr_info("\n=== output for debug===\n\n"); 694 pr_info("\n=== output for debug===\n\n");
692 pr_info("bad: %d, total: %d\n", bad, total); 695 pr_info("bad: %d, total: %d\n", bad, total);
693 pr_info("bad rate: %f %%\n", (double)bad / (double)total * 100); 696 pr_info("bad rate: %.2f %%\n", (double)bad / (double)total * 100);
694 pr_info("histogram of events caused bad sequence\n"); 697 pr_info("histogram of events caused bad sequence\n");
695 for (i = 0; i < BROKEN_MAX; i++) 698 for (i = 0; i < BROKEN_MAX; i++)
696 pr_info(" %10s: %d\n", name[i], bad_hist[i]); 699 pr_info(" %10s: %d\n", name[i], bad_hist[i]);
@@ -707,6 +710,7 @@ static void print_result(void)
707 pr_info("%10s ", "acquired"); 710 pr_info("%10s ", "acquired");
708 pr_info("%10s ", "contended"); 711 pr_info("%10s ", "contended");
709 712
713 pr_info("%15s ", "avg wait (ns)");
710 pr_info("%15s ", "total wait (ns)"); 714 pr_info("%15s ", "total wait (ns)");
711 pr_info("%15s ", "max wait (ns)"); 715 pr_info("%15s ", "max wait (ns)");
712 pr_info("%15s ", "min wait (ns)"); 716 pr_info("%15s ", "min wait (ns)");
@@ -738,6 +742,7 @@ static void print_result(void)
738 pr_info("%10u ", st->nr_acquired); 742 pr_info("%10u ", st->nr_acquired);
739 pr_info("%10u ", st->nr_contended); 743 pr_info("%10u ", st->nr_contended);
740 744
745 pr_info("%15" PRIu64 " ", st->avg_wait_time);
741 pr_info("%15" PRIu64 " ", st->wait_time_total); 746 pr_info("%15" PRIu64 " ", st->wait_time_total);
742 pr_info("%15" PRIu64 " ", st->wait_time_max); 747 pr_info("%15" PRIu64 " ", st->wait_time_max);
743 pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ? 748 pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ?
@@ -762,7 +767,7 @@ static void dump_threads(void)
762 while (node) { 767 while (node) {
763 st = container_of(node, struct thread_stat, rb); 768 st = container_of(node, struct thread_stat, rb);
764 t = perf_session__findnew(session, st->tid); 769 t = perf_session__findnew(session, st->tid);
765 pr_info("%10d: %s\n", st->tid, t->comm); 770 pr_info("%10d: %s\n", st->tid, thread__comm_str(t));
766 node = rb_next(node); 771 node = rb_next(node);
767 }; 772 };
768} 773}
@@ -814,14 +819,26 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
814 return -1; 819 return -1;
815 } 820 }
816 821
817 if (evsel->handler.func != NULL) { 822 if (evsel->handler != NULL) {
818 tracepoint_handler f = evsel->handler.func; 823 tracepoint_handler f = evsel->handler;
819 return f(evsel, sample); 824 return f(evsel, sample);
820 } 825 }
821 826
822 return 0; 827 return 0;
823} 828}
824 829
830static void sort_result(void)
831{
832 unsigned int i;
833 struct lock_stat *st;
834
835 for (i = 0; i < LOCKHASH_SIZE; i++) {
836 list_for_each_entry(st, &lockhash_table[i], hash_entry) {
837 insert_to_result(st, compare);
838 }
839 }
840}
841
825static const struct perf_evsel_str_handler lock_tracepoints[] = { 842static const struct perf_evsel_str_handler lock_tracepoints[] = {
826 { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */ 843 { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */
827 { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */ 844 { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
@@ -829,51 +846,51 @@ static const struct perf_evsel_str_handler lock_tracepoints[] = {
829 { "lock:lock_release", perf_evsel__process_lock_release, }, /* CONFIG_LOCKDEP */ 846 { "lock:lock_release", perf_evsel__process_lock_release, }, /* CONFIG_LOCKDEP */
830}; 847};
831 848
832static int read_events(void) 849static int __cmd_report(bool display_info)
833{ 850{
851 int err = -EINVAL;
834 struct perf_tool eops = { 852 struct perf_tool eops = {
835 .sample = process_sample_event, 853 .sample = process_sample_event,
836 .comm = perf_event__process_comm, 854 .comm = perf_event__process_comm,
837 .ordered_samples = true, 855 .ordered_samples = true,
838 }; 856 };
839 session = perf_session__new(input_name, O_RDONLY, 0, false, &eops); 857 struct perf_data_file file = {
858 .path = input_name,
859 .mode = PERF_DATA_MODE_READ,
860 };
861
862 session = perf_session__new(&file, false, &eops);
840 if (!session) { 863 if (!session) {
841 pr_err("Initializing perf session failed\n"); 864 pr_err("Initializing perf session failed\n");
842 return -1; 865 return -ENOMEM;
843 } 866 }
844 867
868 if (!perf_session__has_traces(session, "lock record"))
869 goto out_delete;
870
845 if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) { 871 if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) {
846 pr_err("Initializing perf session tracepoint handlers failed\n"); 872 pr_err("Initializing perf session tracepoint handlers failed\n");
847 return -1; 873 goto out_delete;
848 } 874 }
849 875
850 return perf_session__process_events(session, &eops); 876 if (select_key())
851} 877 goto out_delete;
852
853static void sort_result(void)
854{
855 unsigned int i;
856 struct lock_stat *st;
857 878
858 for (i = 0; i < LOCKHASH_SIZE; i++) { 879 err = perf_session__process_events(session, &eops);
859 list_for_each_entry(st, &lockhash_table[i], hash_entry) { 880 if (err)
860 insert_to_result(st, compare); 881 goto out_delete;
861 }
862 }
863}
864 882
865static int __cmd_report(void)
866{
867 setup_pager(); 883 setup_pager();
884 if (display_info) /* used for info subcommand */
885 err = dump_info();
886 else {
887 sort_result();
888 print_result();
889 }
868 890
869 if ((select_key() != 0) || 891out_delete:
870 (read_events() != 0)) 892 perf_session__delete(session);
871 return -1; 893 return err;
872
873 sort_result();
874 print_result();
875
876 return 0;
877} 894}
878 895
879static int __cmd_record(int argc, const char **argv) 896static int __cmd_record(int argc, const char **argv)
@@ -881,7 +898,7 @@ static int __cmd_record(int argc, const char **argv)
881 const char *record_args[] = { 898 const char *record_args[] = {
882 "record", "-R", "-m", "1024", "-c", "1", 899 "record", "-R", "-m", "1024", "-c", "1",
883 }; 900 };
884 unsigned int rec_argc, i, j; 901 unsigned int rec_argc, i, j, ret;
885 const char **rec_argv; 902 const char **rec_argv;
886 903
887 for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) { 904 for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) {
@@ -898,7 +915,7 @@ static int __cmd_record(int argc, const char **argv)
898 rec_argc += 2 * ARRAY_SIZE(lock_tracepoints); 915 rec_argc += 2 * ARRAY_SIZE(lock_tracepoints);
899 916
900 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 917 rec_argv = calloc(rec_argc + 1, sizeof(char *));
901 if (rec_argv == NULL) 918 if (!rec_argv)
902 return -ENOMEM; 919 return -ENOMEM;
903 920
904 for (i = 0; i < ARRAY_SIZE(record_args); i++) 921 for (i = 0; i < ARRAY_SIZE(record_args); i++)
@@ -914,7 +931,9 @@ static int __cmd_record(int argc, const char **argv)
914 931
915 BUG_ON(i != rec_argc); 932 BUG_ON(i != rec_argc);
916 933
917 return cmd_record(i, rec_argv, NULL); 934 ret = cmd_record(i, rec_argv, NULL);
935 free(rec_argv);
936 return ret;
918} 937}
919 938
920int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) 939int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
@@ -934,7 +953,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
934 }; 953 };
935 const struct option report_options[] = { 954 const struct option report_options[] = {
936 OPT_STRING('k', "key", &sort_key, "acquired", 955 OPT_STRING('k', "key", &sort_key, "acquired",
937 "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"), 956 "key for sorting (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"),
938 /* TODO: type */ 957 /* TODO: type */
939 OPT_END() 958 OPT_END()
940 }; 959 };
@@ -972,7 +991,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
972 if (argc) 991 if (argc)
973 usage_with_options(report_usage, report_options); 992 usage_with_options(report_usage, report_options);
974 } 993 }
975 __cmd_report(); 994 rc = __cmd_report(false);
976 } else if (!strcmp(argv[0], "script")) { 995 } else if (!strcmp(argv[0], "script")) {
977 /* Aliased to 'perf script' */ 996 /* Aliased to 'perf script' */
978 return cmd_script(argc, argv, prefix); 997 return cmd_script(argc, argv, prefix);
@@ -985,11 +1004,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
985 } 1004 }
986 /* recycling report_lock_ops */ 1005 /* recycling report_lock_ops */
987 trace_handler = &report_lock_ops; 1006 trace_handler = &report_lock_ops;
988 setup_pager(); 1007 rc = __cmd_report(true);
989 if (read_events() != 0)
990 rc = -1;
991 else
992 rc = dump_info();
993 } else { 1008 } else {
994 usage_with_options(lock_usage, lock_options); 1009 usage_with_options(lock_usage, lock_options);
995 } 1010 }