blob: 75153c87e65087cc2b02a29280d30c7c78b919bd [file] [log] [blame]
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +09001#include "builtin.h"
2#include "perf.h"
3
Arnaldo Carvalho de Melofcf65bf2012-08-07 09:58:03 -03004#include "util/evsel.h"
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +09005#include "util/util.h"
6#include "util/cache.h"
7#include "util/symbol.h"
8#include "util/thread.h"
9#include "util/header.h"
10
11#include "util/parse-options.h"
12#include "util/trace-event.h"
13
14#include "util/debug.h"
15#include "util/session.h"
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020016#include "util/tool.h"
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +090017
18#include <sys/types.h>
19#include <sys/prctl.h>
20#include <semaphore.h>
21#include <pthread.h>
22#include <math.h>
23#include <limits.h>
24
25#include <linux/list.h>
26#include <linux/hash.h>
27
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +090028static struct perf_session *session;
29
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +090030/* based on kernel/lockdep.c */
31#define LOCKHASH_BITS 12
32#define LOCKHASH_SIZE (1UL << LOCKHASH_BITS)
33
34static struct list_head lockhash_table[LOCKHASH_SIZE];
35
36#define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS)
37#define lockhashentry(key) (lockhash_table + __lockhashfn((key)))
38
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +090039struct lock_stat {
Ingo Molnar59f411b2010-01-31 08:27:58 +010040 struct list_head hash_entry;
41 struct rb_node rb; /* used for sorting */
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +090042
Ingo Molnar59f411b2010-01-31 08:27:58 +010043 /*
44 * FIXME: raw_field_value() returns unsigned long long,
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +090045 * so address of lockdep_map should be dealed as 64bit.
Ingo Molnar59f411b2010-01-31 08:27:58 +010046 * Is there more better solution?
47 */
48 void *addr; /* address of lockdep_map, used as ID */
49 char *name; /* for strcpy(), we cannot use const */
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +090050
Ingo Molnar59f411b2010-01-31 08:27:58 +010051 unsigned int nr_acquire;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +090052 unsigned int nr_acquired;
Ingo Molnar59f411b2010-01-31 08:27:58 +010053 unsigned int nr_contended;
54 unsigned int nr_release;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +090055
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +090056 unsigned int nr_readlock;
57 unsigned int nr_trylock;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +090058 /* these times are in nano sec. */
Ingo Molnar59f411b2010-01-31 08:27:58 +010059 u64 wait_time_total;
60 u64 wait_time_min;
61 u64 wait_time_max;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +090062
63 int discard; /* flag of blacklist */
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +090064};
65
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +090066/*
67 * States of lock_seq_stat
68 *
69 * UNINITIALIZED is required for detecting first event of acquire.
70 * As the nature of lock events, there is no guarantee
71 * that the first event for the locks are acquire,
72 * it can be acquired, contended or release.
73 */
74#define SEQ_STATE_UNINITIALIZED 0 /* initial state */
75#define SEQ_STATE_RELEASED 1
76#define SEQ_STATE_ACQUIRING 2
77#define SEQ_STATE_ACQUIRED 3
78#define SEQ_STATE_READ_ACQUIRED 4
79#define SEQ_STATE_CONTENDED 5
80
81/*
82 * MAX_LOCK_DEPTH
83 * Imported from include/linux/sched.h.
84 * Should this be synchronized?
85 */
86#define MAX_LOCK_DEPTH 48
87
88/*
89 * struct lock_seq_stat:
90 * Place to put on state of one lock sequence
91 * 1) acquire -> acquired -> release
92 * 2) acquire -> contended -> acquired -> release
93 * 3) acquire (with read or try) -> release
94 * 4) Are there other patterns?
95 */
96struct lock_seq_stat {
97 struct list_head list;
98 int state;
99 u64 prev_event_time;
100 void *addr;
101
102 int read_count;
103};
104
105struct thread_stat {
106 struct rb_node rb;
107
108 u32 tid;
109 struct list_head seq_list;
110};
111
112static struct rb_root thread_stats;
113
114static struct thread_stat *thread_stat_find(u32 tid)
115{
116 struct rb_node *node;
117 struct thread_stat *st;
118
119 node = thread_stats.rb_node;
120 while (node) {
121 st = container_of(node, struct thread_stat, rb);
122 if (st->tid == tid)
123 return st;
124 else if (tid < st->tid)
125 node = node->rb_left;
126 else
127 node = node->rb_right;
128 }
129
130 return NULL;
131}
132
133static void thread_stat_insert(struct thread_stat *new)
134{
135 struct rb_node **rb = &thread_stats.rb_node;
136 struct rb_node *parent = NULL;
137 struct thread_stat *p;
138
139 while (*rb) {
140 p = container_of(*rb, struct thread_stat, rb);
141 parent = *rb;
142
143 if (new->tid < p->tid)
144 rb = &(*rb)->rb_left;
145 else if (new->tid > p->tid)
146 rb = &(*rb)->rb_right;
147 else
148 BUG_ON("inserting invalid thread_stat\n");
149 }
150
151 rb_link_node(&new->rb, parent, rb);
152 rb_insert_color(&new->rb, &thread_stats);
153}
154
155static struct thread_stat *thread_stat_findnew_after_first(u32 tid)
156{
157 struct thread_stat *st;
158
159 st = thread_stat_find(tid);
160 if (st)
161 return st;
162
163 st = zalloc(sizeof(struct thread_stat));
David Ahern33d6aef2012-08-26 12:24:43 -0600164 if (!st) {
165 pr_err("memory allocation failed\n");
166 return NULL;
167 }
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900168
169 st->tid = tid;
170 INIT_LIST_HEAD(&st->seq_list);
171
172 thread_stat_insert(st);
173
174 return st;
175}
176
177static struct thread_stat *thread_stat_findnew_first(u32 tid);
178static struct thread_stat *(*thread_stat_findnew)(u32 tid) =
179 thread_stat_findnew_first;
180
181static struct thread_stat *thread_stat_findnew_first(u32 tid)
182{
183 struct thread_stat *st;
184
185 st = zalloc(sizeof(struct thread_stat));
David Ahern33d6aef2012-08-26 12:24:43 -0600186 if (!st) {
187 pr_err("memory allocation failed\n");
188 return NULL;
189 }
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900190 st->tid = tid;
191 INIT_LIST_HEAD(&st->seq_list);
192
193 rb_link_node(&st->rb, NULL, &thread_stats.rb_node);
194 rb_insert_color(&st->rb, &thread_stats);
195
196 thread_stat_findnew = thread_stat_findnew_after_first;
197 return st;
198}
199
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900200/* build simple key function one is bigger than two */
Ingo Molnar59f411b2010-01-31 08:27:58 +0100201#define SINGLE_KEY(member) \
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900202 static int lock_stat_key_ ## member(struct lock_stat *one, \
203 struct lock_stat *two) \
204 { \
205 return one->member > two->member; \
206 }
207
208SINGLE_KEY(nr_acquired)
209SINGLE_KEY(nr_contended)
210SINGLE_KEY(wait_time_total)
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900211SINGLE_KEY(wait_time_max)
212
Marcin Slusarz9df03ab2011-02-22 18:47:15 +0100213static int lock_stat_key_wait_time_min(struct lock_stat *one,
214 struct lock_stat *two)
215{
216 u64 s1 = one->wait_time_min;
217 u64 s2 = two->wait_time_min;
218 if (s1 == ULLONG_MAX)
219 s1 = 0;
220 if (s2 == ULLONG_MAX)
221 s2 = 0;
222 return s1 > s2;
223}
224
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900225struct lock_key {
226 /*
227 * name: the value for specify by user
228 * this should be simpler than raw name of member
229 * e.g. nr_acquired -> acquired, wait_time_total -> wait_total
230 */
Ingo Molnar59f411b2010-01-31 08:27:58 +0100231 const char *name;
232 int (*key)(struct lock_stat*, struct lock_stat*);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900233};
234
Ingo Molnar59f411b2010-01-31 08:27:58 +0100235static const char *sort_key = "acquired";
236
237static int (*compare)(struct lock_stat *, struct lock_stat *);
238
239static struct rb_root result; /* place to store sorted data */
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900240
241#define DEF_KEY_LOCK(name, fn_suffix) \
242 { #name, lock_stat_key_ ## fn_suffix }
243struct lock_key keys[] = {
244 DEF_KEY_LOCK(acquired, nr_acquired),
245 DEF_KEY_LOCK(contended, nr_contended),
246 DEF_KEY_LOCK(wait_total, wait_time_total),
247 DEF_KEY_LOCK(wait_min, wait_time_min),
248 DEF_KEY_LOCK(wait_max, wait_time_max),
249
250 /* extra comparisons much complicated should be here */
251
252 { NULL, NULL }
253};
254
David Ahern33d6aef2012-08-26 12:24:43 -0600255static int select_key(void)
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900256{
257 int i;
258
259 for (i = 0; keys[i].name; i++) {
260 if (!strcmp(keys[i].name, sort_key)) {
261 compare = keys[i].key;
David Ahern33d6aef2012-08-26 12:24:43 -0600262 return 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900263 }
264 }
265
David Ahern33d6aef2012-08-26 12:24:43 -0600266 pr_err("Unknown compare key: %s\n", sort_key);
267
268 return -1;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900269}
270
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900271static void insert_to_result(struct lock_stat *st,
Ingo Molnar59f411b2010-01-31 08:27:58 +0100272 int (*bigger)(struct lock_stat *, struct lock_stat *))
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900273{
274 struct rb_node **rb = &result.rb_node;
275 struct rb_node *parent = NULL;
276 struct lock_stat *p;
277
278 while (*rb) {
279 p = container_of(*rb, struct lock_stat, rb);
280 parent = *rb;
281
282 if (bigger(st, p))
283 rb = &(*rb)->rb_left;
284 else
285 rb = &(*rb)->rb_right;
286 }
287
288 rb_link_node(&st->rb, parent, rb);
289 rb_insert_color(&st->rb, &result);
290}
291
292/* returns left most element of result, and erase it */
293static struct lock_stat *pop_from_result(void)
294{
295 struct rb_node *node = result.rb_node;
296
297 if (!node)
298 return NULL;
299
300 while (node->rb_left)
301 node = node->rb_left;
302
303 rb_erase(node, &result);
304 return container_of(node, struct lock_stat, rb);
305}
306
Ingo Molnar59f411b2010-01-31 08:27:58 +0100307static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900308{
309 struct list_head *entry = lockhashentry(addr);
310 struct lock_stat *ret, *new;
311
312 list_for_each_entry(ret, entry, hash_entry) {
313 if (ret->addr == addr)
314 return ret;
315 }
316
317 new = zalloc(sizeof(struct lock_stat));
318 if (!new)
319 goto alloc_failed;
320
321 new->addr = addr;
322 new->name = zalloc(sizeof(char) * strlen(name) + 1);
323 if (!new->name)
324 goto alloc_failed;
325 strcpy(new->name, name);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900326
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900327 new->wait_time_min = ULLONG_MAX;
328
329 list_add(&new->hash_entry, entry);
330 return new;
331
332alloc_failed:
David Ahern33d6aef2012-08-26 12:24:43 -0600333 pr_err("memory allocation failed\n");
334 return NULL;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900335}
336
Robert Richterefad1412011-12-07 10:02:54 +0100337static const char *input_name;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900338
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900339struct raw_event_sample {
Ingo Molnar59f411b2010-01-31 08:27:58 +0100340 u32 size;
341 char data[0];
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900342};
343
344struct trace_acquire_event {
Ingo Molnar59f411b2010-01-31 08:27:58 +0100345 void *addr;
346 const char *name;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900347 int flag;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900348};
349
350struct trace_acquired_event {
Ingo Molnar59f411b2010-01-31 08:27:58 +0100351 void *addr;
352 const char *name;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900353};
354
355struct trace_contended_event {
Ingo Molnar59f411b2010-01-31 08:27:58 +0100356 void *addr;
357 const char *name;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900358};
359
360struct trace_release_event {
Ingo Molnar59f411b2010-01-31 08:27:58 +0100361 void *addr;
362 const char *name;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900363};
364
365struct trace_lock_handler {
David Ahern33d6aef2012-08-26 12:24:43 -0600366 int (*acquire_event)(struct trace_acquire_event *,
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300367 const struct perf_sample *sample);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900368
David Ahern33d6aef2012-08-26 12:24:43 -0600369 int (*acquired_event)(struct trace_acquired_event *,
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300370 const struct perf_sample *sample);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900371
David Ahern33d6aef2012-08-26 12:24:43 -0600372 int (*contended_event)(struct trace_contended_event *,
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300373 const struct perf_sample *sample);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900374
David Ahern33d6aef2012-08-26 12:24:43 -0600375 int (*release_event)(struct trace_release_event *,
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300376 const struct perf_sample *sample);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900377};
378
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900379static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr)
380{
381 struct lock_seq_stat *seq;
382
383 list_for_each_entry(seq, &ts->seq_list, list) {
384 if (seq->addr == addr)
385 return seq;
386 }
387
388 seq = zalloc(sizeof(struct lock_seq_stat));
David Ahern33d6aef2012-08-26 12:24:43 -0600389 if (!seq) {
390 pr_err("memory allocation failed\n");
391 return NULL;
392 }
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900393 seq->state = SEQ_STATE_UNINITIALIZED;
394 seq->addr = addr;
395
396 list_add(&seq->list, &ts->seq_list);
397 return seq;
398}
399
Frederic Weisbecker10350ec2010-05-05 23:47:28 +0200400enum broken_state {
401 BROKEN_ACQUIRE,
402 BROKEN_ACQUIRED,
403 BROKEN_CONTENDED,
404 BROKEN_RELEASE,
405 BROKEN_MAX,
406};
407
408static int bad_hist[BROKEN_MAX];
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900409
Frederic Weisbecker84c7a212010-05-05 23:57:25 +0200410enum acquire_flags {
411 TRY_LOCK = 1,
412 READ_LOCK = 2,
413};
414
David Ahern33d6aef2012-08-26 12:24:43 -0600415static int
Ingo Molnar59f411b2010-01-31 08:27:58 +0100416report_lock_acquire_event(struct trace_acquire_event *acquire_event,
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300417 const struct perf_sample *sample)
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900418{
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900419 struct lock_stat *ls;
420 struct thread_stat *ts;
421 struct lock_seq_stat *seq;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900422
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900423 ls = lock_stat_findnew(acquire_event->addr, acquire_event->name);
David Ahern33d6aef2012-08-26 12:24:43 -0600424 if (!ls)
425 return -1;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900426 if (ls->discard)
David Ahern33d6aef2012-08-26 12:24:43 -0600427 return 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900428
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300429 ts = thread_stat_findnew(sample->tid);
David Ahern33d6aef2012-08-26 12:24:43 -0600430 if (!ts)
431 return -1;
432
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900433 seq = get_seq(ts, acquire_event->addr);
David Ahern33d6aef2012-08-26 12:24:43 -0600434 if (!seq)
435 return -1;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900436
437 switch (seq->state) {
438 case SEQ_STATE_UNINITIALIZED:
439 case SEQ_STATE_RELEASED:
440 if (!acquire_event->flag) {
441 seq->state = SEQ_STATE_ACQUIRING;
442 } else {
Frederic Weisbecker84c7a212010-05-05 23:57:25 +0200443 if (acquire_event->flag & TRY_LOCK)
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900444 ls->nr_trylock++;
Frederic Weisbecker84c7a212010-05-05 23:57:25 +0200445 if (acquire_event->flag & READ_LOCK)
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900446 ls->nr_readlock++;
447 seq->state = SEQ_STATE_READ_ACQUIRED;
448 seq->read_count = 1;
449 ls->nr_acquired++;
450 }
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900451 break;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900452 case SEQ_STATE_READ_ACQUIRED:
Frederic Weisbecker84c7a212010-05-05 23:57:25 +0200453 if (acquire_event->flag & READ_LOCK) {
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900454 seq->read_count++;
455 ls->nr_acquired++;
456 goto end;
457 } else {
458 goto broken;
459 }
460 break;
461 case SEQ_STATE_ACQUIRED:
462 case SEQ_STATE_ACQUIRING:
463 case SEQ_STATE_CONTENDED:
464broken:
465 /* broken lock sequence, discard it */
466 ls->discard = 1;
Frederic Weisbecker10350ec2010-05-05 23:47:28 +0200467 bad_hist[BROKEN_ACQUIRE]++;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900468 list_del(&seq->list);
469 free(seq);
470 goto end;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900471 break;
472 default:
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900473 BUG_ON("Unknown state of lock sequence found!\n");
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900474 break;
475 }
476
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900477 ls->nr_acquire++;
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300478 seq->prev_event_time = sample->time;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900479end:
David Ahern33d6aef2012-08-26 12:24:43 -0600480 return 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900481}
482
David Ahern33d6aef2012-08-26 12:24:43 -0600483static int
Ingo Molnar59f411b2010-01-31 08:27:58 +0100484report_lock_acquired_event(struct trace_acquired_event *acquired_event,
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300485 const struct perf_sample *sample)
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900486{
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300487 u64 timestamp = sample->time;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900488 struct lock_stat *ls;
489 struct thread_stat *ts;
490 struct lock_seq_stat *seq;
491 u64 contended_term;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900492
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900493 ls = lock_stat_findnew(acquired_event->addr, acquired_event->name);
David Ahern33d6aef2012-08-26 12:24:43 -0600494 if (!ls)
495 return -1;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900496 if (ls->discard)
David Ahern33d6aef2012-08-26 12:24:43 -0600497 return 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900498
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300499 ts = thread_stat_findnew(sample->tid);
David Ahern33d6aef2012-08-26 12:24:43 -0600500 if (!ts)
501 return -1;
502
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900503 seq = get_seq(ts, acquired_event->addr);
David Ahern33d6aef2012-08-26 12:24:43 -0600504 if (!seq)
505 return -1;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900506
507 switch (seq->state) {
508 case SEQ_STATE_UNINITIALIZED:
509 /* orphan event, do nothing */
David Ahern33d6aef2012-08-26 12:24:43 -0600510 return 0;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900511 case SEQ_STATE_ACQUIRING:
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900512 break;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900513 case SEQ_STATE_CONTENDED:
514 contended_term = timestamp - seq->prev_event_time;
515 ls->wait_time_total += contended_term;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900516 if (contended_term < ls->wait_time_min)
517 ls->wait_time_min = contended_term;
Frederic Weisbecker90c0e5f2010-05-07 02:33:42 +0200518 if (ls->wait_time_max < contended_term)
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900519 ls->wait_time_max = contended_term;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900520 break;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900521 case SEQ_STATE_RELEASED:
522 case SEQ_STATE_ACQUIRED:
523 case SEQ_STATE_READ_ACQUIRED:
524 /* broken lock sequence, discard it */
525 ls->discard = 1;
Frederic Weisbecker10350ec2010-05-05 23:47:28 +0200526 bad_hist[BROKEN_ACQUIRED]++;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900527 list_del(&seq->list);
528 free(seq);
529 goto end;
530 break;
531
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900532 default:
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900533 BUG_ON("Unknown state of lock sequence found!\n");
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900534 break;
535 }
536
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900537 seq->state = SEQ_STATE_ACQUIRED;
538 ls->nr_acquired++;
539 seq->prev_event_time = timestamp;
540end:
David Ahern33d6aef2012-08-26 12:24:43 -0600541 return 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900542}
543
David Ahern33d6aef2012-08-26 12:24:43 -0600544static int
Ingo Molnar59f411b2010-01-31 08:27:58 +0100545report_lock_contended_event(struct trace_contended_event *contended_event,
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300546 const struct perf_sample *sample)
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900547{
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900548 struct lock_stat *ls;
549 struct thread_stat *ts;
550 struct lock_seq_stat *seq;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900551
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900552 ls = lock_stat_findnew(contended_event->addr, contended_event->name);
David Ahern33d6aef2012-08-26 12:24:43 -0600553 if (!ls)
554 return -1;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900555 if (ls->discard)
David Ahern33d6aef2012-08-26 12:24:43 -0600556 return 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900557
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300558 ts = thread_stat_findnew(sample->tid);
David Ahern33d6aef2012-08-26 12:24:43 -0600559 if (!ts)
560 return -1;
561
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900562 seq = get_seq(ts, contended_event->addr);
David Ahern33d6aef2012-08-26 12:24:43 -0600563 if (!seq)
564 return -1;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900565
566 switch (seq->state) {
567 case SEQ_STATE_UNINITIALIZED:
568 /* orphan event, do nothing */
David Ahern33d6aef2012-08-26 12:24:43 -0600569 return 0;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900570 case SEQ_STATE_ACQUIRING:
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900571 break;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900572 case SEQ_STATE_RELEASED:
573 case SEQ_STATE_ACQUIRED:
574 case SEQ_STATE_READ_ACQUIRED:
575 case SEQ_STATE_CONTENDED:
576 /* broken lock sequence, discard it */
577 ls->discard = 1;
Frederic Weisbecker10350ec2010-05-05 23:47:28 +0200578 bad_hist[BROKEN_CONTENDED]++;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900579 list_del(&seq->list);
580 free(seq);
581 goto end;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900582 break;
583 default:
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900584 BUG_ON("Unknown state of lock sequence found!\n");
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900585 break;
586 }
587
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900588 seq->state = SEQ_STATE_CONTENDED;
589 ls->nr_contended++;
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300590 seq->prev_event_time = sample->time;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900591end:
David Ahern33d6aef2012-08-26 12:24:43 -0600592 return 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900593}
594
David Ahern33d6aef2012-08-26 12:24:43 -0600595static int
Ingo Molnar59f411b2010-01-31 08:27:58 +0100596report_lock_release_event(struct trace_release_event *release_event,
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300597 const struct perf_sample *sample)
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900598{
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900599 struct lock_stat *ls;
600 struct thread_stat *ts;
601 struct lock_seq_stat *seq;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900602
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900603 ls = lock_stat_findnew(release_event->addr, release_event->name);
David Ahern33d6aef2012-08-26 12:24:43 -0600604 if (!ls)
605 return -1;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900606 if (ls->discard)
David Ahern33d6aef2012-08-26 12:24:43 -0600607 return 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900608
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300609 ts = thread_stat_findnew(sample->tid);
David Ahern33d6aef2012-08-26 12:24:43 -0600610 if (!ts)
611 return -1;
612
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900613 seq = get_seq(ts, release_event->addr);
David Ahern33d6aef2012-08-26 12:24:43 -0600614 if (!seq)
615 return -1;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900616
617 switch (seq->state) {
618 case SEQ_STATE_UNINITIALIZED:
619 goto end;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900620 break;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900621 case SEQ_STATE_ACQUIRED:
622 break;
623 case SEQ_STATE_READ_ACQUIRED:
624 seq->read_count--;
625 BUG_ON(seq->read_count < 0);
626 if (!seq->read_count) {
627 ls->nr_release++;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900628 goto end;
629 }
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900630 break;
631 case SEQ_STATE_ACQUIRING:
632 case SEQ_STATE_CONTENDED:
633 case SEQ_STATE_RELEASED:
634 /* broken lock sequence, discard it */
635 ls->discard = 1;
Frederic Weisbecker10350ec2010-05-05 23:47:28 +0200636 bad_hist[BROKEN_RELEASE]++;
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900637 goto free_seq;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900638 break;
639 default:
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900640 BUG_ON("Unknown state of lock sequence found!\n");
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900641 break;
642 }
643
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900644 ls->nr_release++;
645free_seq:
646 list_del(&seq->list);
647 free(seq);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900648end:
David Ahern33d6aef2012-08-26 12:24:43 -0600649 return 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900650}
651
652/* lock oriented handlers */
653/* TODO: handlers for CPU oriented, thread oriented */
Ingo Molnar59f411b2010-01-31 08:27:58 +0100654static struct trace_lock_handler report_lock_ops = {
655 .acquire_event = report_lock_acquire_event,
656 .acquired_event = report_lock_acquired_event,
657 .contended_event = report_lock_contended_event,
658 .release_event = report_lock_release_event,
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900659};
660
661static struct trace_lock_handler *trace_handler;
662
David Ahern33d6aef2012-08-26 12:24:43 -0600663static int perf_evsel__process_lock_acquire(struct perf_evsel *evsel,
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300664 struct perf_sample *sample)
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900665{
666 struct trace_acquire_event acquire_event;
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300667 struct event_format *event = evsel->tp_format;
668 void *data = sample->raw_data;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900669 u64 tmp; /* this is required for casting... */
David Ahern33d6aef2012-08-26 12:24:43 -0600670 int rc = 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900671
672 tmp = raw_field_value(event, "lockdep_addr", data);
673 memcpy(&acquire_event.addr, &tmp, sizeof(void *));
674 acquire_event.name = (char *)raw_field_ptr(event, "name", data);
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900675 acquire_event.flag = (int)raw_field_value(event, "flag", data);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900676
Ingo Molnar59f411b2010-01-31 08:27:58 +0100677 if (trace_handler->acquire_event)
David Ahern33d6aef2012-08-26 12:24:43 -0600678 rc = trace_handler->acquire_event(&acquire_event, sample);
679
680 return rc;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900681}
682
David Ahern33d6aef2012-08-26 12:24:43 -0600683static int perf_evsel__process_lock_acquired(struct perf_evsel *evsel,
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300684 struct perf_sample *sample)
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900685{
686 struct trace_acquired_event acquired_event;
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300687 struct event_format *event = evsel->tp_format;
688 void *data = sample->raw_data;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900689 u64 tmp; /* this is required for casting... */
David Ahern33d6aef2012-08-26 12:24:43 -0600690 int rc = 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900691
692 tmp = raw_field_value(event, "lockdep_addr", data);
693 memcpy(&acquired_event.addr, &tmp, sizeof(void *));
694 acquired_event.name = (char *)raw_field_ptr(event, "name", data);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900695
David Ahern33d6aef2012-08-26 12:24:43 -0600696 if (trace_handler->acquired_event)
697 rc = trace_handler->acquired_event(&acquired_event, sample);
698
699 return rc;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900700}
701
David Ahern33d6aef2012-08-26 12:24:43 -0600702static int perf_evsel__process_lock_contended(struct perf_evsel *evsel,
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300703 struct perf_sample *sample)
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900704{
705 struct trace_contended_event contended_event;
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300706 struct event_format *event = evsel->tp_format;
707 void *data = sample->raw_data;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900708 u64 tmp; /* this is required for casting... */
David Ahern33d6aef2012-08-26 12:24:43 -0600709 int rc = 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900710
711 tmp = raw_field_value(event, "lockdep_addr", data);
712 memcpy(&contended_event.addr, &tmp, sizeof(void *));
713 contended_event.name = (char *)raw_field_ptr(event, "name", data);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900714
David Ahern33d6aef2012-08-26 12:24:43 -0600715 if (trace_handler->contended_event)
716 rc = trace_handler->contended_event(&contended_event, sample);
717
718 return rc;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900719}
720
David Ahern33d6aef2012-08-26 12:24:43 -0600721static int perf_evsel__process_lock_release(struct perf_evsel *evsel,
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300722 struct perf_sample *sample)
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900723{
724 struct trace_release_event release_event;
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300725 struct event_format *event = evsel->tp_format;
726 void *data = sample->raw_data;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900727 u64 tmp; /* this is required for casting... */
David Ahern33d6aef2012-08-26 12:24:43 -0600728 int rc = 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900729
730 tmp = raw_field_value(event, "lockdep_addr", data);
731 memcpy(&release_event.addr, &tmp, sizeof(void *));
732 release_event.name = (char *)raw_field_ptr(event, "name", data);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900733
David Ahern33d6aef2012-08-26 12:24:43 -0600734 if (trace_handler->release_event)
735 rc = trace_handler->release_event(&release_event, sample);
736
737 return rc;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900738}
739
David Ahern33d6aef2012-08-26 12:24:43 -0600740static int perf_evsel__process_lock_event(struct perf_evsel *evsel,
Arnaldo Carvalho de Melo01d95522012-08-07 10:59:44 -0300741 struct perf_sample *sample)
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900742{
Arnaldo Carvalho de Melofcf65bf2012-08-07 09:58:03 -0300743 struct event_format *event = evsel->tp_format;
David Ahern33d6aef2012-08-26 12:24:43 -0600744 int rc = 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900745
746 if (!strcmp(event->name, "lock_acquire"))
David Ahern33d6aef2012-08-26 12:24:43 -0600747 rc = perf_evsel__process_lock_acquire(evsel, sample);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900748 if (!strcmp(event->name, "lock_acquired"))
David Ahern33d6aef2012-08-26 12:24:43 -0600749 rc = perf_evsel__process_lock_acquired(evsel, sample);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900750 if (!strcmp(event->name, "lock_contended"))
David Ahern33d6aef2012-08-26 12:24:43 -0600751 rc = perf_evsel__process_lock_contended(evsel, sample);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900752 if (!strcmp(event->name, "lock_release"))
David Ahern33d6aef2012-08-26 12:24:43 -0600753 rc = perf_evsel__process_lock_release(evsel, sample);
754
755 return rc;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900756}
757
Frederic Weisbecker10350ec2010-05-05 23:47:28 +0200758static void print_bad_events(int bad, int total)
759{
760 /* Output for debug, this have to be removed */
761 int i;
762 const char *name[4] =
763 { "acquire", "acquired", "contended", "release" };
764
765 pr_info("\n=== output for debug===\n\n");
Frederic Weisbecker5efe08c2010-05-06 04:55:22 +0200766 pr_info("bad: %d, total: %d\n", bad, total);
767 pr_info("bad rate: %f %%\n", (double)bad / (double)total * 100);
Frederic Weisbecker10350ec2010-05-05 23:47:28 +0200768 pr_info("histogram of events caused bad sequence\n");
769 for (i = 0; i < BROKEN_MAX; i++)
770 pr_info(" %10s: %d\n", name[i], bad_hist[i]);
771}
772
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900773/* TODO: various way to print, coloring, nano or milli sec */
774static void print_result(void)
775{
776 struct lock_stat *st;
777 char cut_name[20];
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900778 int bad, total;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900779
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900780 pr_info("%20s ", "Name");
781 pr_info("%10s ", "acquired");
782 pr_info("%10s ", "contended");
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900783
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900784 pr_info("%15s ", "total wait (ns)");
785 pr_info("%15s ", "max wait (ns)");
786 pr_info("%15s ", "min wait (ns)");
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900787
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900788 pr_info("\n\n");
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900789
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900790 bad = total = 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900791 while ((st = pop_from_result())) {
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900792 total++;
793 if (st->discard) {
794 bad++;
795 continue;
796 }
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900797 bzero(cut_name, 20);
798
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900799 if (strlen(st->name) < 16) {
800 /* output raw name */
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900801 pr_info("%20s ", st->name);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900802 } else {
803 strncpy(cut_name, st->name, 16);
804 cut_name[16] = '.';
805 cut_name[17] = '.';
806 cut_name[18] = '.';
807 cut_name[19] = '\0';
808 /* cut off name for saving output style */
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900809 pr_info("%20s ", cut_name);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900810 }
811
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900812 pr_info("%10u ", st->nr_acquired);
813 pr_info("%10u ", st->nr_contended);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900814
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -0200815 pr_info("%15" PRIu64 " ", st->wait_time_total);
816 pr_info("%15" PRIu64 " ", st->wait_time_max);
817 pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ?
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900818 0 : st->wait_time_min);
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900819 pr_info("\n");
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900820 }
Hitoshi Mitakee4cef1f2010-04-21 21:23:54 +0900821
Frederic Weisbecker10350ec2010-05-05 23:47:28 +0200822 print_bad_events(bad, total);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900823}
824
Arnaldo Carvalho de Melo80354582010-05-17 15:51:10 -0300825static bool info_threads, info_map;
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900826
827static void dump_threads(void)
828{
829 struct thread_stat *st;
830 struct rb_node *node;
831 struct thread *t;
832
833 pr_info("%10s: comm\n", "Thread ID");
834
835 node = rb_first(&thread_stats);
836 while (node) {
837 st = container_of(node, struct thread_stat, rb);
838 t = perf_session__findnew(session, st->tid);
839 pr_info("%10d: %s\n", st->tid, t->comm);
840 node = rb_next(node);
841 };
842}
843
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900844static void dump_map(void)
845{
846 unsigned int i;
847 struct lock_stat *st;
848
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900849 pr_info("Address of instance: name of class\n");
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900850 for (i = 0; i < LOCKHASH_SIZE; i++) {
851 list_for_each_entry(st, &lockhash_table[i], hash_entry) {
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900852 pr_info(" %p: %s\n", st->addr, st->name);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900853 }
854 }
855}
856
David Ahern33d6aef2012-08-26 12:24:43 -0600857static int dump_info(void)
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900858{
David Ahern33d6aef2012-08-26 12:24:43 -0600859 int rc = 0;
860
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900861 if (info_threads)
862 dump_threads();
863 else if (info_map)
864 dump_map();
David Ahern33d6aef2012-08-26 12:24:43 -0600865 else {
866 rc = -1;
867 pr_err("Unknown type of information\n");
868 }
869
870 return rc;
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900871}
872
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200873static int process_sample_event(struct perf_tool *tool __used,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200874 union perf_event *event,
Arnaldo Carvalho de Melo9e69c212011-03-15 15:44:01 -0300875 struct perf_sample *sample,
Arnaldo Carvalho de Melofcf65bf2012-08-07 09:58:03 -0300876 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200877 struct machine *machine)
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200878{
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200879 struct thread *thread = machine__findnew_thread(machine, sample->tid);
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200880
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200881 if (thread == NULL) {
882 pr_debug("problem processing %d event, skipping it.\n",
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200883 event->header.type);
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200884 return -1;
885 }
886
David Ahern33d6aef2012-08-26 12:24:43 -0600887 return perf_evsel__process_lock_event(evsel, sample);
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200888}
889
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200890static struct perf_tool eops = {
Ingo Molnar59f411b2010-01-31 08:27:58 +0100891 .sample = process_sample_event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200892 .comm = perf_event__process_comm,
Frederic Weisbeckerc61e52e2010-04-24 00:04:12 +0200893 .ordered_samples = true,
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900894};
895
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900896static int read_events(void)
897{
Ian Munsie21ef97f2010-12-10 14:09:16 +1100898 session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
David Ahern33d6aef2012-08-26 12:24:43 -0600899 if (!session) {
900 pr_err("Initializing perf session failed\n");
901 return -1;
902 }
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900903
904 return perf_session__process_events(session, &eops);
905}
906
907static void sort_result(void)
908{
909 unsigned int i;
910 struct lock_stat *st;
911
912 for (i = 0; i < LOCKHASH_SIZE; i++) {
913 list_for_each_entry(st, &lockhash_table[i], hash_entry) {
914 insert_to_result(st, compare);
915 }
916 }
917}
918
David Ahern33d6aef2012-08-26 12:24:43 -0600919static int __cmd_report(void)
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900920{
921 setup_pager();
David Ahern33d6aef2012-08-26 12:24:43 -0600922
923 if ((select_key() != 0) ||
924 (read_events() != 0))
925 return -1;
926
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900927 sort_result();
928 print_result();
David Ahern33d6aef2012-08-26 12:24:43 -0600929
930 return 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900931}
932
Ingo Molnar59f411b2010-01-31 08:27:58 +0100933static const char * const report_usage[] = {
934 "perf lock report [<options>]",
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900935 NULL
936};
937
Ingo Molnar59f411b2010-01-31 08:27:58 +0100938static const struct option report_options[] = {
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900939 OPT_STRING('k', "key", &sort_key, "acquired",
Marcin Slusarz9826e832011-02-22 21:53:12 +0100940 "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900941 /* TODO: type */
942 OPT_END()
943};
944
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900945static const char * const info_usage[] = {
946 "perf lock info [<options>]",
947 NULL
948};
949
950static const struct option info_options[] = {
951 OPT_BOOLEAN('t', "threads", &info_threads,
952 "dump thread list in perf.data"),
953 OPT_BOOLEAN('m', "map", &info_map,
Namhyung Kimd1eec3e2012-01-29 17:55:56 +0900954 "map of lock instances (address:name table)"),
Hitoshi Mitake26242d82010-05-03 14:12:00 +0900955 OPT_END()
956};
957
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900958static const char * const lock_usage[] = {
Namhyung Kimd1eec3e2012-01-29 17:55:56 +0900959 "perf lock [<options>] {record|report|script|info}",
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900960 NULL
961};
962
963static const struct option lock_options[] = {
Ingo Molnar59f411b2010-01-31 08:27:58 +0100964 OPT_STRING('i', "input", &input_name, "file", "input file name"),
Ian Munsiec0555642010-04-13 18:37:33 +1000965 OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
Ingo Molnar59f411b2010-01-31 08:27:58 +0100966 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900967 OPT_END()
968};
969
David Ahernd25dcba2012-08-09 10:35:37 -0600970static const char * const lock_tracepoints[] = {
971 "lock:lock_acquire", /* CONFIG_LOCKDEP */
972 "lock:lock_acquired", /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
973 "lock:lock_contended", /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
974 "lock:lock_release", /* CONFIG_LOCKDEP */
975};
976
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900977static const char *record_args[] = {
978 "record",
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900979 "-R",
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900980 "-f",
981 "-m", "1024",
982 "-c", "1",
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900983};
984
985static int __cmd_record(int argc, const char **argv)
986{
987 unsigned int rec_argc, i, j;
988 const char **rec_argv;
989
David Ahernd25dcba2012-08-09 10:35:37 -0600990 for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) {
991 if (!is_valid_tracepoint(lock_tracepoints[i])) {
992 pr_err("tracepoint %s is not enabled. "
993 "Are CONFIG_LOCKDEP and CONFIG_LOCK_STAT enabled?\n",
994 lock_tracepoints[i]);
995 return 1;
996 }
997 }
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +0900998
David Ahernd25dcba2012-08-09 10:35:37 -0600999 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
1000 /* factor of 2 is for -e in front of each tracepoint */
1001 rec_argc += 2 * ARRAY_SIZE(lock_tracepoints);
1002
1003 rec_argv = calloc(rec_argc + 1, sizeof(char *));
Chris Samuelce47dc52010-11-13 13:35:06 +11001004 if (rec_argv == NULL)
1005 return -ENOMEM;
1006
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +09001007 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1008 rec_argv[i] = strdup(record_args[i]);
1009
David Ahernd25dcba2012-08-09 10:35:37 -06001010 for (j = 0; j < ARRAY_SIZE(lock_tracepoints); j++) {
1011 rec_argv[i++] = "-e";
1012 rec_argv[i++] = strdup(lock_tracepoints[j]);
1013 }
1014
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +09001015 for (j = 1; j < (unsigned int)argc; j++, i++)
1016 rec_argv[i] = argv[j];
1017
1018 BUG_ON(i != rec_argc);
1019
1020 return cmd_record(i, rec_argv, NULL);
1021}
1022
1023int cmd_lock(int argc, const char **argv, const char *prefix __used)
1024{
1025 unsigned int i;
David Ahern33d6aef2012-08-26 12:24:43 -06001026 int rc = 0;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +09001027
1028 symbol__init();
1029 for (i = 0; i < LOCKHASH_SIZE; i++)
1030 INIT_LIST_HEAD(lockhash_table + i);
1031
1032 argc = parse_options(argc, argv, lock_options, lock_usage,
1033 PARSE_OPT_STOP_AT_NON_OPTION);
1034 if (!argc)
1035 usage_with_options(lock_usage, lock_options);
1036
1037 if (!strncmp(argv[0], "rec", 3)) {
1038 return __cmd_record(argc, argv);
Ingo Molnar59f411b2010-01-31 08:27:58 +01001039 } else if (!strncmp(argv[0], "report", 6)) {
1040 trace_handler = &report_lock_ops;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +09001041 if (argc) {
1042 argc = parse_options(argc, argv,
Ingo Molnar59f411b2010-01-31 08:27:58 +01001043 report_options, report_usage, 0);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +09001044 if (argc)
Ingo Molnar59f411b2010-01-31 08:27:58 +01001045 usage_with_options(report_usage, report_options);
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +09001046 }
Ingo Molnar59f411b2010-01-31 08:27:58 +01001047 __cmd_report();
Ingo Molnar133dc4c2010-11-16 18:45:39 +01001048 } else if (!strcmp(argv[0], "script")) {
1049 /* Aliased to 'perf script' */
1050 return cmd_script(argc, argv, prefix);
Hitoshi Mitake26242d82010-05-03 14:12:00 +09001051 } else if (!strcmp(argv[0], "info")) {
1052 if (argc) {
1053 argc = parse_options(argc, argv,
1054 info_options, info_usage, 0);
1055 if (argc)
1056 usage_with_options(info_usage, info_options);
1057 }
Ingo Molnar59f411b2010-01-31 08:27:58 +01001058 /* recycling report_lock_ops */
1059 trace_handler = &report_lock_ops;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +09001060 setup_pager();
David Ahern33d6aef2012-08-26 12:24:43 -06001061 if (read_events() != 0)
1062 rc = -1;
1063 else
1064 rc = dump_info();
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +09001065 } else {
1066 usage_with_options(lock_usage, lock_options);
1067 }
1068
David Ahern33d6aef2012-08-26 12:24:43 -06001069 return rc;
Hitoshi Mitake9b5e3502010-01-30 20:43:33 +09001070}