Blame view

tools/perf/builtin-lock.c 23 KB
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  #include "builtin.h"
  #include "perf.h"
  
  #include "util/util.h"
  #include "util/cache.h"
  #include "util/symbol.h"
  #include "util/thread.h"
  #include "util/header.h"
  
  #include "util/parse-options.h"
  #include "util/trace-event.h"
  
  #include "util/debug.h"
  #include "util/session.h"
45694aa77   Arnaldo Carvalho de Melo   perf tools: Renam...
15
  #include "util/tool.h"
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
16
17
18
19
20
21
22
23
24
25
  
  #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>
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
26
  static struct perf_session *session;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
27
28
29
30
31
32
33
34
  /* 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...
35
  struct lock_stat {
59f411b62   Ingo Molnar   perf lock: Clean ...
36
37
  	struct list_head	hash_entry;
  	struct rb_node		rb;		/* used for sorting */
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
38

59f411b62   Ingo Molnar   perf lock: Clean ...
39
40
  	/*
  	 * FIXME: raw_field_value() returns unsigned long long,
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
41
  	 * so address of lockdep_map should be dealed as 64bit.
59f411b62   Ingo Molnar   perf lock: Clean ...
42
43
44
45
  	 * 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...
46

59f411b62   Ingo Molnar   perf lock: Clean ...
47
  	unsigned int		nr_acquire;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
48
  	unsigned int		nr_acquired;
59f411b62   Ingo Molnar   perf lock: Clean ...
49
50
  	unsigned int		nr_contended;
  	unsigned int		nr_release;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
51

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
52
53
  	unsigned int		nr_readlock;
  	unsigned int		nr_trylock;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
54
  	/* these times are in nano sec. */
59f411b62   Ingo Molnar   perf lock: Clean ...
55
56
57
  	u64			wait_time_total;
  	u64			wait_time_min;
  	u64			wait_time_max;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
58
59
60
61
62
63
64
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
  
  	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...
99
  };
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
100
101
102
103
104
105
106
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
  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));
  	if (!st)
  		die("memory allocation failed
  ");
  
  	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));
  	if (!st)
  		die("memory allocation failed
  ");
  	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...
193
  /* build simple key function one is bigger than two */
59f411b62   Ingo Molnar   perf lock: Clean ...
194
  #define SINGLE_KEY(member)						\
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
195
196
197
198
199
200
201
202
203
  	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)
  SINGLE_KEY(wait_time_total)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
204
  SINGLE_KEY(wait_time_max)
9df03abed   Marcin Slusarz   perf lock: Fix so...
205
206
207
208
209
210
211
212
213
214
215
  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...
216
217
218
219
220
221
  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 ...
222
223
  	const char		*name;
  	int			(*key)(struct lock_stat*, struct lock_stat*);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
224
  };
