builtin-lock.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. #include "builtin.h"
  2. #include "perf.h"
  3. #include "util/evsel.h"
  4. #include "util/util.h"
  5. #include "util/cache.h"
  6. #include "util/symbol.h"
  7. #include "util/thread.h"
  8. #include "util/header.h"
  9. #include "util/parse-options.h"
  10. #include "util/trace-event.h"
  11. #include "util/debug.h"
  12. #include "util/session.h"
  13. #include "util/tool.h"
  14. #include <sys/types.h>
  15. #include <sys/prctl.h>
  16. #include <semaphore.h>
  17. #include <pthread.h>
  18. #include <math.h>
  19. #include <limits.h>
  20. #include <linux/list.h>
  21. #include <linux/hash.h>
  22. static struct perf_session *session;
  23. /* based on kernel/lockdep.c */
  24. #define LOCKHASH_BITS 12
  25. #define LOCKHASH_SIZE (1UL << LOCKHASH_BITS)
  26. static struct list_head lockhash_table[LOCKHASH_SIZE];
  27. #define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS)
  28. #define lockhashentry(key) (lockhash_table + __lockhashfn((key)))
  29. struct lock_stat {
  30. struct list_head hash_entry;
  31. struct rb_node rb; /* used for sorting */
  32. /*
  33. * FIXME: raw_field_value() returns unsigned long long,
  34. * so address of lockdep_map should be dealed as 64bit.
  35. * Is there more better solution?
  36. */
  37. void *addr; /* address of lockdep_map, used as ID */
  38. char *name; /* for strcpy(), we cannot use const */
  39. unsigned int nr_acquire;
  40. unsigned int nr_acquired;
  41. unsigned int nr_contended;
  42. unsigned int nr_release;
  43. unsigned int nr_readlock;
  44. unsigned int nr_trylock;
  45. /* these times are in nano sec. */
  46. u64 wait_time_total;
  47. u64 wait_time_min;
  48. u64 wait_time_max;
  49. int discard; /* flag of blacklist */
  50. };
  51. /*
  52. * States of lock_seq_stat
  53. *
  54. * UNINITIALIZED is required for detecting first event of acquire.
  55. * As the nature of lock events, there is no guarantee
  56. * that the first event for the locks are acquire,
  57. * it can be acquired, contended or release.
  58. */
  59. #define SEQ_STATE_UNINITIALIZED 0 /* initial state */
  60. #define SEQ_STATE_RELEASED 1
  61. #define SEQ_STATE_ACQUIRING 2
  62. #define SEQ_STATE_ACQUIRED 3
  63. #define SEQ_STATE_READ_ACQUIRED 4
  64. #define SEQ_STATE_CONTENDED 5
  65. /*
  66. * MAX_LOCK_DEPTH
  67. * Imported from include/linux/sched.h.
  68. * Should this be synchronized?
  69. */
  70. #define MAX_LOCK_DEPTH 48
  71. /*
  72. * struct lock_seq_stat:
  73. * Place to put on state of one lock sequence
  74. * 1) acquire -> acquired -> release
  75. * 2) acquire -> contended -> acquired -> release
  76. * 3) acquire (with read or try) -> release
  77. * 4) Are there other patterns?
  78. */
  79. struct lock_seq_stat {
  80. struct list_head list;
  81. int state;
  82. u64 prev_event_time;
  83. void *addr;
  84. int read_count;
  85. };
  86. struct thread_stat {
  87. struct rb_node rb;
  88. u32 tid;
  89. struct list_head seq_list;
  90. };
  91. static struct rb_root thread_stats;
  92. static struct thread_stat *thread_stat_find(u32 tid)
  93. {
  94. struct rb_node *node;
  95. struct thread_stat *st;
  96. node = thread_stats.rb_node;
  97. while (node) {
  98. st = container_of(node, struct thread_stat, rb);
  99. if (st->tid == tid)
  100. return st;
  101. else if (tid < st->tid)
  102. node = node->rb_left;
  103. else
  104. node = node->rb_right;
  105. }
  106. return NULL;
  107. }
  108. static void thread_stat_insert(struct thread_stat *new)
  109. {
  110. struct rb_node **rb = &thread_stats.rb_node;
  111. struct rb_node *parent = NULL;
  112. struct thread_stat *p;
  113. while (*rb) {
  114. p = container_of(*rb, struct thread_stat, rb);
  115. parent = *rb;
  116. if (new->tid < p->tid)
  117. rb = &(*rb)->rb_left;
  118. else if (new->tid > p->tid)
  119. rb = &(*rb)->rb_right;
  120. else
  121. BUG_ON("inserting invalid thread_stat\n");
  122. }
  123. rb_link_node(&new->rb, parent, rb);
  124. rb_insert_color(&new->rb, &thread_stats);
  125. }
  126. static struct thread_stat *thread_stat_findnew_after_first(u32 tid)
  127. {
  128. struct thread_stat *st;
  129. st = thread_stat_find(tid);
  130. if (st)
  131. return st;
  132. st = zalloc(sizeof(struct thread_stat));
  133. if (!st)
  134. die("memory allocation failed\n");
  135. st->tid = tid;
  136. INIT_LIST_HEAD(&st->seq_list);
  137. thread_stat_insert(st);
  138. return st;
  139. }
  140. static struct thread_stat *thread_stat_findnew_first(u32 tid);
  141. static struct thread_stat *(*thread_stat_findnew)(u32 tid) =
  142. thread_stat_findnew_first;
  143. static struct thread_stat *thread_stat_findnew_first(u32 tid)
  144. {
  145. struct thread_stat *st;
  146. st = zalloc(sizeof(struct thread_stat));
  147. if (!st)
  148. die("memory allocation failed\n");
  149. st->tid = tid;
  150. INIT_LIST_HEAD(&st->seq_list);
  151. rb_link_node(&st->rb, NULL, &thread_stats.rb_node);
  152. rb_insert_color(&st->rb, &thread_stats);
  153. thread_stat_findnew = thread_stat_findnew_after_first;
  154. return st;
  155. }
  156. /* build simple key function one is bigger than two */
  157. #define SINGLE_KEY(member) \
  158. static int lock_stat_key_ ## member(struct lock_stat *one, \
  159. struct lock_stat *two) \
  160. { \
  161. return one->member > two->member; \
  162. }
  163. SINGLE_KEY(nr_acquired)
  164. SINGLE_KEY(nr_contended)
  165. SINGLE_KEY(wait_time_total)
  166. SINGLE_KEY(wait_time_max)
  167. static int lock_stat_key_wait_time_min(struct lock_stat *one,
  168. struct lock_stat *two)
  169. {
  170. u64 s1 = one->wait_time_min;
  171. u64 s2 = two->wait_time_min;
  172. if (s1 == ULLONG_MAX)
  173. s1 = 0;
  174. if (s2 == ULLONG_MAX)
  175. s2 = 0;
  176. return s1 > s2;
  177. }
  178. struct lock_key {
  179. /*
  180. * name: the value for specify by user
  181. * this should be simpler than raw name of member
  182. * e.g. nr_acquired -> acquired, wait_time_total -> wait_total
  183. */
  184. const char *name;
  185. int (*key)(struct lock_stat*, struct lock_stat*);
  186. };
  187. static const char *sort_key = "acquired";
  188. static int (*compare)(struct lock_stat *, struct lock_stat *);
  189. static struct rb_root result; /* place to store sorted data */
  190. #define DEF_KEY_LOCK(name, fn_suffix) \
  191. { #name, lock_stat_key_ ## fn_suffix }
  192. struct lock_key keys[] = {
  193. DEF_KEY_LOCK(acquired, nr_acquired),
  194. DEF_KEY_LOCK(contended, nr_contended),
  195. DEF_KEY_LOCK(wait_total, wait_time_total),
  196. DEF_KEY_LOCK(wait_min, wait_time_min),
  197. DEF_KEY_LOCK(wait_max, wait_time_max),
  198. /* extra comparisons much complicated should be here */
  199. { NULL, NULL }
  200. };
  201. static void select_key(void)
  202. {
  203. int i;
  204. for (i = 0; keys[i].name; i++) {
  205. if (!strcmp(keys[i].name, sort_key)) {
  206. compare = keys[i].key;
  207. return;
  208. }
  209. }
  210. die("Unknown compare key:%s\n", sort_key);
  211. }
  212. static void insert_to_result(struct lock_stat *st,
  213. int (*bigger)(struct lock_stat *, struct lock_stat *))
  214. {
  215. struct rb_node **rb = &result.rb_node;
  216. struct rb_node *parent = NULL;
  217. struct lock_stat *p;
  218. while (*rb) {
  219. p = container_of(*rb, struct lock_stat, rb);
  220. parent = *rb;
  221. if (bigger(st, p))
  222. rb = &(*rb)->rb_left;
  223. else
  224. rb = &(*rb)->rb_right;
  225. }
  226. rb_link_node(&st->rb, parent, rb);
  227. rb_insert_color(&st->rb, &result);
  228. }
  229. /* returns left most element of result, and erase it */
  230. static struct lock_stat *pop_from_result(void)
  231. {
  232. struct rb_node *node = result.rb_node;
  233. if (!node)
  234. return NULL;
  235. while (node->rb_left)
  236. node = node->rb_left;
  237. rb_erase(node, &result);
  238. return container_of(node, struct lock_stat, rb);
  239. }
  240. static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
  241. {
  242. struct list_head *entry = lockhashentry(addr);
  243. struct lock_stat *ret, *new;
  244. list_for_each_entry(ret, entry, hash_entry) {
  245. if (ret->addr == addr)
  246. return ret;
  247. }
  248. new = zalloc(sizeof(struct lock_stat));
  249. if (!new)
  250. goto alloc_failed;
  251. new->addr = addr;
  252. new->name = zalloc(sizeof(char) * strlen(name) + 1);
  253. if (!new->name)
  254. goto alloc_failed;
  255. strcpy(new->name, name);
  256. new->wait_time_min = ULLONG_MAX;
  257. list_add(&new->hash_entry, entry);
  258. return new;
  259. alloc_failed:
  260. die("memory allocation failed\n");
  261. }
  262. static const char *input_name;
  263. struct raw_event_sample {
  264. u32 size;
  265. char data[0];
  266. };
  267. struct trace_acquire_event {
  268. void *addr;
  269. const char *name;
  270. int flag;
  271. };
  272. struct trace_acquired_event {
  273. void *addr;
  274. const char *name;
  275. };
  276. struct trace_contended_event {
  277. void *addr;
  278. const char *name;
  279. };
  280. struct trace_release_event {
  281. void *addr;
  282. const char *name;
  283. };
  284. struct trace_lock_handler {
  285. void (*acquire_event)(struct trace_acquire_event *,
  286. const struct perf_sample *sample);
  287. void (*acquired_event)(struct trace_acquired_event *,
  288. const struct perf_sample *sample);
  289. void (*contended_event)(struct trace_contended_event *,
  290. const struct perf_sample *sample);
  291. void (*release_event)(struct trace_release_event *,
  292. const struct perf_sample *sample);
  293. };
  294. static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr)
  295. {
  296. struct lock_seq_stat *seq;
  297. list_for_each_entry(seq, &ts->seq_list, list) {
  298. if (seq->addr == addr)
  299. return seq;
  300. }
  301. seq = zalloc(sizeof(struct lock_seq_stat));
  302. if (!seq)
  303. die("Not enough memory\n");
  304. seq->state = SEQ_STATE_UNINITIALIZED;
  305. seq->addr = addr;
  306. list_add(&seq->list, &ts->seq_list);
  307. return seq;
  308. }
  309. enum broken_state {
  310. BROKEN_ACQUIRE,
  311. BROKEN_ACQUIRED,
  312. BROKEN_CONTENDED,
  313. BROKEN_RELEASE,
  314. BROKEN_MAX,
  315. };
  316. static int bad_hist[BROKEN_MAX];
  317. enum acquire_flags {
  318. TRY_LOCK = 1,
  319. READ_LOCK = 2,
  320. };
  321. static void
  322. report_lock_acquire_event(struct trace_acquire_event *acquire_event,
  323. const struct perf_sample *sample)
  324. {
  325. struct lock_stat *ls;
  326. struct thread_stat *ts;
  327. struct lock_seq_stat *seq;
  328. ls = lock_stat_findnew(acquire_event->addr, acquire_event->name);
  329. if (ls->discard)
  330. return;
  331. ts = thread_stat_findnew(sample->tid);
  332. seq = get_seq(ts, acquire_event->addr);
  333. switch (seq->state) {
  334. case SEQ_STATE_UNINITIALIZED:
  335. case SEQ_STATE_RELEASED:
  336. if (!acquire_event->flag) {
  337. seq->state = SEQ_STATE_ACQUIRING;
  338. } else {
  339. if (acquire_event->flag & TRY_LOCK)
  340. ls->nr_trylock++;
  341. if (acquire_event->flag & READ_LOCK)
  342. ls->nr_readlock++;
  343. seq->state = SEQ_STATE_READ_ACQUIRED;
  344. seq->read_count = 1;
  345. ls->nr_acquired++;
  346. }
  347. break;
  348. case SEQ_STATE_READ_ACQUIRED:
  349. if (acquire_event->flag & READ_LOCK) {
  350. seq->read_count++;
  351. ls->nr_acquired++;
  352. goto end;
  353. } else {
  354. goto broken;
  355. }
  356. break;
  357. case SEQ_STATE_ACQUIRED:
  358. case SEQ_STATE_ACQUIRING:
  359. case SEQ_STATE_CONTENDED:
  360. broken:
  361. /* broken lock sequence, discard it */
  362. ls->discard = 1;
  363. bad_hist[BROKEN_ACQUIRE]++;
  364. list_del(&seq->list);
  365. free(seq);
  366. goto end;
  367. break;
  368. default:
  369. BUG_ON("Unknown state of lock sequence found!\n");
  370. break;
  371. }
  372. ls->nr_acquire++;
  373. seq->prev_event_time = sample->time;
  374. end:
  375. return;
  376. }
  377. static void
  378. report_lock_acquired_event(struct trace_acquired_event *acquired_event,
  379. const struct perf_sample *sample)
  380. {
  381. u64 timestamp = sample->time;
  382. struct lock_stat *ls;
  383. struct thread_stat *ts;
  384. struct lock_seq_stat *seq;
  385. u64 contended_term;
  386. ls = lock_stat_findnew(acquired_event->addr, acquired_event->name);
  387. if (ls->discard)
  388. return;
  389. ts = thread_stat_findnew(sample->tid);
  390. seq = get_seq(ts, acquired_event->addr);
  391. switch (seq->state) {
  392. case SEQ_STATE_UNINITIALIZED:
  393. /* orphan event, do nothing */
  394. return;
  395. case SEQ_STATE_ACQUIRING:
  396. break;
  397. case SEQ_STATE_CONTENDED:
  398. contended_term = timestamp - seq->prev_event_time;
  399. ls->wait_time_total += contended_term;
  400. if (contended_term < ls->wait_time_min)
  401. ls->wait_time_min = contended_term;
  402. if (ls->wait_time_max < contended_term)
  403. ls->wait_time_max = contended_term;
  404. break;
  405. case SEQ_STATE_RELEASED:
  406. case SEQ_STATE_ACQUIRED:
  407. case SEQ_STATE_READ_ACQUIRED:
  408. /* broken lock sequence, discard it */
  409. ls->discard = 1;
  410. bad_hist[BROKEN_ACQUIRED]++;
  411. list_del(&seq->list);
  412. free(seq);
  413. goto end;
  414. break;
  415. default:
  416. BUG_ON("Unknown state of lock sequence found!\n");
  417. break;
  418. }
  419. seq->state = SEQ_STATE_ACQUIRED;
  420. ls->nr_acquired++;
  421. seq->prev_event_time = timestamp;
  422. end:
  423. return;
  424. }
  425. static void
  426. report_lock_contended_event(struct trace_contended_event *contended_event,
  427. const struct perf_sample *sample)
  428. {
  429. struct lock_stat *ls;
  430. struct thread_stat *ts;
  431. struct lock_seq_stat *seq;
  432. ls = lock_stat_findnew(contended_event->addr, contended_event->name);
  433. if (ls->discard)
  434. return;
  435. ts = thread_stat_findnew(sample->tid);
  436. seq = get_seq(ts, contended_event->addr);
  437. switch (seq->state) {
  438. case SEQ_STATE_UNINITIALIZED:
  439. /* orphan event, do nothing */
  440. return;
  441. case SEQ_STATE_ACQUIRING:
  442. break;
  443. case SEQ_STATE_RELEASED:
  444. case SEQ_STATE_ACQUIRED:
  445. case SEQ_STATE_READ_ACQUIRED:
  446. case SEQ_STATE_CONTENDED:
  447. /* broken lock sequence, discard it */
  448. ls->discard = 1;
  449. bad_hist[BROKEN_CONTENDED]++;
  450. list_del(&seq->list);
  451. free(seq);
  452. goto end;
  453. break;
  454. default:
  455. BUG_ON("Unknown state of lock sequence found!\n");
  456. break;
  457. }
  458. seq->state = SEQ_STATE_CONTENDED;
  459. ls->nr_contended++;
  460. seq->prev_event_time = sample->time;
  461. end:
  462. return;
  463. }
  464. static void
  465. report_lock_release_event(struct trace_release_event *release_event,
  466. const struct perf_sample *sample)
  467. {
  468. struct lock_stat *ls;
  469. struct thread_stat *ts;
  470. struct lock_seq_stat *seq;
  471. ls = lock_stat_findnew(release_event->addr, release_event->name);
  472. if (ls->discard)
  473. return;
  474. ts = thread_stat_findnew(sample->tid);
  475. seq = get_seq(ts, release_event->addr);
  476. switch (seq->state) {
  477. case SEQ_STATE_UNINITIALIZED:
  478. goto end;
  479. break;
  480. case SEQ_STATE_ACQUIRED:
  481. break;
  482. case SEQ_STATE_READ_ACQUIRED:
  483. seq->read_count--;
  484. BUG_ON(seq->read_count < 0);
  485. if (!seq->read_count) {
  486. ls->nr_release++;
  487. goto end;
  488. }
  489. break;
  490. case SEQ_STATE_ACQUIRING:
  491. case SEQ_STATE_CONTENDED:
  492. case SEQ_STATE_RELEASED:
  493. /* broken lock sequence, discard it */
  494. ls->discard = 1;
  495. bad_hist[BROKEN_RELEASE]++;
  496. goto free_seq;
  497. break;
  498. default:
  499. BUG_ON("Unknown state of lock sequence found!\n");
  500. break;
  501. }
  502. ls->nr_release++;
  503. free_seq:
  504. list_del(&seq->list);
  505. free(seq);
  506. end:
  507. return;
  508. }
  509. /* lock oriented handlers */
  510. /* TODO: handlers for CPU oriented, thread oriented */
  511. static struct trace_lock_handler report_lock_ops = {
  512. .acquire_event = report_lock_acquire_event,
  513. .acquired_event = report_lock_acquired_event,
  514. .contended_event = report_lock_contended_event,
  515. .release_event = report_lock_release_event,
  516. };
  517. static struct trace_lock_handler *trace_handler;
  518. static void perf_evsel__process_lock_acquire(struct perf_evsel *evsel,
  519. struct perf_sample *sample)
  520. {
  521. struct trace_acquire_event acquire_event;
  522. struct event_format *event = evsel->tp_format;
  523. void *data = sample->raw_data;
  524. u64 tmp; /* this is required for casting... */
  525. tmp = raw_field_value(event, "lockdep_addr", data);
  526. memcpy(&acquire_event.addr, &tmp, sizeof(void *));
  527. acquire_event.name = (char *)raw_field_ptr(event, "name", data);
  528. acquire_event.flag = (int)raw_field_value(event, "flag", data);
  529. if (trace_handler->acquire_event)
  530. trace_handler->acquire_event(&acquire_event, sample);
  531. }
  532. static void perf_evsel__process_lock_acquired(struct perf_evsel *evsel,
  533. struct perf_sample *sample)
  534. {
  535. struct trace_acquired_event acquired_event;
  536. struct event_format *event = evsel->tp_format;
  537. void *data = sample->raw_data;
  538. u64 tmp; /* this is required for casting... */
  539. tmp = raw_field_value(event, "lockdep_addr", data);
  540. memcpy(&acquired_event.addr, &tmp, sizeof(void *));
  541. acquired_event.name = (char *)raw_field_ptr(event, "name", data);
  542. if (trace_handler->acquire_event)
  543. trace_handler->acquired_event(&acquired_event, sample);
  544. }
  545. static void perf_evsel__process_lock_contended(struct perf_evsel *evsel,
  546. struct perf_sample *sample)
  547. {
  548. struct trace_contended_event contended_event;
  549. struct event_format *event = evsel->tp_format;
  550. void *data = sample->raw_data;
  551. u64 tmp; /* this is required for casting... */
  552. tmp = raw_field_value(event, "lockdep_addr", data);
  553. memcpy(&contended_event.addr, &tmp, sizeof(void *));
  554. contended_event.name = (char *)raw_field_ptr(event, "name", data);
  555. if (trace_handler->acquire_event)
  556. trace_handler->contended_event(&contended_event, sample);
  557. }
  558. static void perf_evsel__process_lock_release(struct perf_evsel *evsel,
  559. struct perf_sample *sample)
  560. {
  561. struct trace_release_event release_event;
  562. struct event_format *event = evsel->tp_format;
  563. void *data = sample->raw_data;
  564. u64 tmp; /* this is required for casting... */
  565. tmp = raw_field_value(event, "lockdep_addr", data);
  566. memcpy(&release_event.addr, &tmp, sizeof(void *));
  567. release_event.name = (char *)raw_field_ptr(event, "name", data);
  568. if (trace_handler->acquire_event)
  569. trace_handler->release_event(&release_event, sample);
  570. }
  571. static void perf_evsel__process_lock_event(struct perf_evsel *evsel,
  572. struct perf_sample *sample)
  573. {
  574. struct event_format *event = evsel->tp_format;
  575. if (!strcmp(event->name, "lock_acquire"))
  576. perf_evsel__process_lock_acquire(evsel, sample);
  577. if (!strcmp(event->name, "lock_acquired"))
  578. perf_evsel__process_lock_acquired(evsel, sample);
  579. if (!strcmp(event->name, "lock_contended"))
  580. perf_evsel__process_lock_contended(evsel, sample);
  581. if (!strcmp(event->name, "lock_release"))
  582. perf_evsel__process_lock_release(evsel, sample);
  583. }
  584. static void print_bad_events(int bad, int total)
  585. {
  586. /* Output for debug, this have to be removed */
  587. int i;
  588. const char *name[4] =
  589. { "acquire", "acquired", "contended", "release" };
  590. pr_info("\n=== output for debug===\n\n");
  591. pr_info("bad: %d, total: %d\n", bad, total);
  592. pr_info("bad rate: %f %%\n", (double)bad / (double)total * 100);
  593. pr_info("histogram of events caused bad sequence\n");
  594. for (i = 0; i < BROKEN_MAX; i++)
  595. pr_info(" %10s: %d\n", name[i], bad_hist[i]);
  596. }
  597. /* TODO: various way to print, coloring, nano or milli sec */
  598. static void print_result(void)
  599. {
  600. struct lock_stat *st;
  601. char cut_name[20];
  602. int bad, total;
  603. pr_info("%20s ", "Name");
  604. pr_info("%10s ", "acquired");
  605. pr_info("%10s ", "contended");
  606. pr_info("%15s ", "total wait (ns)");
  607. pr_info("%15s ", "max wait (ns)");
  608. pr_info("%15s ", "min wait (ns)");
  609. pr_info("\n\n");
  610. bad = total = 0;
  611. while ((st = pop_from_result())) {
  612. total++;
  613. if (st->discard) {
  614. bad++;
  615. continue;
  616. }
  617. bzero(cut_name, 20);
  618. if (strlen(st->name) < 16) {
  619. /* output raw name */
  620. pr_info("%20s ", st->name);
  621. } else {
  622. strncpy(cut_name, st->name, 16);
  623. cut_name[16] = '.';
  624. cut_name[17] = '.';
  625. cut_name[18] = '.';
  626. cut_name[19] = '\0';
  627. /* cut off name for saving output style */
  628. pr_info("%20s ", cut_name);
  629. }
  630. pr_info("%10u ", st->nr_acquired);
  631. pr_info("%10u ", st->nr_contended);
  632. pr_info("%15" PRIu64 " ", st->wait_time_total);
  633. pr_info("%15" PRIu64 " ", st->wait_time_max);
  634. pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ?
  635. 0 : st->wait_time_min);
  636. pr_info("\n");
  637. }
  638. print_bad_events(bad, total);
  639. }
  640. static bool info_threads, info_map;
  641. static void dump_threads(void)
  642. {
  643. struct thread_stat *st;
  644. struct rb_node *node;
  645. struct thread *t;
  646. pr_info("%10s: comm\n", "Thread ID");
  647. node = rb_first(&thread_stats);
  648. while (node) {
  649. st = container_of(node, struct thread_stat, rb);
  650. t = perf_session__findnew(session, st->tid);
  651. pr_info("%10d: %s\n", st->tid, t->comm);
  652. node = rb_next(node);
  653. };
  654. }
  655. static void dump_map(void)
  656. {
  657. unsigned int i;
  658. struct lock_stat *st;
  659. pr_info("Address of instance: name of class\n");
  660. for (i = 0; i < LOCKHASH_SIZE; i++) {
  661. list_for_each_entry(st, &lockhash_table[i], hash_entry) {
  662. pr_info(" %p: %s\n", st->addr, st->name);
  663. }
  664. }
  665. }
  666. static void dump_info(void)
  667. {
  668. if (info_threads)
  669. dump_threads();
  670. else if (info_map)
  671. dump_map();
  672. else
  673. die("Unknown type of information\n");
  674. }
  675. static int process_sample_event(struct perf_tool *tool __used,
  676. union perf_event *event,
  677. struct perf_sample *sample,
  678. struct perf_evsel *evsel,
  679. struct machine *machine)
  680. {
  681. struct thread *thread = machine__findnew_thread(machine, sample->tid);
  682. if (thread == NULL) {
  683. pr_debug("problem processing %d event, skipping it.\n",
  684. event->header.type);
  685. return -1;
  686. }
  687. perf_evsel__process_lock_event(evsel, sample);
  688. return 0;
  689. }
  690. static struct perf_tool eops = {
  691. .sample = process_sample_event,
  692. .comm = perf_event__process_comm,
  693. .ordered_samples = true,
  694. };
  695. static int read_events(void)
  696. {
  697. session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
  698. if (!session)
  699. die("Initializing perf session failed\n");
  700. return perf_session__process_events(session, &eops);
  701. }
  702. static void sort_result(void)
  703. {
  704. unsigned int i;
  705. struct lock_stat *st;
  706. for (i = 0; i < LOCKHASH_SIZE; i++) {
  707. list_for_each_entry(st, &lockhash_table[i], hash_entry) {
  708. insert_to_result(st, compare);
  709. }
  710. }
  711. }
  712. static void __cmd_report(void)
  713. {
  714. setup_pager();
  715. select_key();
  716. read_events();
  717. sort_result();
  718. print_result();
  719. }
  720. static const char * const report_usage[] = {
  721. "perf lock report [<options>]",
  722. NULL
  723. };
  724. static const struct option report_options[] = {
  725. OPT_STRING('k', "key", &sort_key, "acquired",
  726. "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
  727. /* TODO: type */
  728. OPT_END()
  729. };
  730. static const char * const info_usage[] = {
  731. "perf lock info [<options>]",
  732. NULL
  733. };
  734. static const struct option info_options[] = {
  735. OPT_BOOLEAN('t', "threads", &info_threads,
  736. "dump thread list in perf.data"),
  737. OPT_BOOLEAN('m', "map", &info_map,
  738. "map of lock instances (address:name table)"),
  739. OPT_END()
  740. };
  741. static const char * const lock_usage[] = {
  742. "perf lock [<options>] {record|report|script|info}",
  743. NULL
  744. };
  745. static const struct option lock_options[] = {
  746. OPT_STRING('i', "input", &input_name, "file", "input file name"),
  747. OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
  748. OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
  749. OPT_END()
  750. };
  751. static const char *record_args[] = {
  752. "record",
  753. "-R",
  754. "-f",
  755. "-m", "1024",
  756. "-c", "1",
  757. "-e", "lock:lock_acquire",
  758. "-e", "lock:lock_acquired",
  759. "-e", "lock:lock_contended",
  760. "-e", "lock:lock_release",
  761. };
  762. static int __cmd_record(int argc, const char **argv)
  763. {
  764. unsigned int rec_argc, i, j;
  765. const char **rec_argv;
  766. rec_argc = ARRAY_SIZE(record_args) + argc - 1;
  767. rec_argv = calloc(rec_argc + 1, sizeof(char *));
  768. if (rec_argv == NULL)
  769. return -ENOMEM;
  770. for (i = 0; i < ARRAY_SIZE(record_args); i++)
  771. rec_argv[i] = strdup(record_args[i]);
  772. for (j = 1; j < (unsigned int)argc; j++, i++)
  773. rec_argv[i] = argv[j];
  774. BUG_ON(i != rec_argc);
  775. return cmd_record(i, rec_argv, NULL);
  776. }
  777. int cmd_lock(int argc, const char **argv, const char *prefix __used)
  778. {
  779. unsigned int i;
  780. symbol__init();
  781. for (i = 0; i < LOCKHASH_SIZE; i++)
  782. INIT_LIST_HEAD(lockhash_table + i);
  783. argc = parse_options(argc, argv, lock_options, lock_usage,
  784. PARSE_OPT_STOP_AT_NON_OPTION);
  785. if (!argc)
  786. usage_with_options(lock_usage, lock_options);
  787. if (!strncmp(argv[0], "rec", 3)) {
  788. return __cmd_record(argc, argv);
  789. } else if (!strncmp(argv[0], "report", 6)) {
  790. trace_handler = &report_lock_ops;
  791. if (argc) {
  792. argc = parse_options(argc, argv,
  793. report_options, report_usage, 0);
  794. if (argc)
  795. usage_with_options(report_usage, report_options);
  796. }
  797. __cmd_report();
  798. } else if (!strcmp(argv[0], "script")) {
  799. /* Aliased to 'perf script' */
  800. return cmd_script(argc, argv, prefix);
  801. } else if (!strcmp(argv[0], "info")) {
  802. if (argc) {
  803. argc = parse_options(argc, argv,
  804. info_options, info_usage, 0);
  805. if (argc)
  806. usage_with_options(info_usage, info_options);
  807. }
  808. /* recycling report_lock_ops */
  809. trace_handler = &report_lock_ops;
  810. setup_pager();
  811. read_events();
  812. dump_info();
  813. } else {
  814. usage_with_options(lock_usage, lock_options);
  815. }
  816. return 0;
  817. }