Blame view

tools/perf/builtin-lock.c 23.2 KB
a43783aee   Arnaldo Carvalho de Melo   perf tools: Inclu...
1
  #include <errno.h>
fd20e8111   Arnaldo Carvalho de Melo   perf tools: Inclu...
2
  #include <inttypes.h>
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
3
4
  #include "builtin.h"
  #include "perf.h"
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
5
  #include "util/evlist.h"
fcf65bf14   Arnaldo Carvalho de Melo   perf evsel: Cache...
6
  #include "util/evsel.h"
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
7
8
9
10
11
  #include "util/util.h"
  #include "util/cache.h"
  #include "util/symbol.h"
  #include "util/thread.h"
  #include "util/header.h"
4b6ab94ea   Josh Poimboeuf   perf subcmd: Crea...
12
  #include <subcmd/parse-options.h>
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
13
14
15
16
  #include "util/trace-event.h"
  
  #include "util/debug.h"
  #include "util/session.h"
45694aa77   Arnaldo Carvalho de Melo   perf tools: Renam...
17
  #include "util/tool.h"
f5fc14124   Jiri Olsa   perf tools: Add d...
18
  #include "util/data.h"
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
19
20
21
22
23
24
25
26
27
28
  
  #include <sys/types.h>
  #include <sys/prctl.h>
  #include <semaphore.h>
  #include <pthread.h>
  #include <math.h>
  #include <limits.h>
  
  #include <linux/list.h>
  #include <linux/hash.h>
877a7a110   Arnaldo Carvalho de Melo   perf tools: Add i...
29
  #include <linux/kernel.h>
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
30

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
31
  static struct perf_session *session;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