59f411b62   Ingo Molnar   perf lock: Clean ...
225
226
227
228
229
  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...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  
  #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),
  	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 }
  };
  
  static void select_key(void)
  {
  	int i;
  
  	for (i = 0; keys[i].name; i++) {
  		if (!strcmp(keys[i].name, sort_key)) {
  			compare = keys[i].key;
  			return;
  		}
  	}
  
  	die("Unknown compare key:%s
  ", sort_key);
  }
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
259
  static void insert_to_result(struct lock_stat *st,
59f411b62   Ingo Molnar   perf lock: Clean ...
260
  			     int (*bigger)(struct lock_stat *, struct lock_stat *))
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
  {
  	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 ...
294
  static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  {
  	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);
  	if (!new->name)
  		goto alloc_failed;
  	strcpy(new->name, name);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
313

9b5e350c7   Hitoshi Mitake   perf lock: Introd...
314
315
316
317
318
319
320
321
322
  	new->wait_time_min = ULLONG_MAX;
  
  	list_add(&new->hash_entry, entry);
  	return new;
  
  alloc_failed:
  	die("memory allocation failed
  ");
  }
efad14150   Robert Richter   perf report: Acce...
323
  static const char *input_name;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
324

9b5e350c7   Hitoshi Mitake   perf lock: Introd...
325
  struct raw_event_sample {
59f411b62   Ingo Molnar   perf lock: Clean ...
326
327
  	u32			size;
  	char			data[0];
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
328
329
330
  };
  
  struct trace_acquire_event {
59f411b62   Ingo Molnar   perf lock: Clean ...
331
332
  	void			*addr;
  	const char		*name;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
333
  	int			flag;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
334
335
336
  };
  
  struct trace_acquired_event {
59f411b62   Ingo Molnar   perf lock: Clean ...
337
338
  	void			*addr;
  	const char		*name;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
339
340
341
  };
  
  struct trace_contended_event {
59f411b62   Ingo Molnar   perf lock: Clean ...
342
343
  	void			*addr;
  	const char		*name;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
344
345
346
  };
  
  struct trace_release_event {
59f411b62   Ingo Molnar   perf lock: Clean ...
347
348
  	void			*addr;
  	const char		*name;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
  };
  
  struct trace_lock_handler {
  	void (*acquire_event)(struct trace_acquire_event *,
  			      struct event *,
  			      int cpu,
  			      u64 timestamp,
  			      struct thread *thread);
  
  	void (*acquired_event)(struct trace_acquired_event *,
  			       struct event *,
  			       int cpu,
  			       u64 timestamp,
  			       struct thread *thread);
  
  	void (*contended_event)(struct trace_contended_event *,
  				struct event *,
  				int cpu,
  				u64 timestamp,
  				struct thread *thread);
  
  	void (*release_event)(struct trace_release_event *,
  			      struct event *,
  			      int cpu,
  			      u64 timestamp,
  			      struct thread *thread);
  };
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
  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));
  	if (!seq)
  		die("Not enough memory
  ");
  	seq->state = SEQ_STATE_UNINITIALIZED;
  	seq->addr = addr;
  
  	list_add(&seq->list, &ts->seq_list);
  	return seq;
  }
10350ec36   Frederic Weisbecker   perf: Cleanup per...
395
396
397
398
399
400
401
402
403
  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...
404

84c7a2179   Frederic Weisbecker   perf: Humanize lo...
405
406
407
408
  enum acquire_flags {
  	TRY_LOCK = 1,
  	READ_LOCK = 2,
  };
