Blame view

kernel/latencytop.c 7.88 KB
9745512ce   Arjan van de Ven   sched: latencytop...
1
2
3
4
5
6
7
8
9
10
11
  /*
   * latencytop.c: Latency display infrastructure
   *
   * (C) Copyright 2008 Intel Corporation
   * Author: Arjan van de Ven <arjan@linux.intel.com>
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; version 2
   * of the License.
   */
ad0b0fd55   Arjan van de Ven   sched, latencytop...
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
  
  /*
   * CONFIG_LATENCYTOP enables a kernel latency tracking infrastructure that is
   * used by the "latencytop" userspace tool. The latency that is tracked is not
   * the 'traditional' interrupt latency (which is primarily caused by something
   * else consuming CPU), but instead, it is the latency an application encounters
   * because the kernel sleeps on its behalf for various reasons.
   *
   * This code tracks 2 levels of statistics:
   * 1) System level latency
   * 2) Per process latency
   *
   * The latency is stored in fixed sized data structures in an accumulated form;
   * if the "same" latency cause is hit twice, this will be tracked as one entry
   * in the data structure. Both the count, total accumulated latency and maximum
   * latency are tracked in this data structure. When the fixed size structure is
   * full, no new causes are tracked until the buffer is flushed by writing to
   * the /proc file; the userspace tool does this on a regular basis.
   *
   * A latency cause is identified by a stringified backtrace at the point that
   * the scheduler gets invoked. The userland tool will use this string to
   * identify the cause of the latency in human readable form.
   *
   * The information is exported via /proc/latency_stats and /proc/<pid>/latency.
   * These files look like this:
   *
   * Latency Top version : v0.1
   * 70 59433 4897 i915_irq_wait drm_ioctl vfs_ioctl do_vfs_ioctl sys_ioctl
   * |    |    |    |
   * |    |    |    +----> the stringified backtrace
   * |    |    +---------> The maximum latency for this entry in microseconds
   * |    +--------------> The accumulated latency for this entry (microseconds)
   * +-------------------> The number of times this entry is hit
   *
   * (note: the average latency is the accumulated latency divided by the number
   * of times)
   */
9745512ce   Arjan van de Ven   sched: latencytop...
49
50
51
52
53
  #include <linux/kallsyms.h>
  #include <linux/seq_file.h>
  #include <linux/notifier.h>
  #include <linux/spinlock.h>
  #include <linux/proc_fs.h>
cb2517653   Mel Gorman   sched/debug: Make...
54
  #include <linux/latencytop.h>
9984de1a5   Paul Gortmaker   kernel: Map most ...
55
  #include <linux/export.h>
9745512ce   Arjan van de Ven   sched: latencytop...
56
  #include <linux/sched.h>
b17b01533   Ingo Molnar   sched/headers: Pr...
57
  #include <linux/sched/debug.h>
3905f9ad4   Ingo Molnar   sched/headers: Pr...
58
  #include <linux/sched/stat.h>
9745512ce   Arjan van de Ven   sched: latencytop...
59
  #include <linux/list.h>
9745512ce   Arjan van de Ven   sched: latencytop...
60
  #include <linux/stacktrace.h>
757455d41   Thomas Gleixner   locking, latencyt...
61
  static DEFINE_RAW_SPINLOCK(latency_lock);