32
33
34
35
36
37
38
39
  /* based on kernel/lockdep.c */
  #define LOCKHASH_BITS		12
  #define LOCKHASH_SIZE		(1UL << LOCKHASH_BITS)
  
  static struct list_head lockhash_table[LOCKHASH_SIZE];
  
  #define __lockhashfn(key)	hash_long((unsigned long)key, LOCKHASH_BITS)
  #define lockhashentry(key)	(lockhash_table + __lockhashfn((key)))
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
40
  struct lock_stat {
59f411b62   Ingo Molnar   perf lock: Clean ...
41
42
  	struct list_head	hash_entry;
  	struct rb_node		rb;		/* used for sorting */
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
43

59f411b62   Ingo Molnar   perf lock: Clean ...
44
  	/*
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
45
  	 * FIXME: perf_evsel__intval() returns u64,
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
46
  	 * so address of lockdep_map should be dealed as 64bit.
59f411b62   Ingo Molnar   perf lock: Clean ...
47
48
49
50
  	 * Is there more better solution?
  	 */
  	void			*addr;		/* address of lockdep_map, used as ID */
  	char			*name;		/* for strcpy(), we cannot use const */
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
51

59f411b62   Ingo Molnar   perf lock: Clean ...
52
  	unsigned int		nr_acquire;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
53
  	unsigned int		nr_acquired;
59f411b62   Ingo Molnar   perf lock: Clean ...
54
55
  	unsigned int		nr_contended;
  	unsigned int		nr_release;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
56

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
57
58
  	unsigned int		nr_readlock;
  	unsigned int		nr_trylock;
f37376cd7   Davidlohr Bueso   perf lock: Accoun...
59

9b5e350c7   Hitoshi Mitake   perf lock: Introd...
60
  	/* these times are in nano sec. */
f37376cd7   Davidlohr Bueso   perf lock: Accoun...
61
  	u64                     avg_wait_time;
59f411b62   Ingo Molnar   perf lock: Clean ...
62
63
64
  	u64			wait_time_total;
  	u64			wait_time_min;
  	u64			wait_time_max;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  
  	int			discard; /* flag of blacklist */
  };
  
  /*
   * States of lock_seq_stat
   *
   * UNINITIALIZED is required for detecting first event of acquire.
   * As the nature of lock events, there is no guarantee
   * that the first event for the locks are acquire,
   * it can be acquired, contended or release.
   */
  #define SEQ_STATE_UNINITIALIZED      0	       /* initial state */
  #define SEQ_STATE_RELEASED	1
  #define SEQ_STATE_ACQUIRING	2
  #define SEQ_STATE_ACQUIRED	3
  #define SEQ_STATE_READ_ACQUIRED	4
  #define SEQ_STATE_CONTENDED	5
  
  /*
   * MAX_LOCK_DEPTH
   * Imported from include/linux/sched.h.
   * Should this be synchronized?
   */
  #define MAX_LOCK_DEPTH 48
  
  /*
   * struct lock_seq_stat:
   * Place to put on state of one lock sequence
   * 1) acquire -> acquired -> release
   * 2) acquire -> contended -> acquired -> release
   * 3) acquire (with read or try) -> release
   * 4) Are there other patterns?
   */
  struct lock_seq_stat {
  	struct list_head        list;
  	int			state;
  	u64			prev_event_time;
  	void                    *addr;
  
  	int                     read_count;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
106
  };
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  struct thread_stat {
  	struct rb_node		rb;
  
  	u32                     tid;
  	struct list_head        seq_list;
  };
  
  static struct rb_root		thread_stats;
  
  static struct thread_stat *thread_stat_find(u32 tid)
  {
  	struct rb_node *node;
  	struct thread_stat *st;
  
  	node = thread_stats.rb_node;
  	while (node) {
  		st = container_of(node, struct thread_stat, rb);
  		if (st->tid == tid)
  			return st;
  		else if (tid < st->tid)
  			node = node->rb_left;
  		else
  			node = node->rb_right;
  	}
  
  	return NULL;
  }
  
  static void thread_stat_insert(struct thread_stat *new)
  {
  	struct rb_node **rb = &thread_stats.rb_node;
  	struct rb_node *parent = NULL;
  	struct thread_stat *p;
  
  	while (*rb) {
  		p = container_of(*rb, struct thread_stat, rb);
  		parent = *rb;
  
  		if (new->tid < p->tid)
  			rb = &(*rb)->rb_left;
  		else if (new->tid > p->tid)
  			rb = &(*rb)->rb_right;
  		else
  			BUG_ON("inserting invalid thread_stat
  ");
  	}
  
  	rb_link_node(&new->rb, parent, rb);
  	rb_insert_color(&new->rb, &thread_stats);
  }
  
  static struct thread_stat *thread_stat_findnew_after_first(u32 tid)
  {
  	struct thread_stat *st;
  
  	st = thread_stat_find(tid);
  	if (st)
  		return st;
  
  	st = zalloc(sizeof(struct thread_stat));
33d6aef51   David Ahern   perf lock: Remove...
167
168
169
170
171
  	if (!st) {
  		pr_err("memory allocation failed
  ");
  		return NULL;
  	}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
  
  	st->tid = tid;
  	INIT_LIST_HEAD(&st->seq_list);
  
  	thread_stat_insert(st);
  
  	return st;
  }
  
  static struct thread_stat *thread_stat_findnew_first(u32 tid);
  static struct thread_stat *(*thread_stat_findnew)(u32 tid) =
  	thread_stat_findnew_first;
  
  static struct thread_stat *thread_stat_findnew_first(u32 tid)
  {
  	struct thread_stat *st;
  
  	st = zalloc(sizeof(struct thread_stat));
33d6aef51   David Ahern   perf lock: Remove...
190
191
192
193
194
  	if (!st) {
  		pr_err("memory allocation failed
  ");
  		return NULL;
  	}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
195
196
197
198
199
200
201
202
203
  	st->tid = tid;
  	INIT_LIST_HEAD(&st->seq_list);
  
  	rb_link_node(&st->rb, NULL, &thread_stats.rb_node);
  	rb_insert_color(&st->rb, &thread_stats);
  
  	thread_stat_findnew = thread_stat_findnew_after_first;
  	return st;
  }
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
204
  /* build simple key function one is bigger than two */
59f411b62   Ingo Molnar   perf lock: Clean ...
205
  #define SINGLE_KEY(member)						\
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
206
207
208
209
210
211
212
213
  	static int lock_stat_key_ ## member(struct lock_stat *one,	\
  					 struct lock_stat *two)		\
  	{								\
  		return one->member > two->member;			\
  	}
  
  SINGLE_KEY(nr_acquired)
  SINGLE_KEY(nr_contended)
f37376cd7   Davidlohr Bueso   perf lock: Accoun...
214
  SINGLE_KEY(avg_wait_time)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
215
  SINGLE_KEY(wait_time_total)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
216
  SINGLE_KEY(wait_time_max)
9df03abed   Marcin Slusarz   perf lock: Fix so...
217
218
219
220
221
222
223
224
225
226
227
  static int lock_stat_key_wait_time_min(struct lock_stat *one,
  					struct lock_stat *two)
  {
  	u64 s1 = one->wait_time_min;
  	u64 s2 = two->wait_time_min;
  	if (s1 == ULLONG_MAX)
  		s1 = 0;
  	if (s2 == ULLONG_MAX)
  		s2 = 0;
  	return s1 > s2;
  }
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
228
229
230
231
232
233
  struct lock_key {
  	/*
  	 * name: the value for specify by user
  	 * this should be simpler than raw name of member
  	 * e.g. nr_acquired -> acquired, wait_time_total -> wait_total
  	 */
59f411b62   Ingo Molnar   perf lock: Clean ...
234
235
  	const char		*name;
  	int			(*key)(struct lock_stat*, struct lock_stat*);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
236
  };
59f411b62   Ingo Molnar   perf lock: Clean ...
237
238
239
240
241
  static const char		*sort_key = "acquired";
  
  static int			(*compare)(struct lock_stat *, struct lock_stat *);
  
  static struct rb_root		result;	/* place to store sorted data */
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
242
243
244
245
246
247
  
  #define DEF_KEY_LOCK(name, fn_suffix)	\
  	{ #name, lock_stat_key_ ## fn_suffix }
  struct lock_key keys[] = {
  	DEF_KEY_LOCK(acquired, nr_acquired),
  	DEF_KEY_LOCK(contended, nr_contended),
f37376cd7   Davidlohr Bueso   perf lock: Accoun...
248
  	DEF_KEY_LOCK(avg_wait, avg_wait_time),
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
249
250
251
252
253
254
255
256
  	DEF_KEY_LOCK(wait_total, wait_time_total),
  	DEF_KEY_LOCK(wait_min, wait_time_min),
  	DEF_KEY_LOCK(wait_max, wait_time_max),
  
  	/* extra comparisons much complicated should be here */
  
  	{ NULL, NULL }
  };
33d6aef51   David Ahern   perf lock: Remove...
257
  static int select_key(void)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
258
259
260
261
262
263
  {
  	int i;
  
  	for (i = 0; keys[i].name; i++) {
  		if (!strcmp(keys[i].name, sort_key)) {
  			compare = keys[i].key;
33d6aef51   David Ahern   perf lock: Remove...
264
  			return 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
265
266
  		}
  	}
33d6aef51   David Ahern   perf lock: Remove...
267
268
269
270
  	pr_err("Unknown compare key: %s
  ", sort_key);
  
  	return -1;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
271
  }
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
272
  static void insert_to_result(struct lock_stat *st,
59f411b62   Ingo Molnar   perf lock: Clean ...
273
  			     int (*bigger)(struct lock_stat *, struct lock_stat *))
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
  {
  	struct rb_node **rb = &result.rb_node;
  	struct rb_node *parent = NULL;
  	struct lock_stat *p;
  
  	while (*rb) {
  		p = container_of(*rb, struct lock_stat, rb);
  		parent = *rb;
  
  		if (bigger(st, p))
  			rb = &(*rb)->rb_left;
  		else
  			rb = &(*rb)->rb_right;
  	}
  
  	rb_link_node(&st->rb, parent, rb);
  	rb_insert_color(&st->rb, &result);
  }
  
  /* returns left most element of result, and erase it */
  static struct lock_stat *pop_from_result(void)
  {
  	struct rb_node *node = result.rb_node;
  
  	if (!node)
  		return NULL;
  
  	while (node->rb_left)
  		node = node->rb_left;
  
  	rb_erase(node, &result);
  	return container_of(node, struct lock_stat, rb);
  }
59f411b62   Ingo Molnar   perf lock: Clean ...
307
  static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  {
  	struct list_head *entry = lockhashentry(addr);
  	struct lock_stat *ret, *new;
  
  	list_for_each_entry(ret, entry, hash_entry) {
  		if (ret->addr == addr)
  			return ret;
  	}
  
  	new = zalloc(sizeof(struct lock_stat));
  	if (!new)
  		goto alloc_failed;
  
  	new->addr = addr;
  	new->name = zalloc(sizeof(char) * strlen(name) + 1);
0a98c7feb   Davidlohr Bueso   perf lock: Plug s...
323
324
  	if (!new->name) {
  		free(new);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
325
  		goto alloc_failed;
0a98c7feb   Davidlohr Bueso   perf lock: Plug s...
326
  	}
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
327

0a98c7feb   Davidlohr Bueso   perf lock: Plug s...
328
  	strcpy(new->name, name);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
329
330
331
332
333
334
  	new->wait_time_min = ULLONG_MAX;
  
  	list_add(&new->hash_entry, entry);
  	return new;
  
  alloc_failed:
33d6aef51   David Ahern   perf lock: Remove...
335
336
337
  	pr_err("memory allocation failed
  ");
  	return NULL;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
338
  }
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
339
  struct trace_lock_handler {
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
340
341
  	int (*acquire_event)(struct perf_evsel *evsel,
  			     struct perf_sample *sample);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
342

746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
343
344
  	int (*acquired_event)(struct perf_evsel *evsel,
  			      struct perf_sample *sample);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
345

746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
346
347
  	int (*contended_event)(struct perf_evsel *evsel,
  			       struct perf_sample *sample);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
348

746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
349
350
  	int (*release_event)(struct perf_evsel *evsel,
  			     struct perf_sample *sample);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
351
  };
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
352
353
354
355
356
357
358
359
360
361
  static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr)
  {
  	struct lock_seq_stat *seq;
  
  	list_for_each_entry(seq, &ts->seq_list, list) {
  		if (seq->addr == addr)
  			return seq;
  	}
  
  	seq = zalloc(sizeof(struct lock_seq_stat));
33d6aef51   David Ahern   perf lock: Remove...
362
363
364
365
366
  	if (!seq) {
  		pr_err("memory allocation failed
  ");
  		return NULL;
  	}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
367
368
369
370
371
372
  	seq->state = SEQ_STATE_UNINITIALIZED;
  	seq->addr = addr;
  
  	list_add(&seq->list, &ts->seq_list);
  	return seq;
  }
10350ec36   Frederic Weisbecker   perf: Cleanup per...
373
374
375
376
377
378
379
380
381
  enum broken_state {
  	BROKEN_ACQUIRE,
  	BROKEN_ACQUIRED,
  	BROKEN_CONTENDED,
  	BROKEN_RELEASE,
  	BROKEN_MAX,
  };
  
  static int bad_hist[BROKEN_MAX];
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
382

84c7a2179   Frederic Weisbecker   perf: Humanize lo...
383
384
385
386
  enum acquire_flags {
  	TRY_LOCK = 1,
  	READ_LOCK = 2,
  };
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
387
388
  static int report_lock_acquire_event(struct perf_evsel *evsel,
  				     struct perf_sample *sample)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
389
  {
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
390
  	void *addr;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
391
392
393
  	struct lock_stat *ls;
  	struct thread_stat *ts;
  	struct lock_seq_stat *seq;
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
394
395
396
  	const char *name = perf_evsel__strval(evsel, sample, "name");
  	u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
  	int flag = perf_evsel__intval(evsel, sample, "flag");
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
397

746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
398
399
400
  	memcpy(&addr, &tmp, sizeof(void *));
  
  	ls = lock_stat_findnew(addr, name);
33d6aef51   David Ahern   perf lock: Remove...
401
  	if (!ls)
b33492ade   Davidlohr Bueso   perf lock: Return...
402
  		return -ENOMEM;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
403
  	if (ls->discard)
33d6aef51   David Ahern   perf lock: Remove...
404
  		return 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
405

01d955244   Arnaldo Carvalho de Melo   perf lock: Use ev...
406
  	ts = thread_stat_findnew(sample->tid);
33d6aef51   David Ahern   perf lock: Remove...
407
  	if (!ts)
b33492ade   Davidlohr Bueso   perf lock: Return...
408
  		return -ENOMEM;
33d6aef51   David Ahern   perf lock: Remove...
409

746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
410
  	seq = get_seq(ts, addr);
33d6aef51   David Ahern   perf lock: Remove...
411
  	if (!seq)
b33492ade   Davidlohr Bueso   perf lock: Return...
412
  		return -ENOMEM;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
413

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
414
415
416
  	switch (seq->state) {
  	case SEQ_STATE_UNINITIALIZED:
  	case SEQ_STATE_RELEASED:
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
417
  		if (!flag) {
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
418
419
  			seq->state = SEQ_STATE_ACQUIRING;
  		} else {
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
420
  			if (flag & TRY_LOCK)
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
421
  				ls->nr_trylock++;
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
422
  			if (flag & READ_LOCK)
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
423
424
425
426
427
428
429
  				ls->nr_readlock++;
  			seq->state = SEQ_STATE_READ_ACQUIRED;
  			seq->read_count = 1;
  			ls->nr_acquired++;
  		}
  		break;
  	case SEQ_STATE_READ_ACQUIRED:
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
430
  		if (flag & READ_LOCK) {
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
431
432
433
434
435
436
  			seq->read_count++;
  			ls->nr_acquired++;
  			goto end;
  		} else {
  			goto broken;
  		}
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
437
  		break;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
438
439
440
441
442
443
  	case SEQ_STATE_ACQUIRED:
  	case SEQ_STATE_ACQUIRING:
  	case SEQ_STATE_CONTENDED:
  broken:
  		/* broken lock sequence, discard it */
  		ls->discard = 1;
10350ec36   Frederic Weisbecker   perf: Cleanup per...
444
  		bad_hist[BROKEN_ACQUIRE]++;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
445
446
447
  		list_del(&seq->list);
  		free(seq);
  		goto end;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
448
  	default:
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
449
450
  		BUG_ON("Unknown state of lock sequence found!
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
451
452
  		break;
  	}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
453
  	ls->nr_acquire++;
01d955244   Arnaldo Carvalho de Melo   perf lock: Use ev...
454
  	seq->prev_event_time = sample->time;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
455
  end:
33d6aef51   David Ahern   perf lock: Remove...
456
  	return 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
457
  }
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
458
459
  static int report_lock_acquired_event(struct perf_evsel *evsel,
  				      struct perf_sample *sample)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
460
  {
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
461
  	void *addr;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
462
463
464
465
  	struct lock_stat *ls;
  	struct thread_stat *ts;
  	struct lock_seq_stat *seq;
  	u64 contended_term;
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
466
467
468
469
  	const char *name = perf_evsel__strval(evsel, sample, "name");
  	u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
  
  	memcpy(&addr, &tmp, sizeof(void *));
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
470

746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
471
  	ls = lock_stat_findnew(addr, name);
33d6aef51   David Ahern   perf lock: Remove...
472
  	if (!ls)
b33492ade   Davidlohr Bueso   perf lock: Return...
473
  		return -ENOMEM;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
474
  	if (ls->discard)
33d6aef51   David Ahern   perf lock: Remove...
475
  		return 0;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
476

01d955244   Arnaldo Carvalho de Melo   perf lock: Use ev...
477
  	ts = thread_stat_findnew(sample->tid);
33d6aef51   David Ahern   perf lock: Remove...
478
  	if (!ts)
b33492ade   Davidlohr Bueso   perf lock: Return...
479
  		return -ENOMEM;
33d6aef51   David Ahern   perf lock: Remove...
480

746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
481
  	seq = get_seq(ts, addr);
33d6aef51   David Ahern   perf lock: Remove...
482
  	if (!seq)
b33492ade   Davidlohr Bueso   perf lock: Return...
483
  		return -ENOMEM;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
484

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
485
486
487
  	switch (seq->state) {
  	case SEQ_STATE_UNINITIALIZED:
  		/* orphan event, do nothing */
33d6aef51   David Ahern   perf lock: Remove...
488
  		return 0;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
489
  	case SEQ_STATE_ACQUIRING:
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
490
  		break;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
491
  	case SEQ_STATE_CONTENDED:
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
492
  		contended_term = sample->time - seq->prev_event_time;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
493
  		ls->wait_time_total += contended_term;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
494
495
  		if (contended_term < ls->wait_time_min)
  			ls->wait_time_min = contended_term;
90c0e5fc7   Frederic Weisbecker   perf lock: Always...
496
  		if (ls->wait_time_max < contended_term)
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
497
  			ls->wait_time_max = contended_term;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
498
  		break;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
499
500
501
502
503
  	case SEQ_STATE_RELEASED:
  	case SEQ_STATE_ACQUIRED:
  	case SEQ_STATE_READ_ACQUIRED:
  		/* broken lock sequence, discard it */
  		ls->discard = 1;
10350ec36   Frederic Weisbecker   perf: Cleanup per...
504
  		bad_hist[BROKEN_ACQUIRED]++;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
505
506
507
  		list_del(&seq->list);
  		free(seq);
  		goto end;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
508
  	default:
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
509
510
  		BUG_ON("Unknown state of lock sequence found!
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
511
512
  		break;
  	}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
513
514
  	seq->state = SEQ_STATE_ACQUIRED;
  	ls->nr_acquired++;
f37376cd7   Davidlohr Bueso   perf lock: Accoun...
515
  	ls->avg_wait_time = ls->nr_contended ? ls->wait_time_total/ls->nr_contended : 0;
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
516
  	seq->prev_event_time = sample->time;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
517
  end:
33d6aef51   David Ahern   perf lock: Remove...
518
  	return 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
519
  }
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
520
521
  static int report_lock_contended_event(struct perf_evsel *evsel,
  				       struct perf_sample *sample)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
522
  {
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
523
  	void *addr;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
524
525
526
  	struct lock_stat *ls;
  	struct thread_stat *ts;
  	struct lock_seq_stat *seq;
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
527
528
529
530
  	const char *name = perf_evsel__strval(evsel, sample, "name");
  	u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
  
  	memcpy(&addr, &tmp, sizeof(void *));
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
531

746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
532
  	ls = lock_stat_findnew(addr, name);
33d6aef51   David Ahern   perf lock: Remove...
533
  	if (!ls)
b33492ade   Davidlohr Bueso   perf lock: Return...
534
  		return -ENOMEM;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
535
  	if (ls->discard)
33d6aef51   David Ahern   perf lock: Remove...
536
  		return 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
537

01d955244   Arnaldo Carvalho de Melo   perf lock: Use ev...
538
  	ts = thread_stat_findnew(sample->tid);
33d6aef51   David Ahern   perf lock: Remove...
539
  	if (!ts)
b33492ade   Davidlohr Bueso   perf lock: Return...
540
  		return -ENOMEM;
33d6aef51   David Ahern   perf lock: Remove...
541

746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
542
  	seq = get_seq(ts, addr);
33d6aef51   David Ahern   perf lock: Remove...
543
  	if (!seq)
b33492ade   Davidlohr Bueso   perf lock: Return...
544
  		return -ENOMEM;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
545

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
546
547
548
  	switch (seq->state) {
  	case SEQ_STATE_UNINITIALIZED:
  		/* orphan event, do nothing */
33d6aef51   David Ahern   perf lock: Remove...
549
  		return 0;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
550
  	case SEQ_STATE_ACQUIRING:
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
551
  		break;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
552
553
554
555
556
557
  	case SEQ_STATE_RELEASED:
  	case SEQ_STATE_ACQUIRED:
  	case SEQ_STATE_READ_ACQUIRED:
  	case SEQ_STATE_CONTENDED:
  		/* broken lock sequence, discard it */
  		ls->discard = 1;
10350ec36   Frederic Weisbecker   perf: Cleanup per...
558
  		bad_hist[BROKEN_CONTENDED]++;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
559
560
561
  		list_del(&seq->list);
  		free(seq);
  		goto end;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
562
  	default:
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
563
564
  		BUG_ON("Unknown state of lock sequence found!
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
565
566
  		break;
  	}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
567
568
  	seq->state = SEQ_STATE_CONTENDED;
  	ls->nr_contended++;
f37376cd7   Davidlohr Bueso   perf lock: Accoun...
569
  	ls->avg_wait_time = ls->wait_time_total/ls->nr_contended;
01d955244   Arnaldo Carvalho de Melo   perf lock: Use ev...
570
  	seq->prev_event_time = sample->time;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
571
  end:
33d6aef51   David Ahern   perf lock: Remove...
572
  	return 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
573
  }
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
574
575
  static int report_lock_release_event(struct perf_evsel *evsel,
  				     struct perf_sample *sample)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
576
  {
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
577
  	void *addr;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
578
579
580
  	struct lock_stat *ls;
  	struct thread_stat *ts;
  	struct lock_seq_stat *seq;
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
581
582
  	const char *name = perf_evsel__strval(evsel, sample, "name");
  	u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
583

746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
584
585
586
  	memcpy(&addr, &tmp, sizeof(void *));
  
  	ls = lock_stat_findnew(addr, name);
33d6aef51   David Ahern   perf lock: Remove...
587
  	if (!ls)
b33492ade   Davidlohr Bueso   perf lock: Return...
588
  		return -ENOMEM;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
589
  	if (ls->discard)
33d6aef51   David Ahern   perf lock: Remove...
590
  		return 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
591

01d955244   Arnaldo Carvalho de Melo   perf lock: Use ev...
592
  	ts = thread_stat_findnew(sample->tid);
33d6aef51   David Ahern   perf lock: Remove...
593
  	if (!ts)
b33492ade   Davidlohr Bueso   perf lock: Return...
594
  		return -ENOMEM;
33d6aef51   David Ahern   perf lock: Remove...
595

746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
596
  	seq = get_seq(ts, addr);
33d6aef51   David Ahern   perf lock: Remove...
597
  	if (!seq)
b33492ade   Davidlohr Bueso   perf lock: Return...
598
  		return -ENOMEM;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
599

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
600
601
602
  	switch (seq->state) {
  	case SEQ_STATE_UNINITIALIZED:
  		goto end;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
603
604
605
606
607
608
609
  	case SEQ_STATE_ACQUIRED:
  		break;
  	case SEQ_STATE_READ_ACQUIRED:
  		seq->read_count--;
  		BUG_ON(seq->read_count < 0);
  		if (!seq->read_count) {
  			ls->nr_release++;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
610
611
  			goto end;
  		}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
612
613
614
615
616
617
  		break;
  	case SEQ_STATE_ACQUIRING:
  	case SEQ_STATE_CONTENDED:
  	case SEQ_STATE_RELEASED:
  		/* broken lock sequence, discard it */
  		ls->discard = 1;
10350ec36   Frederic Weisbecker   perf: Cleanup per...
618
  		bad_hist[BROKEN_RELEASE]++;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
619
  		goto free_seq;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
620
  	default:
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
621
622
  		BUG_ON("Unknown state of lock sequence found!
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
623
624
  		break;
  	}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
625
626
627
628
  	ls->nr_release++;
  free_seq:
  	list_del(&seq->list);
  	free(seq);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
629
  end:
33d6aef51   David Ahern   perf lock: Remove...
630
  	return 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
631
632
633
634
  }
  
  /* lock oriented handlers */
  /* TODO: handlers for CPU oriented, thread oriented */
59f411b62   Ingo Molnar   perf lock: Clean ...
635
636
637
638
639
  static struct trace_lock_handler report_lock_ops  = {
  	.acquire_event		= report_lock_acquire_event,
  	.acquired_event		= report_lock_acquired_event,
  	.contended_event	= report_lock_contended_event,
  	.release_event		= report_lock_release_event,
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
640
641
642
  };
  
  static struct trace_lock_handler *trace_handler;
33d6aef51   David Ahern   perf lock: Remove...
643
  static int perf_evsel__process_lock_acquire(struct perf_evsel *evsel,
01d955244   Arnaldo Carvalho de Melo   perf lock: Use ev...
644
  					     struct perf_sample *sample)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
645
  {
59f411b62   Ingo Molnar   perf lock: Clean ...
646
  	if (trace_handler->acquire_event)
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
647
648
  		return trace_handler->acquire_event(evsel, sample);
  	return 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
649
  }
33d6aef51   David Ahern   perf lock: Remove...
650
  static int perf_evsel__process_lock_acquired(struct perf_evsel *evsel,
01d955244   Arnaldo Carvalho de Melo   perf lock: Use ev...
651
  					      struct perf_sample *sample)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
652
  {
33d6aef51   David Ahern   perf lock: Remove...
653
  	if (trace_handler->acquired_event)
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
654
655
  		return trace_handler->acquired_event(evsel, sample);
  	return 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
656
  }
33d6aef51   David Ahern   perf lock: Remove...
657
  static int perf_evsel__process_lock_contended(struct perf_evsel *evsel,
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
658
  					      struct perf_sample *sample)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
659
  {
33d6aef51   David Ahern   perf lock: Remove...
660
  	if (trace_handler->contended_event)
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
661
662
  		return trace_handler->contended_event(evsel, sample);
  	return 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
663
  }
33d6aef51   David Ahern   perf lock: Remove...
664
  static int perf_evsel__process_lock_release(struct perf_evsel *evsel,
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
665
  					    struct perf_sample *sample)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
666
  {
33d6aef51   David Ahern   perf lock: Remove...
667
  	if (trace_handler->release_event)
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
668
669
  		return trace_handler->release_event(evsel, sample);
  	return 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
670
  }
10350ec36   Frederic Weisbecker   perf: Cleanup per...
671
672
673
674
675
676
677
678
679
680
681
  static void print_bad_events(int bad, int total)
  {
  	/* Output for debug, this have to be removed */
  	int i;
  	const char *name[4] =
  		{ "acquire", "acquired", "contended", "release" };
  
  	pr_info("
  === output for debug===
  
  ");
5efe08cf6   Frederic Weisbecker   perf: Fix perf lo...
682
683
  	pr_info("bad: %d, total: %d
  ", bad, total);
60a25cbc4   Davidlohr Bueso   perf lock: Limit ...
684
685
  	pr_info("bad rate: %.2f %%
  ", (double)bad / (double)total * 100);
10350ec36   Frederic Weisbecker   perf: Cleanup per...
686
687
688
689
690
691
  	pr_info("histogram of events caused bad sequence
  ");
  	for (i = 0; i < BROKEN_MAX; i++)
  		pr_info(" %10s: %d
  ", name[i], bad_hist[i]);
  }
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
692
693
694
695
696
  /* TODO: various way to print, coloring, nano or milli sec */
  static void print_result(void)
  {
  	struct lock_stat *st;
  	char cut_name[20];
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
697
  	int bad, total;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
698

26242d859   Hitoshi Mitake   perf lock: Add "i...
699
700
701
  	pr_info("%20s ", "Name");
  	pr_info("%10s ", "acquired");
  	pr_info("%10s ", "contended");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
702

f37376cd7   Davidlohr Bueso   perf lock: Accoun...
703
  	pr_info("%15s ", "avg wait (ns)");
26242d859   Hitoshi Mitake   perf lock: Add "i...
704
705
706
  	pr_info("%15s ", "total wait (ns)");
  	pr_info("%15s ", "max wait (ns)");
  	pr_info("%15s ", "min wait (ns)");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
707

26242d859   Hitoshi Mitake   perf lock: Add "i...
708
709
710
  	pr_info("
  
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
711

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
712
  	bad = total = 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
713
  	while ((st = pop_from_result())) {
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
714
715
716
717
718
  		total++;
  		if (st->discard) {
  			bad++;
  			continue;
  		}
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
719
  		bzero(cut_name, 20);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
720
721
  		if (strlen(st->name) < 16) {
  			/* output raw name */
26242d859   Hitoshi Mitake   perf lock: Add "i...
722
  			pr_info("%20s ", st->name);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
723
724
725
726
727
728
729
  		} else {
  			strncpy(cut_name, st->name, 16);
  			cut_name[16] = '.';
  			cut_name[17] = '.';
  			cut_name[18] = '.';
  			cut_name[19] = '\0';
  			/* cut off name for saving output style */
26242d859   Hitoshi Mitake   perf lock: Add "i...
730
  			pr_info("%20s ", cut_name);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
731
  		}
26242d859   Hitoshi Mitake   perf lock: Add "i...
732
733
  		pr_info("%10u ", st->nr_acquired);
  		pr_info("%10u ", st->nr_contended);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
734

f37376cd7   Davidlohr Bueso   perf lock: Accoun...
735
  		pr_info("%15" PRIu64 " ", st->avg_wait_time);
9486aa387   Arnaldo Carvalho de Melo   perf tools: Fix 6...
736
737
738
  		pr_info("%15" PRIu64 " ", st->wait_time_total);
  		pr_info("%15" PRIu64 " ", st->wait_time_max);
  		pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ?
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
739
  		       0 : st->wait_time_min);
26242d859   Hitoshi Mitake   perf lock: Add "i...
740
741
  		pr_info("
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
742
  	}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
743

10350ec36   Frederic Weisbecker   perf: Cleanup per...
744
  	print_bad_events(bad, total);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
745
  }
8035458fb   Arnaldo Carvalho de Melo   perf options: Typ...
746
  static bool info_threads, info_map;
26242d859   Hitoshi Mitake   perf lock: Add "i...
747
748
749
750
751
752
753
754
755
756
757
758
759
760
  
  static void dump_threads(void)
  {
  	struct thread_stat *st;
  	struct rb_node *node;
  	struct thread *t;
  
  	pr_info("%10s: comm
  ", "Thread ID");
  
  	node = rb_first(&thread_stats);
  	while (node) {
  		st = container_of(node, struct thread_stat, rb);
  		t = perf_session__findnew(session, st->tid);
b9c5143a0   Frederic Weisbecker   perf tools: Use a...
761
762
  		pr_info("%10d: %s
  ", st->tid, thread__comm_str(t));
26242d859   Hitoshi Mitake   perf lock: Add "i...
763
  		node = rb_next(node);
b91fc39f4   Arnaldo Carvalho de Melo   perf machine: Pro...
764
  		thread__put(t);
26242d859   Hitoshi Mitake   perf lock: Add "i...
765
766
  	};
  }
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
767
768
769
770
  static void dump_map(void)
  {
  	unsigned int i;
  	struct lock_stat *st;
26242d859   Hitoshi Mitake   perf lock: Add "i...
771
772
  	pr_info("Address of instance: name of class
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
773
774
  	for (i = 0; i < LOCKHASH_SIZE; i++) {
  		list_for_each_entry(st, &lockhash_table[i], hash_entry) {
26242d859   Hitoshi Mitake   perf lock: Add "i...
775
776
  			pr_info(" %p: %s
  ", st->addr, st->name);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
777
778
779
  		}
  	}
  }
33d6aef51   David Ahern   perf lock: Remove...
780
  static int dump_info(void)
26242d859   Hitoshi Mitake   perf lock: Add "i...
781
  {
33d6aef51   David Ahern   perf lock: Remove...
782
  	int rc = 0;
26242d859   Hitoshi Mitake   perf lock: Add "i...
783
784
785
786
  	if (info_threads)
  		dump_threads();
  	else if (info_map)
  		dump_map();
33d6aef51   David Ahern   perf lock: Remove...
787
788
789
790
791
792
793
  	else {
  		rc = -1;
  		pr_err("Unknown type of information
  ");
  	}
  
  	return rc;
26242d859   Hitoshi Mitake   perf lock: Add "i...
794
  }
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
795
796
  typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
  				  struct perf_sample *sample);
1d037ca16   Irina Tirdea   perf tools: Use _...
797
  static int process_sample_event(struct perf_tool *tool __maybe_unused,
d20deb64e   Arnaldo Carvalho de Melo   perf tools: Pass ...
798
  				union perf_event *event,
9e69c2108   Arnaldo Carvalho de Melo   perf session: Pas...
799
  				struct perf_sample *sample,
fcf65bf14   Arnaldo Carvalho de Melo   perf evsel: Cache...
800
  				struct perf_evsel *evsel,
743eb8686   Arnaldo Carvalho de Melo   perf tools: Resol...
801
  				struct machine *machine)
c61e52ee7   Frederic Weisbecker   perf: Generalize ...
802
  {
b91fc39f4   Arnaldo Carvalho de Melo   perf machine: Pro...
803
  	int err = 0;
314add6b1   Adrian Hunter   perf tools: chang...
804
805
  	struct thread *thread = machine__findnew_thread(machine, sample->pid,
  							sample->tid);
c61e52ee7   Frederic Weisbecker   perf: Generalize ...
806

c61e52ee7   Frederic Weisbecker   perf: Generalize ...
807
808
809
  	if (thread == NULL) {
  		pr_debug("problem processing %d event, skipping it.
  ",
8115d60c3   Arnaldo Carvalho de Melo   perf tools: Kill ...
810
  			event->header.type);
c61e52ee7   Frederic Weisbecker   perf: Generalize ...
811
812
  		return -1;
  	}
744a97194   Arnaldo Carvalho de Melo   perf evsel: Ditch...
813
814
  	if (evsel->handler != NULL) {
  		tracepoint_handler f = evsel->handler;
b91fc39f4   Arnaldo Carvalho de Melo   perf machine: Pro...
815
  		err = f(evsel, sample);
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
816
  	}
b91fc39f4   Arnaldo Carvalho de Melo   perf machine: Pro...
817
818
819
  	thread__put(thread);
  
  	return err;
c61e52ee7   Frederic Weisbecker   perf: Generalize ...
820
  }
375eb2be5   Davidlohr Bueso   perf lock: Redo _...
821
822
823
824
825
826
827
828
829
830
831
  static void sort_result(void)
  {
  	unsigned int i;
  	struct lock_stat *st;
  
  	for (i = 0; i < LOCKHASH_SIZE; i++) {
  		list_for_each_entry(st, &lockhash_table[i], hash_entry) {
  			insert_to_result(st, compare);
  		}
  	}
  }
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
832
833
834
835
836
837
  static const struct perf_evsel_str_handler lock_tracepoints[] = {
  	{ "lock:lock_acquire",	 perf_evsel__process_lock_acquire,   }, /* CONFIG_LOCKDEP */
  	{ "lock:lock_acquired",	 perf_evsel__process_lock_acquired,  }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
  	{ "lock:lock_contended", perf_evsel__process_lock_contended, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
  	{ "lock:lock_release",	 perf_evsel__process_lock_release,   }, /* CONFIG_LOCKDEP */
  };
c4ac732a0   Yunlong Song   perf lock: Suppor...
838
  static bool force;
375eb2be5   Davidlohr Bueso   perf lock: Redo _...
839
  static int __cmd_report(bool display_info)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
840
  {
375eb2be5   Davidlohr Bueso   perf lock: Redo _...
841
  	int err = -EINVAL;
c75d98afa   Arnaldo Carvalho de Melo   perf lock: Don't ...
842
843
844
  	struct perf_tool eops = {
  		.sample		 = process_sample_event,
  		.comm		 = perf_event__process_comm,
f3b3614a2   Hari Bathini   perf tools: Add P...
845
  		.namespaces	 = perf_event__process_namespaces,
0a8cb85c2   Jiri Olsa   perf tools: Renam...
846
  		.ordered_events	 = true,
c75d98afa   Arnaldo Carvalho de Melo   perf lock: Don't ...
847
  	};
f5fc14124   Jiri Olsa   perf tools: Add d...
848
849
850
  	struct perf_data_file file = {
  		.path = input_name,
  		.mode = PERF_DATA_MODE_READ,
c4ac732a0   Yunlong Song   perf lock: Suppor...
851
  		.force = force,
f5fc14124   Jiri Olsa   perf tools: Add d...
852
  	};
375eb2be5   Davidlohr Bueso   perf lock: Redo _...
853

f5fc14124   Jiri Olsa   perf tools: Add d...
854
  	session = perf_session__new(&file, false, &eops);
33d6aef51   David Ahern   perf lock: Remove...
855
856
857
  	if (!session) {
  		pr_err("Initializing perf session failed
  ");
52e028349   Taeung Song   perf tools: Modif...
858
  		return -1;
33d6aef51   David Ahern   perf lock: Remove...
859
  	}
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
860

0a7e6d1b6   Namhyung Kim   perf tools: Check...
861
  	symbol__init(&session->header.env);
6fd6c6b46   Namhyung Kim   perf lock: Move c...
862

375eb2be5   Davidlohr Bueso   perf lock: Redo _...
863
864
  	if (!perf_session__has_traces(session, "lock record"))
  		goto out_delete;
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
865
866
867
  	if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) {
  		pr_err("Initializing perf session tracepoint handlers failed
  ");
375eb2be5   Davidlohr Bueso   perf lock: Redo _...
868
  		goto out_delete;
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
869
  	}
375eb2be5   Davidlohr Bueso   perf lock: Redo _...
870
871
  	if (select_key())
  		goto out_delete;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
872

b7b61cbeb   Arnaldo Carvalho de Melo   perf ordered_even...
873
  	err = perf_session__process_events(session);
375eb2be5   Davidlohr Bueso   perf lock: Redo _...
874
875
  	if (err)
  		goto out_delete;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
876

9b5e350c7   Hitoshi Mitake   perf lock: Introd...
877
  	setup_pager();
375eb2be5   Davidlohr Bueso   perf lock: Redo _...
878
879
880
881
882
883
  	if (display_info) /* used for info subcommand */
  		err = dump_info();
  	else {
  		sort_result();
  		print_result();
  	}
33d6aef51   David Ahern   perf lock: Remove...
884

375eb2be5   Davidlohr Bueso   perf lock: Redo _...
885
886
887
  out_delete:
  	perf_session__delete(session);
  	return err;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
888
  }
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
889
890
  static int __cmd_record(int argc, const char **argv)
  {
c75d98afa   Arnaldo Carvalho de Melo   perf lock: Don't ...
891
  	const char *record_args[] = {
4a4d371a4   Jiri Olsa   perf record: Remo...
892
  		"record", "-R", "-m", "1024", "-c", "1",
c75d98afa   Arnaldo Carvalho de Melo   perf lock: Don't ...
893
  	};
0a98c7feb   Davidlohr Bueso   perf lock: Plug s...
894
  	unsigned int rec_argc, i, j, ret;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
895
  	const char **rec_argv;
d25dcba85   David Ahern   perf lock record:...
896
  	for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) {
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
897
  		if (!is_valid_tracepoint(lock_tracepoints[i].name)) {
d25dcba85   David Ahern   perf lock record:...
898
899
900
  				pr_err("tracepoint %s is not enabled. "
  				       "Are CONFIG_LOCKDEP and CONFIG_LOCK_STAT enabled?
  ",
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
901
  				       lock_tracepoints[i].name);
d25dcba85   David Ahern   perf lock record:...
902
903
904
  				return 1;
  		}
  	}
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
905
  	rec_argc = ARRAY_SIZE(record_args) + argc - 1;
d25dcba85   David Ahern   perf lock record:...
906
907
  	/* factor of 2 is for -e in front of each tracepoint */
  	rec_argc += 2 * ARRAY_SIZE(lock_tracepoints);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
908

d25dcba85   David Ahern   perf lock record:...
909
  	rec_argv = calloc(rec_argc + 1, sizeof(char *));
0a98c7feb   Davidlohr Bueso   perf lock: Plug s...
910
  	if (!rec_argv)
ce47dc56a   Chris Samuel   perf tools: Catch...
911
  		return -ENOMEM;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
912
913
  	for (i = 0; i < ARRAY_SIZE(record_args); i++)
  		rec_argv[i] = strdup(record_args[i]);
d25dcba85   David Ahern   perf lock record:...
914
915
  	for (j = 0; j < ARRAY_SIZE(lock_tracepoints); j++) {
  		rec_argv[i++] = "-e";
746f16ec6   Arnaldo Carvalho de Melo   perf lock: Use pe...
916
  		rec_argv[i++] = strdup(lock_tracepoints[j].name);
d25dcba85   David Ahern   perf lock record:...
917
  	}
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
918
919
920
921
  	for (j = 1; j < (unsigned int)argc; j++, i++)
  		rec_argv[i] = argv[j];
  
  	BUG_ON(i != rec_argc);
b0ad8ea66   Arnaldo Carvalho de Melo   perf tools: Remov...
922
  	ret = cmd_record(i, rec_argv);
0a98c7feb   Davidlohr Bueso   perf lock: Plug s...
923
924
  	free(rec_argv);
  	return ret;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
925
  }
b0ad8ea66   Arnaldo Carvalho de Melo   perf tools: Remov...
926
  int cmd_lock(int argc, const char **argv)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
927
  {
249eed531   Changbin Du   perf lock: Subcom...
928
929
930
931
  	const struct option lock_options[] = {
  	OPT_STRING('i', "input", &input_name, "file", "input file name"),
  	OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
  	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
b40e36121   Arnaldo Carvalho de Melo   perf lock: Make '...
932
  	OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
249eed531   Changbin Du   perf lock: Subcom...
933
934
  	OPT_END()
  	};
c75d98afa   Arnaldo Carvalho de Melo   perf lock: Don't ...
935
936
937
938
939
  	const struct option info_options[] = {
  	OPT_BOOLEAN('t', "threads", &info_threads,
  		    "dump thread list in perf.data"),
  	OPT_BOOLEAN('m', "map", &info_map,
  		    "map of lock instances (address:name table)"),
249eed531   Changbin Du   perf lock: Subcom...
940
  	OPT_PARENT(lock_options)
c75d98afa   Arnaldo Carvalho de Melo   perf lock: Don't ...
941
  	};
249eed531   Changbin Du   perf lock: Subcom...
942

c75d98afa   Arnaldo Carvalho de Melo   perf lock: Don't ...
943
944
  	const struct option report_options[] = {
  	OPT_STRING('k', "key", &sort_key, "acquired",
f37376cd7   Davidlohr Bueso   perf lock: Accoun...
945
  		    "key for sorting (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"),
c75d98afa   Arnaldo Carvalho de Melo   perf lock: Don't ...
946
  	/* TODO: type */
249eed531   Changbin Du   perf lock: Subcom...
947
  	OPT_PARENT(lock_options)
c75d98afa   Arnaldo Carvalho de Melo   perf lock: Don't ...
948
  	};
249eed531   Changbin Du   perf lock: Subcom...
949

c75d98afa   Arnaldo Carvalho de Melo   perf lock: Don't ...
950
951
952
953
  	const char * const info_usage[] = {
  		"perf lock info [<options>]",
  		NULL
  	};
a2368c319   Ramkumar Ramachandra   perf lock: Introd...
954
955
956
957
  	const char *const lock_subcommands[] = { "record", "report", "script",
  						 "info", NULL };
  	const char *lock_usage[] = {
  		NULL,
c75d98afa   Arnaldo Carvalho de Melo   perf lock: Don't ...
958
959
960
961
962
963
  		NULL
  	};
  	const char * const report_usage[] = {
  		"perf lock report [<options>]",
  		NULL
  	};
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
964
  	unsigned int i;
33d6aef51   David Ahern   perf lock: Remove...
965
  	int rc = 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
966

9b5e350c7   Hitoshi Mitake   perf lock: Introd...
967
968
  	for (i = 0; i < LOCKHASH_SIZE; i++)
  		INIT_LIST_HEAD(lockhash_table + i);
a2368c319   Ramkumar Ramachandra   perf lock: Introd...
969
970
  	argc = parse_options_subcommand(argc, argv, lock_options, lock_subcommands,
  					lock_usage, PARSE_OPT_STOP_AT_NON_OPTION);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
971
972
973
974
975
  	if (!argc)
  		usage_with_options(lock_usage, lock_options);
  
  	if (!strncmp(argv[0], "rec", 3)) {
  		return __cmd_record(argc, argv);
59f411b62   Ingo Molnar   perf lock: Clean ...
976
977
  	} else if (!strncmp(argv[0], "report", 6)) {
  		trace_handler = &report_lock_ops;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
978
979
  		if (argc) {
  			argc = parse_options(argc, argv,
59f411b62   Ingo Molnar   perf lock: Clean ...
980
  					     report_options, report_usage, 0);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
981
  			if (argc)
59f411b62   Ingo Molnar   perf lock: Clean ...
982
  				usage_with_options(report_usage, report_options);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
983
  		}
375eb2be5   Davidlohr Bueso   perf lock: Redo _...
984
  		rc = __cmd_report(false);
133dc4c39   Ingo Molnar   perf: Rename 'per...
985
986
  	} else if (!strcmp(argv[0], "script")) {
  		/* Aliased to 'perf script' */
b0ad8ea66   Arnaldo Carvalho de Melo   perf tools: Remov...
987
  		return cmd_script(argc, argv);
26242d859   Hitoshi Mitake   perf lock: Add "i...
988
989
990
991
992
993
994
  	} else if (!strcmp(argv[0], "info")) {
  		if (argc) {
  			argc = parse_options(argc, argv,
  					     info_options, info_usage, 0);
  			if (argc)
  				usage_with_options(info_usage, info_options);
  		}
59f411b62   Ingo Molnar   perf lock: Clean ...
995
996
  		/* recycling report_lock_ops */
  		trace_handler = &report_lock_ops;
375eb2be5   Davidlohr Bueso   perf lock: Redo _...
997
  		rc = __cmd_report(true);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
998
999
1000
  	} else {
  		usage_with_options(lock_usage, lock_options);
  	}
33d6aef51   David Ahern   perf lock: Remove...
1001
  	return rc;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
1002
  }