59f411b62   Ingo Molnar   perf lock: Clean ...
409
410
  static void
  report_lock_acquire_event(struct trace_acquire_event *acquire_event,
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
411
412
  			struct event *__event __used,
  			int cpu __used,
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
413
  			u64 timestamp __used,
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
414
415
  			struct thread *thread __used)
  {
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
416
417
418
419
420
421
422
  	struct lock_stat *ls;
  	struct thread_stat *ts;
  	struct lock_seq_stat *seq;
  
  	ls = lock_stat_findnew(acquire_event->addr, acquire_event->name);
  	if (ls->discard)
  		return;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
423

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
424
425
  	ts = thread_stat_findnew(thread->pid);
  	seq = get_seq(ts, acquire_event->addr);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
426

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
427
428
429
430
431
432
  	switch (seq->state) {
  	case SEQ_STATE_UNINITIALIZED:
  	case SEQ_STATE_RELEASED:
  		if (!acquire_event->flag) {
  			seq->state = SEQ_STATE_ACQUIRING;
  		} else {
84c7a2179   Frederic Weisbecker   perf: Humanize lo...
433
  			if (acquire_event->flag & TRY_LOCK)
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
434
  				ls->nr_trylock++;
84c7a2179   Frederic Weisbecker   perf: Humanize lo...
435
  			if (acquire_event->flag & READ_LOCK)
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
436
437
438
439
440
441
442
  				ls->nr_readlock++;
  			seq->state = SEQ_STATE_READ_ACQUIRED;
  			seq->read_count = 1;
  			ls->nr_acquired++;
  		}
  		break;
  	case SEQ_STATE_READ_ACQUIRED:
84c7a2179   Frederic Weisbecker   perf: Humanize lo...
443
  		if (acquire_event->flag & READ_LOCK) {
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
444
445
446
447
448
449
  			seq->read_count++;
  			ls->nr_acquired++;
  			goto end;
  		} else {
  			goto broken;
  		}
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
450
  		break;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
451
452
453
454
455
456
  	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...
457
  		bad_hist[BROKEN_ACQUIRE]++;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
458
459
460
  		list_del(&seq->list);
  		free(seq);
  		goto end;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
461
462
  		break;
  	default:
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
463
464
  		BUG_ON("Unknown state of lock sequence found!
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
465
466
  		break;
  	}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
467
468
469
470
  	ls->nr_acquire++;
  	seq->prev_event_time = timestamp;
  end:
  	return;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
471
  }
59f411b62   Ingo Molnar   perf lock: Clean ...
472
473
  static void
  report_lock_acquired_event(struct trace_acquired_event *acquired_event,
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
474
475
  			 struct event *__event __used,
  			 int cpu __used,
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
476
  			 u64 timestamp __used,
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
477
478
  			 struct thread *thread __used)
  {
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
479
480
481
482
  	struct lock_stat *ls;
  	struct thread_stat *ts;
  	struct lock_seq_stat *seq;
  	u64 contended_term;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
483

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
484
485
486
487
488
489
  	ls = lock_stat_findnew(acquired_event->addr, acquired_event->name);
  	if (ls->discard)
  		return;
  
  	ts = thread_stat_findnew(thread->pid);
  	seq = get_seq(ts, acquired_event->addr);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
490

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
491
492
493
494
495
  	switch (seq->state) {
  	case SEQ_STATE_UNINITIALIZED:
  		/* orphan event, do nothing */
  		return;
  	case SEQ_STATE_ACQUIRING:
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
496
  		break;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
497
498
499
  	case SEQ_STATE_CONTENDED:
  		contended_term = timestamp - seq->prev_event_time;
  		ls->wait_time_total += contended_term;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
500
501
  		if (contended_term < ls->wait_time_min)
  			ls->wait_time_min = contended_term;
90c0e5fc7   Frederic Weisbecker   perf lock: Always...
502
  		if (ls->wait_time_max < contended_term)
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
503
  			ls->wait_time_max = contended_term;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
504
  		break;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
505
506
507
508
509
  	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...
510
  		bad_hist[BROKEN_ACQUIRED]++;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
511
512
513
514
  		list_del(&seq->list);
  		free(seq);
  		goto end;
  		break;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
515
  	default:
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
516
517
  		BUG_ON("Unknown state of lock sequence found!
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
518
519
  		break;
  	}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
520
521
522
523
524
  	seq->state = SEQ_STATE_ACQUIRED;
  	ls->nr_acquired++;
  	seq->prev_event_time = timestamp;
  end:
  	return;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
525
  }
59f411b62   Ingo Molnar   perf lock: Clean ...
526
527
  static void
  report_lock_contended_event(struct trace_contended_event *contended_event,
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
528
529
  			  struct event *__event __used,
  			  int cpu __used,
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
530
  			  u64 timestamp __used,
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
531
532
  			  struct thread *thread __used)
  {
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
533
534
535
536
537
538
539
  	struct lock_stat *ls;
  	struct thread_stat *ts;
  	struct lock_seq_stat *seq;
  
  	ls = lock_stat_findnew(contended_event->addr, contended_event->name);
  	if (ls->discard)
  		return;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
540

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
541
542
  	ts = thread_stat_findnew(thread->pid);
  	seq = get_seq(ts, contended_event->addr);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
543

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
544
545
546
547
548
  	switch (seq->state) {
  	case SEQ_STATE_UNINITIALIZED:
  		/* orphan event, do nothing */
  		return;
  	case SEQ_STATE_ACQUIRING:
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
549
  		break;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
550
551
552
553
554
555
  	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...
556
  		bad_hist[BROKEN_CONTENDED]++;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
557
558
559
  		list_del(&seq->list);
  		free(seq);
  		goto end;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
560
561
  		break;
  	default:
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
562
563
  		BUG_ON("Unknown state of lock sequence found!
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
564
565
  		break;
  	}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
566
567
568
569
570
  	seq->state = SEQ_STATE_CONTENDED;
  	ls->nr_contended++;
  	seq->prev_event_time = timestamp;
  end:
  	return;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
571
  }
59f411b62   Ingo Molnar   perf lock: Clean ...
572
573
  static void
  report_lock_release_event(struct trace_release_event *release_event,
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
574
575
  			struct event *__event __used,
  			int cpu __used,
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
576
  			u64 timestamp __used,
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
577
578
  			struct thread *thread __used)
  {
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
579
580
581
  	struct lock_stat *ls;
  	struct thread_stat *ts;
  	struct lock_seq_stat *seq;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
582

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
583
584
585
  	ls = lock_stat_findnew(release_event->addr, release_event->name);
  	if (ls->discard)
  		return;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
586

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
587
588
  	ts = thread_stat_findnew(thread->pid);
  	seq = get_seq(ts, release_event->addr);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
589

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
590
591
592
593
594
595
596
597
598
599
600
  	switch (seq->state) {
  	case SEQ_STATE_UNINITIALIZED:
  		goto end;
  		break;
  	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...
601
602
  			goto end;
  		}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
603
604
605
606
607
608
  		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...
609
  		bad_hist[BROKEN_RELEASE]++;
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
610
  		goto free_seq;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
611
612
  		break;
  	default:
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
613
614
  		BUG_ON("Unknown state of lock sequence found!
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
615
616
  		break;
  	}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
617
618
619
620
  	ls->nr_release++;
  free_seq:
  	list_del(&seq->list);
  	free(seq);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
621
  end:
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
622
  	return;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
623
624
625
626
  }
  
  /* lock oriented handlers */
  /* TODO: handlers for CPU oriented, thread oriented */
59f411b62   Ingo Molnar   perf lock: Clean ...
627
628
629
630
631
  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...
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
  };
  
  static struct trace_lock_handler *trace_handler;
  
  static void
  process_lock_acquire_event(void *data,
  			   struct event *event __used,
  			   int cpu __used,
  			   u64 timestamp __used,
  			   struct thread *thread __used)
  {
  	struct trace_acquire_event acquire_event;
  	u64 tmp;		/* this is required for casting... */
  
  	tmp = raw_field_value(event, "lockdep_addr", data);
  	memcpy(&acquire_event.addr, &tmp, sizeof(void *));
  	acquire_event.name = (char *)raw_field_ptr(event, "name", data);
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
649
  	acquire_event.flag = (int)raw_field_value(event, "flag", data);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
650

59f411b62   Ingo Molnar   perf lock: Clean ...
651
652
  	if (trace_handler->acquire_event)
  		trace_handler->acquire_event(&acquire_event, event, cpu, timestamp, thread);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
  }
  
  static void
  process_lock_acquired_event(void *data,
  			    struct event *event __used,
  			    int cpu __used,
  			    u64 timestamp __used,
  			    struct thread *thread __used)
  {
  	struct trace_acquired_event acquired_event;
  	u64 tmp;		/* this is required for casting... */
  
  	tmp = raw_field_value(event, "lockdep_addr", data);
  	memcpy(&acquired_event.addr, &tmp, sizeof(void *));
  	acquired_event.name = (char *)raw_field_ptr(event, "name", data);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
668

59f411b62   Ingo Molnar   perf lock: Clean ...
669
670
  	if (trace_handler->acquire_event)
  		trace_handler->acquired_event(&acquired_event, event, cpu, timestamp, thread);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
  }
  
  static void
  process_lock_contended_event(void *data,
  			     struct event *event __used,
  			     int cpu __used,
  			     u64 timestamp __used,
  			     struct thread *thread __used)
  {
  	struct trace_contended_event contended_event;
  	u64 tmp;		/* this is required for casting... */
  
  	tmp = raw_field_value(event, "lockdep_addr", data);
  	memcpy(&contended_event.addr, &tmp, sizeof(void *));
  	contended_event.name = (char *)raw_field_ptr(event, "name", data);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
686

59f411b62   Ingo Molnar   perf lock: Clean ...
687
688
  	if (trace_handler->acquire_event)
  		trace_handler->contended_event(&contended_event, event, cpu, timestamp, thread);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
  }
  
  static void
  process_lock_release_event(void *data,
  			   struct event *event __used,
  			   int cpu __used,
  			   u64 timestamp __used,
  			   struct thread *thread __used)
  {
  	struct trace_release_event release_event;
  	u64 tmp;		/* this is required for casting... */
  
  	tmp = raw_field_value(event, "lockdep_addr", data);
  	memcpy(&release_event.addr, &tmp, sizeof(void *));
  	release_event.name = (char *)raw_field_ptr(event, "name", data);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
704

59f411b62   Ingo Molnar   perf lock: Clean ...
705
706
  	if (trace_handler->acquire_event)
  		trace_handler->release_event(&release_event, event, cpu, timestamp, thread);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
707
708
709
  }
  
  static void
c61e52ee7   Frederic Weisbecker   perf: Generalize ...
710
  process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
  {
  	struct event *event;
  	int type;
  
  	type = trace_parse_common_type(data);
  	event = trace_find_event(type);
  
  	if (!strcmp(event->name, "lock_acquire"))
  		process_lock_acquire_event(data, event, cpu, timestamp, thread);
  	if (!strcmp(event->name, "lock_acquired"))
  		process_lock_acquired_event(data, event, cpu, timestamp, thread);
  	if (!strcmp(event->name, "lock_contended"))
  		process_lock_contended_event(data, event, cpu, timestamp, thread);
  	if (!strcmp(event->name, "lock_release"))
  		process_lock_release_event(data, event, cpu, timestamp, thread);
  }
10350ec36   Frederic Weisbecker   perf: Cleanup per...
727
728
729
730
731
732
733
734
735
736
737
  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...
738
739
740
741
  	pr_info("bad: %d, total: %d
  ", bad, total);
  	pr_info("bad rate: %f %%
  ", (double)bad / (double)total * 100);
10350ec36   Frederic Weisbecker   perf: Cleanup per...
742
743
744
745
746
747
  	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...
748
749
750
751
752
  /* 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...
753
  	int bad, total;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
754

26242d859   Hitoshi Mitake   perf lock: Add "i...
755
756
757
  	pr_info("%20s ", "Name");
  	pr_info("%10s ", "acquired");
  	pr_info("%10s ", "contended");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
758

26242d859   Hitoshi Mitake   perf lock: Add "i...
759
760
761
  	pr_info("%15s ", "total wait (ns)");
  	pr_info("%15s ", "max wait (ns)");
  	pr_info("%15s ", "min wait (ns)");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
762

26242d859   Hitoshi Mitake   perf lock: Add "i...
763
764
765
  	pr_info("
  
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
766

e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
767
  	bad = total = 0;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
768
  	while ((st = pop_from_result())) {
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
769
770
771
772
773
  		total++;
  		if (st->discard) {
  			bad++;
  			continue;
  		}
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
774
  		bzero(cut_name, 20);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
775
776
  		if (strlen(st->name) < 16) {
  			/* output raw name */
26242d859   Hitoshi Mitake   perf lock: Add "i...
777
  			pr_info("%20s ", st->name);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
778
779
780
781
782
783
784
  		} 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...
785
  			pr_info("%20s ", cut_name);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
786
  		}
26242d859   Hitoshi Mitake   perf lock: Add "i...
787
788
  		pr_info("%10u ", st->nr_acquired);
  		pr_info("%10u ", st->nr_contended);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
789

9486aa387   Arnaldo Carvalho de Melo   perf tools: Fix 6...
790
791
792
  		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...
793
  		       0 : st->wait_time_min);
26242d859   Hitoshi Mitake   perf lock: Add "i...
794
795
  		pr_info("
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
796
  	}
e4cef1f65   Hitoshi Mitake   perf lock: Fix st...
797

10350ec36   Frederic Weisbecker   perf: Cleanup per...
798
  	print_bad_events(bad, total);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
799
  }