9745512ce   Arjan van de Ven   sched: latencytop...
62
63
64
65
66
67
68
69
70
71
72
73
  
  #define MAXLR 128
  static struct latency_record latency_record[MAXLR];
  
  int latencytop_enabled;
  
  void clear_all_latency_tracing(struct task_struct *p)
  {
  	unsigned long flags;
  
  	if (!latencytop_enabled)
  		return;
757455d41   Thomas Gleixner   locking, latencyt...
74
  	raw_spin_lock_irqsave(&latency_lock, flags);
9745512ce   Arjan van de Ven   sched: latencytop...
75
76
  	memset(&p->latency_record, 0, sizeof(p->latency_record));
  	p->latency_record_count = 0;
757455d41   Thomas Gleixner   locking, latencyt...
77
  	raw_spin_unlock_irqrestore(&latency_lock, flags);
9745512ce   Arjan van de Ven   sched: latencytop...
78
79
80
81
82
  }
  
  static void clear_global_latency_tracing(void)
  {
  	unsigned long flags;
757455d41   Thomas Gleixner   locking, latencyt...
83
  	raw_spin_lock_irqsave(&latency_lock, flags);
9745512ce   Arjan van de Ven   sched: latencytop...
84
  	memset(&latency_record, 0, sizeof(latency_record));
757455d41   Thomas Gleixner   locking, latencyt...
85
  	raw_spin_unlock_irqrestore(&latency_lock, flags);
9745512ce   Arjan van de Ven   sched: latencytop...
86
87
88
  }
  
  static void __sched
eaa1809b9   Fabian Frederick   kernel/latencytop...
89
90
  account_global_scheduler_latency(struct task_struct *tsk,
  				 struct latency_record *lat)
9745512ce   Arjan van de Ven   sched: latencytop...
91
92
93
94
95
96
97
98
99
100
101
102
  {
  	int firstnonnull = MAXLR + 1;
  	int i;
  
  	if (!latencytop_enabled)
  		return;
  
  	/* skip kernel threads for now */
  	if (!tsk->mm)
  		return;
  
  	for (i = 0; i < MAXLR; i++) {
19fb518c2   Dmitry Adamushko   latencytop: optim...
103
  		int q, same = 1;
9745512ce   Arjan van de Ven   sched: latencytop...
104
105
106
107
108
109
  		/* Nothing stored: */
  		if (!latency_record[i].backtrace[0]) {
  			if (firstnonnull > i)
  				firstnonnull = i;
  			continue;
  		}
ad0b0fd55   Arjan van de Ven   sched, latencytop...
110
  		for (q = 0; q < LT_BACKTRACEDEPTH; q++) {
19fb518c2   Dmitry Adamushko   latencytop: optim...
111
112
113
  			unsigned long record = lat->backtrace[q];
  
  			if (latency_record[i].backtrace[q] != record) {
9745512ce   Arjan van de Ven   sched: latencytop...
114
  				same = 0;
9745512ce   Arjan van de Ven   sched: latencytop...
115
  				break;
19fb518c2   Dmitry Adamushko   latencytop: optim...
116
117
118
119
  			}
  
  			/* 0 and ULONG_MAX entries mean end of backtrace: */
  			if (record == 0 || record == ULONG_MAX)
9745512ce   Arjan van de Ven   sched: latencytop...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  				break;
  		}
  		if (same) {
  			latency_record[i].count++;
  			latency_record[i].time += lat->time;
  			if (lat->time > latency_record[i].max)
  				latency_record[i].max = lat->time;
  			return;
  		}
  	}
  
  	i = firstnonnull;
  	if (i >= MAXLR - 1)
  		return;
  
  	/* Allocted a new one: */
  	memcpy(&latency_record[i], lat, sizeof(struct latency_record));
  }
ad0b0fd55   Arjan van de Ven   sched, latencytop...
138
139
140
141
142
  /*
   * Iterator to store a backtrace into a latency record entry
   */
  static inline void store_stacktrace(struct task_struct *tsk,
  					struct latency_record *lat)
9745512ce   Arjan van de Ven   sched: latencytop...
143
144
145
146
147
148
  {
  	struct stack_trace trace;
  
  	memset(&trace, 0, sizeof(trace));
  	trace.max_entries = LT_BACKTRACEDEPTH;
  	trace.entries = &lat->backtrace[0];
9745512ce   Arjan van de Ven   sched: latencytop...
149
150
  	save_stack_trace_tsk(tsk, &trace);
  }
