19 #include <sys/types.h>
20 #include <sys/prctl.h>
26 #include <linux/list.h>
27 #include <linux/hash.h>
32 #define LOCKHASH_BITS 12
33 #define LOCKHASH_SIZE (1UL << LOCKHASH_BITS)
37 #define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS)
38 #define lockhashentry(key) (lockhash_table + __lockhashfn((key)))
75 #define SEQ_STATE_UNINITIALIZED 0
76 #define SEQ_STATE_RELEASED 1
77 #define SEQ_STATE_ACQUIRING 2
78 #define SEQ_STATE_ACQUIRED 3
79 #define SEQ_STATE_READ_ACQUIRED 4
80 #define SEQ_STATE_CONTENDED 5
87 #define MAX_LOCK_DEPTH 48
113 static struct rb_root thread_stats;
120 node = thread_stats.rb_node;
125 else if (tid < st->tid)
134 static void thread_stat_insert(
struct thread_stat *
new)
136 struct rb_node **
rb = &thread_stats.rb_node;
144 if (new->tid < p->
tid)
146 else if (new->tid > p->
tid)
149 BUG_ON(
"inserting invalid thread_stat\n");
152 rb_link_node(&new->rb, parent, rb);
156 static struct thread_stat *thread_stat_findnew_after_first(
u32 tid)
160 st = thread_stat_find(tid);
166 pr_err(
"memory allocation failed\n");
173 thread_stat_insert(st);
180 thread_stat_findnew_first;
188 pr_err(
"memory allocation failed\n");
194 rb_link_node(&st->
rb,
NULL, &thread_stats.rb_node);
197 thread_stat_findnew = thread_stat_findnew_after_first;
202 #define SINGLE_KEY(member) \
203 static int lock_stat_key_ ## member(struct lock_stat *one, \
204 struct lock_stat *two) \
206 return one->member > two->member; \
217 u64 s1 = one->wait_time_min;
218 u64 s2 = two->wait_time_min;
236 static const char *sort_key =
"acquired";
242 #define DEF_KEY_LOCK(name, fn_suffix) \
243 { #name, lock_stat_key_ ## fn_suffix }
256 static int select_key(
void)
260 for (i = 0; keys[
i].
name; i++) {
262 compare = keys[
i].
key;
267 pr_err(
"Unknown compare key: %s\n", sort_key);
272 static void insert_to_result(
struct lock_stat *st,
289 rb_link_node(&st->
rb, parent, rb);
294 static struct lock_stat *pop_from_result(
void)
314 if (ret->
addr == addr)
330 list_add(&new->hash_entry, entry);
334 pr_err(
"memory allocation failed\n");
338 static const char *input_name;
359 if (seq->
addr == addr)
365 pr_err(
"memory allocation failed\n");
390 static int report_lock_acquire_event(
struct perf_evsel *evsel,
397 const char *name = perf_evsel__strval(evsel, sample,
"name");
401 memcpy(&addr, &tmp,
sizeof(
void *));
403 ls = lock_stat_findnew(addr, name);
409 ts = thread_stat_findnew(sample->
tid);
413 seq = get_seq(ts, addr);
417 switch (seq->
state) {
453 BUG_ON(
"Unknown state of lock sequence found!\n");
463 static int report_lock_acquired_event(
struct perf_evsel *evsel,
471 const char *name = perf_evsel__strval(evsel, sample,
"name");
474 memcpy(&addr, &tmp,
sizeof(
void *));
476 ls = lock_stat_findnew(addr, name);
482 ts = thread_stat_findnew(sample->
tid);
486 seq = get_seq(ts, addr);
490 switch (seq->
state) {
499 if (contended_term < ls->wait_time_min)
516 BUG_ON(
"Unknown state of lock sequence found!\n");
527 static int report_lock_contended_event(
struct perf_evsel *evsel,
534 const char *name = perf_evsel__strval(evsel, sample,
"name");
537 memcpy(&addr, &tmp,
sizeof(
void *));
539 ls = lock_stat_findnew(addr, name);
545 ts = thread_stat_findnew(sample->
tid);
549 seq = get_seq(ts, addr);
553 switch (seq->
state) {
571 BUG_ON(
"Unknown state of lock sequence found!\n");
582 static int report_lock_release_event(
struct perf_evsel *evsel,
589 const char *name = perf_evsel__strval(evsel, sample,
"name");
592 memcpy(&addr, &tmp,
sizeof(
void *));
594 ls = lock_stat_findnew(addr, name);
600 ts = thread_stat_findnew(sample->
tid);
604 seq = get_seq(ts, addr);
608 switch (seq->
state) {
631 BUG_ON(
"Unknown state of lock sequence found!\n");
646 .acquire_event = report_lock_acquire_event,
647 .acquired_event = report_lock_acquired_event,
648 .contended_event = report_lock_contended_event,
649 .release_event = report_lock_release_event,
654 static int perf_evsel__process_lock_acquire(
struct perf_evsel *evsel,
662 static int perf_evsel__process_lock_acquired(
struct perf_evsel *evsel,
670 static int perf_evsel__process_lock_contended(
struct perf_evsel *evsel,
678 static int perf_evsel__process_lock_release(
struct perf_evsel *evsel,
686 static void print_bad_events(
int bad,
int total)
690 const char *name[4] =
691 {
"acquire",
"acquired",
"contended",
"release" };
693 pr_info(
"\n=== output for debug===\n\n");
694 pr_info(
"bad: %d, total: %d\n", bad, total);
695 pr_info(
"bad rate: %f %%\n", (
double)bad / (
double)total * 100);
696 pr_info(
"histogram of events caused bad sequence\n");
698 pr_info(
" %10s: %d\n", name[i], bad_hist[i]);
702 static void print_result(
void)
712 pr_info(
"%15s ",
"total wait (ns)");
713 pr_info(
"%15s ",
"max wait (ns)");
714 pr_info(
"%15s ",
"min wait (ns)");
719 while ((st = pop_from_result())) {
750 print_bad_events(bad, total);
753 static bool info_threads, info_map;
755 static void dump_threads(
void)
761 pr_info(
"%10s: comm\n",
"Thread ID");
772 static void dump_map(
void)
777 pr_info(
"Address of instance: name of class\n");
785 static int dump_info(
void)
795 pr_err(
"Unknown type of information\n");
812 if (thread ==
NULL) {
813 pr_debug(
"problem processing %d event, skipping it.\n",
820 return f(evsel, sample);
827 {
"lock:lock_acquire", perf_evsel__process_lock_acquire, },
828 {
"lock:lock_acquired", perf_evsel__process_lock_acquired, },
829 {
"lock:lock_contended", perf_evsel__process_lock_contended, },
830 {
"lock:lock_release", perf_evsel__process_lock_release, },
833 static int read_events(
void)
836 .
sample = process_sample_event,
838 .ordered_samples =
true,
842 pr_err(
"Initializing perf session failed\n");
847 pr_err(
"Initializing perf session tracepoint handlers failed\n");
854 static void sort_result(
void)
861 insert_to_result(st, compare);
866 static int __cmd_report(
void)
870 if ((select_key() != 0) ||
871 (read_events() != 0))
880 static int __cmd_record(
int argc,
const char **argv)
882 const char *record_args[] = {
883 "record",
"-R",
"-f",
"-m",
"1024",
"-c",
"1",
885 unsigned int rec_argc,
i,
j;
886 const char **rec_argv;
888 for (i = 0; i <
ARRAY_SIZE(lock_tracepoints); i++) {
890 pr_err(
"tracepoint %s is not enabled. "
891 "Are CONFIG_LOCKDEP and CONFIG_LOCK_STAT enabled?\n",
892 lock_tracepoints[i].name);
897 rec_argc =
ARRAY_SIZE(record_args) + argc - 1;
901 rec_argv = calloc(rec_argc + 1,
sizeof(
char *));
902 if (rec_argv ==
NULL)
906 rec_argv[i] = strdup(record_args[i]);
908 for (j = 0; j <
ARRAY_SIZE(lock_tracepoints); j++) {
909 rec_argv[i++] =
"-e";
910 rec_argv[i++] = strdup(lock_tracepoints[j].name);
913 for (j = 1; j < (
unsigned int)argc; j++, i++)
914 rec_argv[i] = argv[j];
923 const struct option info_options[] = {
925 "dump thread list in perf.data"),
927 "map of lock instances (address:name table)"),
930 const struct option lock_options[] = {
931 OPT_STRING(
'i',
"input", &input_name,
"file",
"input file name"),
932 OPT_INCR(
'v',
"verbose", &
verbose,
"be more verbose (show symbol address, etc)"),
936 const struct option report_options[] = {
938 "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
942 const char *
const info_usage[] = {
943 "perf lock info [<options>]",
946 const char *
const lock_usage[] = {
947 "perf lock [<options>] {record|report|script|info}",
950 const char *
const report_usage[] = {
951 "perf lock report [<options>]",
959 INIT_LIST_HEAD(lockhash_table + i);
966 if (!
strncmp(argv[0],
"rec", 3)) {
967 return __cmd_record(argc, argv);
968 }
else if (!
strncmp(argv[0],
"report", 6)) {
969 trace_handler = &report_lock_ops;
972 report_options, report_usage, 0);
977 }
else if (!
strcmp(argv[0],
"script")) {
980 }
else if (!
strcmp(argv[0],
"info")) {
983 info_options, info_usage, 0);
988 trace_handler = &report_lock_ops;
990 if (read_events() != 0)