8035458fb   Arnaldo Carvalho de Melo   perf options: Typ...
800
  static bool info_threads, info_map;
26242d859   Hitoshi Mitake   perf lock: Add "i...
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
  
  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);
  		pr_info("%10d: %s
  ", st->tid, t->comm);
  		node = rb_next(node);
  	};
  }
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
820
821
822
823
  static void dump_map(void)
  {
  	unsigned int i;
  	struct lock_stat *st;
26242d859   Hitoshi Mitake   perf lock: Add "i...
824
825
  	pr_info("Address of instance: name of class
  ");
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
826
827
  	for (i = 0; i < LOCKHASH_SIZE; i++) {
  		list_for_each_entry(st, &lockhash_table[i], hash_entry) {
26242d859   Hitoshi Mitake   perf lock: Add "i...
828
829
  			pr_info(" %p: %s
  ", st->addr, st->name);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
830
831
832
  		}
  	}
  }
26242d859   Hitoshi Mitake   perf lock: Add "i...
833
834
835
836
837
838
839
840
841
842
  static void dump_info(void)
  {
  	if (info_threads)
  		dump_threads();
  	else if (info_map)
  		dump_map();
  	else
  		die("Unknown type of information
  ");
  }
45694aa77   Arnaldo Carvalho de Melo   perf tools: Renam...
843
  static int process_sample_event(struct perf_tool *tool __used,
d20deb64e   Arnaldo Carvalho de Melo   perf tools: Pass ...
844
  				union perf_event *event,
9e69c2108   Arnaldo Carvalho de Melo   perf session: Pas...
845
846
  				struct perf_sample *sample,
  				struct perf_evsel *evsel __used,
743eb8686   Arnaldo Carvalho de Melo   perf tools: Resol...
847
  				struct machine *machine)
c61e52ee7   Frederic Weisbecker   perf: Generalize ...
848
  {
743eb8686   Arnaldo Carvalho de Melo   perf tools: Resol...
849
  	struct thread *thread = machine__findnew_thread(machine, sample->tid);
c61e52ee7   Frederic Weisbecker   perf: Generalize ...
850

c61e52ee7   Frederic Weisbecker   perf: Generalize ...
851
852
853
  	if (thread == NULL) {
  		pr_debug("problem processing %d event, skipping it.
  ",
8115d60c3   Arnaldo Carvalho de Melo   perf tools: Kill ...
854
  			event->header.type);
c61e52ee7   Frederic Weisbecker   perf: Generalize ...
855
856
  		return -1;
  	}
640c03ce8   Arnaldo Carvalho de Melo   perf session: Par...
857
  	process_raw_event(sample->raw_data, sample->cpu, sample->time, thread);
c61e52ee7   Frederic Weisbecker   perf: Generalize ...
858
859
860
  
  	return 0;
  }
45694aa77   Arnaldo Carvalho de Melo   perf tools: Renam...
861
  static struct perf_tool eops = {
59f411b62   Ingo Molnar   perf lock: Clean ...
862
  	.sample			= process_sample_event,
8115d60c3   Arnaldo Carvalho de Melo   perf tools: Kill ...
863
  	.comm			= perf_event__process_comm,
c61e52ee7   Frederic Weisbecker   perf: Generalize ...
864
  	.ordered_samples	= true,
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
865
  };
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
866
867
  static int read_events(void)
  {
21ef97f05   Ian Munsie   perf session: Fal...
868
  	session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
  	if (!session)
  		die("Initializing perf session failed
  ");
  
  	return perf_session__process_events(session, &eops);
  }
  
  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);
  		}
  	}
  }