ad0b0fd55   Arjan van de Ven   sched, latencytop...
151
  /**
25985edce   Lucas De Marchi   Fix common misspe...
152
   * __account_scheduler_latency - record an occurred latency
ad0b0fd55   Arjan van de Ven   sched, latencytop...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
   * @tsk - the task struct of the task hitting the latency
   * @usecs - the duration of the latency in microseconds
   * @inter - 1 if the sleep was interruptible, 0 if uninterruptible
   *
   * This function is the main entry point for recording latency entries
   * as called by the scheduler.
   *
   * This function has a few special cases to deal with normal 'non-latency'
   * sleeps: specifically, interruptible sleep longer than 5 msec is skipped
   * since this usually is caused by waiting for events via select() and co.
   *
   * Negative latencies (caused by time going backwards) are also explicitly
   * skipped.
   */
9745512ce   Arjan van de Ven   sched: latencytop...
167
  void __sched
ad0b0fd55   Arjan van de Ven   sched, latencytop...
168
  __account_scheduler_latency(struct task_struct *tsk, int usecs, int inter)
9745512ce   Arjan van de Ven   sched: latencytop...
169
170
171
172
  {
  	unsigned long flags;
  	int i, q;
  	struct latency_record lat;
9745512ce   Arjan van de Ven   sched: latencytop...
173
174
175
  	/* Long interruptible waits are generally user requested... */
  	if (inter && usecs > 5000)
  		return;
ad0b0fd55   Arjan van de Ven   sched, latencytop...
176
177
178
179
  	/* Negative sleeps are time going backwards */
  	/* Zero-time sleeps are non-interesting */
  	if (usecs <= 0)
  		return;
9745512ce   Arjan van de Ven   sched: latencytop...
180
181
182
183
184
  	memset(&lat, 0, sizeof(lat));
  	lat.count = 1;
  	lat.time = usecs;
  	lat.max = usecs;
  	store_stacktrace(tsk, &lat);
757455d41   Thomas Gleixner   locking, latencyt...
185
  	raw_spin_lock_irqsave(&latency_lock, flags);
9745512ce   Arjan van de Ven   sched: latencytop...
186
187
  
  	account_global_scheduler_latency(tsk, &lat);
38715258a   Ken Chen   latencytop: fix p...
188
  	for (i = 0; i < tsk->latency_record_count; i++) {
9745512ce   Arjan van de Ven   sched: latencytop...
189
190
  		struct latency_record *mylat;
  		int same = 1;
19fb518c2   Dmitry Adamushko   latencytop: optim...
191

9745512ce   Arjan van de Ven   sched: latencytop...
192
  		mylat = &tsk->latency_record[i];
ad0b0fd55   Arjan van de Ven   sched, latencytop...
193
  		for (q = 0; q < LT_BACKTRACEDEPTH; q++) {
19fb518c2   Dmitry Adamushko   latencytop: optim...
194
195
196
  			unsigned long record = lat.backtrace[q];
  
  			if (mylat->backtrace[q] != record) {
9745512ce   Arjan van de Ven   sched: latencytop...
197
  				same = 0;
9745512ce   Arjan van de Ven   sched: latencytop...
198
  				break;
19fb518c2   Dmitry Adamushko   latencytop: optim...
199
200
201
202
  			}
  
  			/* 0 and ULONG_MAX entries mean end of backtrace: */
  			if (record == 0 || record == ULONG_MAX)
9745512ce   Arjan van de Ven   sched: latencytop...
203
204
205
206
207
208
209
210
211
212
  				break;
  		}
  		if (same) {
  			mylat->count++;
  			mylat->time += lat.time;
  			if (lat.time > mylat->max)
  				mylat->max = lat.time;
  			goto out_unlock;
  		}
  	}
38715258a   Ken Chen   latencytop: fix p...
213
214
215
216
217
  	/*
  	 * short term hack; if we're > 32 we stop; future we recycle:
  	 */
  	if (tsk->latency_record_count >= LT_SAVECOUNT)
  		goto out_unlock;
9745512ce   Arjan van de Ven   sched: latencytop...
218
  	/* Allocated a new one: */
38715258a   Ken Chen   latencytop: fix p...
219
  	i = tsk->latency_record_count++;
9745512ce   Arjan van de Ven   sched: latencytop...
220
221
222
  	memcpy(&tsk->latency_record[i], &lat, sizeof(struct latency_record));
  
  out_unlock:
757455d41   Thomas Gleixner   locking, latencyt...
223
  	raw_spin_unlock_irqrestore(&latency_lock, flags);
9745512ce   Arjan van de Ven   sched: latencytop...
224
225
226
227
228
229
230
231
232
233
  }
  
  static int lstats_show(struct seq_file *m, void *v)
  {
  	int i;
  
  	seq_puts(m, "Latency Top version : v0.1
  ");
  
  	for (i = 0; i < MAXLR; i++) {
34e49d4f6   Joe Perches   fs/proc/base.c, k...
234
235
236
  		struct latency_record *lr = &latency_record[i];
  
  		if (lr->backtrace[0]) {
9745512ce   Arjan van de Ven   sched: latencytop...
237
  			int q;
34e49d4f6   Joe Perches   fs/proc/base.c, k...
238
239
  			seq_printf(m, "%i %lu %lu",
  				   lr->count, lr->time, lr->max);
9745512ce   Arjan van de Ven   sched: latencytop...
240
  			for (q = 0; q < LT_BACKTRACEDEPTH; q++) {
34e49d4f6   Joe Perches   fs/proc/base.c, k...
241
242
  				unsigned long bt = lr->backtrace[q];
  				if (!bt)
9745512ce   Arjan van de Ven   sched: latencytop...
243
  					break;
34e49d4f6   Joe Perches   fs/proc/base.c, k...
244
  				if (bt == ULONG_MAX)
9745512ce   Arjan van de Ven   sched: latencytop...
245
  					break;
34e49d4f6   Joe Perches   fs/proc/base.c, k...
246
  				seq_printf(m, " %ps", (void *)bt);
9745512ce   Arjan van de Ven   sched: latencytop...
247
  			}
eaa1809b9   Fabian Frederick   kernel/latencytop...
248
249
  			seq_puts(m, "
  ");
9745512ce   Arjan van de Ven   sched: latencytop...
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  		}
  	}
  	return 0;
  }
  
  static ssize_t
  lstats_write(struct file *file, const char __user *buf, size_t count,
  	     loff_t *offs)
  {
  	clear_global_latency_tracing();
  
  	return count;
  }
  
  static int lstats_open(struct inode *inode, struct file *filp)
  {
  	return single_open(filp, lstats_show, NULL);
  }
ad0b0fd55   Arjan van de Ven   sched, latencytop...
268
  static const struct file_operations lstats_fops = {
9745512ce   Arjan van de Ven   sched: latencytop...
269
270
271
272
273
274
275
276
277
  	.open		= lstats_open,
  	.read		= seq_read,
  	.write		= lstats_write,
  	.llseek		= seq_lseek,
  	.release	= single_release,
  };
  
  static int __init init_lstats_procfs(void)
  {
c33fff0af   Denis V. Lunev   kernel: use non-r...
278
  	proc_create("latency_stats", 0644, NULL, &lstats_fops);
9745512ce   Arjan van de Ven   sched: latencytop...
279
280
  	return 0;
  }
cb2517653   Mel Gorman   sched/debug: Make...
281
282
283
284
285
286
287
288
289
290
291
292
  
  int sysctl_latencytop(struct ctl_table *table, int write,
  			void __user *buffer, size_t *lenp, loff_t *ppos)
  {
  	int err;
  
  	err = proc_dointvec(table, write, buffer, lenp, ppos);
  	if (latencytop_enabled)
  		force_schedstat_enabled();
  
  	return err;
  }
ad0b0fd55   Arjan van de Ven   sched, latencytop...
293
  device_initcall(init_lstats_procfs);