59f411b62   Ingo Molnar   perf lock: Clean ...
887
  static void __cmd_report(void)
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
888
889
890
891
892
893
894
  {
  	setup_pager();
  	select_key();
  	read_events();
  	sort_result();
  	print_result();
  }
59f411b62   Ingo Molnar   perf lock: Clean ...
895
896
  static const char * const report_usage[] = {
  	"perf lock report [<options>]",
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
897
898
  	NULL
  };
59f411b62   Ingo Molnar   perf lock: Clean ...
899
  static const struct option report_options[] = {
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
900
  	OPT_STRING('k', "key", &sort_key, "acquired",
9826e8329   Marcin Slusarz   perf lock: Docume...
901
  		    "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
902
903
904
  	/* TODO: type */
  	OPT_END()
  };
26242d859   Hitoshi Mitake   perf lock: Add "i...
905
906
907
908
909
910
911
912
913
914
915
916
  static const char * const info_usage[] = {
  	"perf lock info [<options>]",
  	NULL
  };
  
  static 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 (name:address table)"),
  	OPT_END()
  };
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
917
  static const char * const lock_usage[] = {
59f411b62   Ingo Molnar   perf lock: Clean ...
918
  	"perf lock [<options>] {record|trace|report}",
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
919
920
921
922
  	NULL
  };
  
  static const struct option lock_options[] = {
59f411b62   Ingo Molnar   perf lock: Clean ...
923
  	OPT_STRING('i', "input", &input_name, "file", "input file name"),
c05556421   Ian Munsie   perf: Fix endiann...
924
  	OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
59f411b62   Ingo Molnar   perf lock: Clean ...
925
  	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
926
927
928
929
930
  	OPT_END()
  };
  
  static const char *record_args[] = {
  	"record",
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
931
  	"-R",
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
932
933
934
  	"-f",
  	"-m", "1024",
  	"-c", "1",
cf8dc9ff2   Zhu Yanhai   perf lock: Droppi...
935
936
937
938
  	"-e", "lock:lock_acquire",
  	"-e", "lock:lock_acquired",
  	"-e", "lock:lock_contended",
  	"-e", "lock:lock_release",
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
939
940
941
942
943
944
945
946
947
  };
  
  static int __cmd_record(int argc, const char **argv)
  {
  	unsigned int rec_argc, i, j;
  	const char **rec_argv;
  
  	rec_argc = ARRAY_SIZE(record_args) + argc - 1;
  	rec_argv = calloc(rec_argc + 1, sizeof(char *));
ce47dc56a   Chris Samuel   perf tools: Catch...
948
949
  	if (rec_argv == NULL)
  		return -ENOMEM;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
  	for (i = 0; i < ARRAY_SIZE(record_args); i++)
  		rec_argv[i] = strdup(record_args[i]);
  
  	for (j = 1; j < (unsigned int)argc; j++, i++)
  		rec_argv[i] = argv[j];
  
  	BUG_ON(i != rec_argc);
  
  	return cmd_record(i, rec_argv, NULL);
  }
  
  int cmd_lock(int argc, const char **argv, const char *prefix __used)
  {
  	unsigned int i;
  
  	symbol__init();
  	for (i = 0; i < LOCKHASH_SIZE; i++)
  		INIT_LIST_HEAD(lockhash_table + i);
  
  	argc = parse_options(argc, argv, lock_options, lock_usage,
  			     PARSE_OPT_STOP_AT_NON_OPTION);
  	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
  		}
59f411b62   Ingo Molnar   perf lock: Clean ...
984
  		__cmd_report();
133dc4c39   Ingo Molnar   perf: Rename 'per...
985
986
987
  	} else if (!strcmp(argv[0], "script")) {
  		/* Aliased to 'perf script' */
  		return cmd_script(argc, argv, prefix);
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;
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
997
998
  		setup_pager();
  		read_events();
26242d859   Hitoshi Mitake   perf lock: Add "i...
999
  		dump_info();
9b5e350c7   Hitoshi Mitake   perf lock: Introd...
1000
1001
1002
1003
1004
1005
  	} else {
  		usage_with_options(lock_usage, lock_options);
  	}
  
  	return 0;
  }