iotop revision 1.1 1 1.1 christos #!/bin/ksh
2 1.1 christos #
3 1.1 christos # iotop - display top disk I/O events by process.
4 1.1 christos # Written using DTrace (Solaris 10 3/05).
5 1.1 christos #
6 1.1 christos # This is measuring disk events that have made it past system caches.
7 1.1 christos #
8 1.1 christos # $Id: iotop,v 1.1 2015/09/30 22:01:06 christos Exp $
9 1.1 christos #
10 1.1 christos # USAGE: iotop [-C] [-D|-o|-P] [-j|-Z] [-d device] [-f filename]
11 1.1 christos # [-m mount_point] [-t top] [interval [count]]
12 1.1 christos #
13 1.1 christos # iotop # default output, 5 second intervals
14 1.1 christos #
15 1.1 christos # -C # don't clear the screen
16 1.1 christos # -D # print delta times, elapsed, us
17 1.1 christos # -j # print project ID
18 1.1 christos # -o # print disk delta times, us
19 1.1 christos # -P # print %I/O (disk delta times)
20 1.1 christos # -Z # print zone ID
21 1.1 christos # -d device # instance name to snoop (eg, dad0)
22 1.1 christos # -f filename # full pathname of file to snoop
23 1.1 christos # -m mount_point # this FS only (will skip raw events)
24 1.1 christos # -t top # print top number only
25 1.1 christos # eg,
26 1.1 christos # iotop 1 # 1 second samples
27 1.1 christos # iotop -C # don't clear the screen
28 1.1 christos # iotop -P # print %I/O (time based)
29 1.1 christos # iotop -j # print project IDs
30 1.1 christos # iotop -Z # print zone IDs
31 1.1 christos # iotop -t 20 # print top 20 lines only
32 1.1 christos # iotop -C 5 12 # print 12 x 5 second samples
33 1.1 christos #
34 1.1 christos # FIELDS:
35 1.1 christos # UID user ID
36 1.1 christos # PID process ID
37 1.1 christos # PPID parent process ID
38 1.1 christos # PROJ project ID
39 1.1 christos # ZONE zone ID
40 1.1 christos # CMD process command name
41 1.1 christos # DEVICE device name
42 1.1 christos # MAJ device major number
43 1.1 christos # MIN device minor number
44 1.1 christos # D direction, Read or Write
45 1.1 christos # BYTES total size of operations, bytes
46 1.1 christos # ELAPSED total elapsed from request to completion, us
47 1.1 christos # DISKTIME total time for disk to complete request, us
48 1.1 christos # %I/O percent disk I/O, based on time (DISKTIME)
49 1.1 christos # load 1 min load average
50 1.1 christos # disk_r total disk read Kbytes for sample
51 1.1 christos # disk_w total disk write Kbytes for sample
52 1.1 christos #
53 1.1 christos # NOTE:
54 1.1 christos # * There are two different delta times reported. -D prints the
55 1.1 christos # elapsed time from the disk request (strategy) to the disk completion
56 1.1 christos # (iodone); -o prints the time for the disk to complete that event
57 1.1 christos # since it's last event (time between iodones), or, the time to the
58 1.1 christos # strategy if the disk had been idle.
59 1.1 christos # * The %I/O value can exceed 100%. It represents how busy a process is
60 1.1 christos # making the disks, in terms of a single disk. A value of 200% could
61 1.1 christos # mean 2 disks are busy at 100%, or 4 disks at 50%...
62 1.1 christos #
63 1.1 christos # SEE ALSO: iosnoop
64 1.1 christos # BigAdmin: DTrace, http://www.sun.com/bigadmin/content/dtrace
65 1.1 christos # Solaris Dynamic Tracing Guide, http://docs.sun.com
66 1.1 christos # DTrace Tools, http://www.brendangregg.com/dtrace.html
67 1.1 christos #
68 1.1 christos # INSPIRATION: top(1) by William LeFebvre
69 1.1 christos #
70 1.1 christos # COPYRIGHT: Copyright (c) 2005, 2006 Brendan Gregg.
71 1.1 christos #
72 1.1 christos # CDDL HEADER START
73 1.1 christos #
74 1.1 christos # The contents of this file are subject to the terms of the
75 1.1 christos # Common Development and Distribution License, Version 1.0 only
76 1.1 christos # (the "License"). You may not use this file except in compliance
77 1.1 christos # with the License.
78 1.1 christos #
79 1.1 christos # You can obtain a copy of the license at Docs/cddl1.txt
80 1.1 christos # or http://www.opensolaris.org/os/licensing.
81 1.1 christos # See the License for the specific language governing permissions
82 1.1 christos # and limitations under the License.
83 1.1 christos #
84 1.1 christos # CDDL HEADER END
85 1.1 christos #
86 1.1 christos # KNOWN BUGS:
87 1.1 christos # - This can print errors while running on servers with Veritas volumes.
88 1.1 christos #
89 1.1 christos # Author: Brendan Gregg [Sydney, Australia]
90 1.1 christos #
91 1.1 christos # 15-Jul-2005 Brendan Gregg Created this.
92 1.1 christos # 20-Apr-2006 " " Last update.
93 1.1 christos #
94 1.1 christos
95 1.1 christos
96 1.1 christos ##############################
97 1.1 christos # --- Process Arguments ---
98 1.1 christos #
99 1.1 christos
100 1.1 christos ### default variables
101 1.1 christos opt_device=0; opt_file=0; opt_mount=0; opt_clear=1; opt_proj=0; opt_zone=0
102 1.1 christos opt_percent=0; opt_def=1; opt_bytes=1; filter=0; device=.; filename=.; mount=.
103 1.1 christos opt_top=0; opt_elapsed=0; opt_dtime=0; interval=5; count=-1; top=0
104 1.1 christos
105 1.1 christos ### process options
106 1.1 christos while getopts CDd:f:hjm:oPt:Z name
107 1.1 christos do
108 1.1 christos case $name in
109 1.1 christos C) opt_clear=0 ;;
110 1.1 christos D) opt_elapsed=1; opt_bytes=0 ;;
111 1.1 christos d) opt_device=1; device=$OPTARG ;;
112 1.1 christos f) opt_file=1; filename=$OPTARG ;;
113 1.1 christos j) opt_proj=1; opt_def=0 ;;
114 1.1 christos m) opt_mount=1; mount=$OPTARG ;;
115 1.1 christos o) opt_dtime=1; opt_bytes=0 ;;
116 1.1 christos P) opt_percent=1; opt_dtime=1; opt_bytes=0 ;;
117 1.1 christos t) opt_top=1; top=$OPTARG ;;
118 1.1 christos Z) opt_zone=1; opt_def=0 ;;
119 1.1 christos h|?) cat <<-END >&2
120 1.1 christos USAGE: iotop [-C] [-D|-o|-P] [-j|-Z] [-d device] [-f filename]
121 1.1 christos [-m mount_point] [-t top] [interval [count]]
122 1.1 christos
123 1.1 christos -C # don't clear the screen
124 1.1 christos -D # print delta times, elapsed, us
125 1.1 christos -j # print project ID
126 1.1 christos -o # print disk delta times, us
127 1.1 christos -P # print %I/O (disk delta times)
128 1.1 christos -Z # print zone ID
129 1.1 christos -d device # instance name to snoop
130 1.1 christos -f filename # snoop this file only
131 1.1 christos -m mount_point # this FS only
132 1.1 christos -t top # print top number only
133 1.1 christos eg,
134 1.1 christos iotop # default output, 5 second samples
135 1.1 christos iotop 1 # 1 second samples
136 1.1 christos iotop -P # print %I/O (time based)
137 1.1 christos iotop -m / # snoop events on filesystem / only
138 1.1 christos iotop -t 20 # print top 20 lines only
139 1.1 christos iotop -C 5 12 # print 12 x 5 second samples
140 1.1 christos END
141 1.1 christos exit 1
142 1.1 christos esac
143 1.1 christos done
144 1.1 christos
145 1.1 christos shift $(( $OPTIND - 1 ))
146 1.1 christos
147 1.1 christos ### option logic
148 1.1 christos if [[ "$1" > 0 ]]; then
149 1.1 christos interval=$1; shift
150 1.1 christos fi
151 1.1 christos if [[ "$1" > 0 ]]; then
152 1.1 christos count=$1; shift
153 1.1 christos fi
154 1.1 christos if (( opt_proj && opt_zone )); then
155 1.1 christos opt_proj=0
156 1.1 christos fi
157 1.1 christos if (( opt_elapsed && opt_dtime )); then
158 1.1 christos opt_elapsed=0
159 1.1 christos fi
160 1.1 christos if (( opt_device || opt_mount || opt_file )); then
161 1.1 christos filter=1
162 1.1 christos fi
163 1.1 christos if (( opt_clear )); then
164 1.1 christos clearstr=`clear`
165 1.1 christos else
166 1.1 christos clearstr=.
167 1.1 christos fi
168 1.1 christos
169 1.1 christos
170 1.1 christos
171 1.1 christos #################################
172 1.1 christos # --- Main Program, DTrace ---
173 1.1 christos #
174 1.1 christos /usr/sbin/dtrace -n '
175 1.1 christos /*
176 1.1 christos * Command line arguments
177 1.1 christos */
178 1.1 christos inline int OPT_def = '$opt_def';
179 1.1 christos inline int OPT_proj = '$opt_proj';
180 1.1 christos inline int OPT_zone = '$opt_zone';
181 1.1 christos inline int OPT_clear = '$opt_clear';
182 1.1 christos inline int OPT_bytes = '$opt_bytes';
183 1.1 christos inline int OPT_elapsed = '$opt_elapsed';
184 1.1 christos inline int OPT_dtime = '$opt_dtime';
185 1.1 christos inline int OPT_percent = '$opt_percent';
186 1.1 christos inline int OPT_device = '$opt_device';
187 1.1 christos inline int OPT_mount = '$opt_mount';
188 1.1 christos inline int OPT_file = '$opt_file';
189 1.1 christos inline int OPT_top = '$opt_top';
190 1.1 christos inline int INTERVAL = '$interval';
191 1.1 christos inline int COUNTER = '$count';
192 1.1 christos inline int FILTER = '$filter';
193 1.1 christos inline int TOP = '$top';
194 1.1 christos inline string DEVICE = "'$device'";
195 1.1 christos inline string FILENAME = "'$filename'";
196 1.1 christos inline string MOUNT = "'$mount'";
197 1.1 christos inline string CLEAR = "'$clearstr'";
198 1.1 christos
199 1.1 christos #pragma D option quiet
200 1.1 christos
201 1.1 christos /* boost the following if you get "dynamic variable drops" */
202 1.1 christos #pragma D option dynvarsize=8m
203 1.1 christos
204 1.1 christos /*
205 1.1 christos * Print header
206 1.1 christos */
207 1.1 christos dtrace:::BEGIN
208 1.1 christos {
209 1.1 christos last_event[""] = 0;
210 1.1 christos
211 1.1 christos /* starting values */
212 1.1 christos counts = COUNTER;
213 1.1 christos secs = INTERVAL;
214 1.1 christos disk_r = 0;
215 1.1 christos disk_w = 0;
216 1.1 christos
217 1.1 christos printf("Tracing... Please wait.\n");
218 1.1 christos }
219 1.1 christos
220 1.1 christos /*
221 1.1 christos * Check event is being traced
222 1.1 christos */
223 1.1 christos io:genunix::start,
224 1.1 christos io:genunix::done
225 1.1 christos {
226 1.1 christos /* default is to trace unless filtering, */
227 1.1 christos this->ok = FILTER ? 0 : 1;
228 1.1 christos
229 1.1 christos /* check each filter, */
230 1.1 christos (OPT_device == 1 && DEVICE == args[1]->dev_statname)? this->ok = 1 : 1;
231 1.1 christos (OPT_file == 1 && FILENAME == args[2]->fi_pathname) ? this->ok = 1 : 1;
232 1.1 christos (OPT_mount == 1 && MOUNT == args[2]->fi_mount) ? this->ok = 1 : 1;
233 1.1 christos }
234 1.1 christos
235 1.1 christos /*
236 1.1 christos * Reset last_event for disk idle -> start
237 1.1 christos * this prevents idle time being counted as disk time.
238 1.1 christos */
239 1.1 christos io:genunix::start
240 1.1 christos /! pending[args[1]->dev_statname]/
241 1.1 christos {
242 1.1 christos /* save last disk event */
243 1.1 christos last_event[args[1]->dev_statname] = timestamp;
244 1.1 christos }
245 1.1 christos
246 1.1 christos /*
247 1.1 christos * Store entry details
248 1.1 christos */
249 1.1 christos io:genunix::start
250 1.1 christos /this->ok/
251 1.1 christos {
252 1.1 christos /* these are used as a unique disk event key, */
253 1.1 christos this->dev = args[0]->b_edev;
254 1.1 christos this->blk = args[0]->b_blkno;
255 1.1 christos
256 1.1 christos /* save disk event details, */
257 1.1 christos start_uid[this->dev, this->blk] = uid;
258 1.1 christos start_pid[this->dev, this->blk] = pid;
259 1.1 christos start_ppid[this->dev, this->blk] = ppid;
260 1.1 christos start_comm[this->dev, this->blk] = execname;
261 1.1 christos start_time[this->dev, this->blk] = timestamp;
262 1.1 christos start_proj[this->dev, this->blk] = curpsinfo->pr_projid;
263 1.1 christos start_zone[this->dev, this->blk] = curpsinfo->pr_zoneid;
264 1.1 christos start_rw[this->dev, this->blk] = args[0]->b_flags & B_READ ? "R" : "W";
265 1.1 christos disk_r += args[0]->b_flags & B_READ ? args[0]->b_bcount : 0;
266 1.1 christos disk_w += args[0]->b_flags & B_READ ? 0 : args[0]->b_bcount;
267 1.1 christos
268 1.1 christos /* increase disk event pending count */
269 1.1 christos pending[args[1]->dev_statname]++;
270 1.1 christos }
271 1.1 christos
272 1.1 christos /*
273 1.1 christos * Process and Print completion
274 1.1 christos */
275 1.1 christos io:genunix::done
276 1.1 christos /this->ok/
277 1.1 christos {
278 1.1 christos /* decrease disk event pending count */
279 1.1 christos pending[args[1]->dev_statname]--;
280 1.1 christos
281 1.1 christos /*
282 1.1 christos * Process details
283 1.1 christos */
284 1.1 christos
285 1.1 christos /* fetch entry values */
286 1.1 christos this->dev = args[0]->b_edev;
287 1.1 christos this->blk = args[0]->b_blkno;
288 1.1 christos this->suid = start_uid[this->dev, this->blk];
289 1.1 christos this->spid = start_pid[this->dev, this->blk];
290 1.1 christos this->sppid = start_ppid[this->dev, this->blk];
291 1.1 christos this->sproj = start_proj[this->dev, this->blk];
292 1.1 christos this->szone = start_zone[this->dev, this->blk];
293 1.1 christos self->scomm = start_comm[this->dev, this->blk];
294 1.1 christos this->stime = start_time[this->dev, this->blk];
295 1.1 christos this->etime = timestamp; /* endtime */
296 1.1 christos this->elapsed = this->etime - this->stime;
297 1.1 christos self->rw = start_rw[this->dev, this->blk];
298 1.1 christos this->dtime = last_event[args[1]->dev_statname] == 0 ? 0 :
299 1.1 christos timestamp - last_event[args[1]->dev_statname];
300 1.1 christos
301 1.1 christos /* memory cleanup */
302 1.1 christos start_uid[this->dev, this->blk] = 0;
303 1.1 christos start_pid[this->dev, this->blk] = 0;
304 1.1 christos start_ppid[this->dev, this->blk] = 0;
305 1.1 christos start_time[this->dev, this->blk] = 0;
306 1.1 christos start_comm[this->dev, this->blk] = 0;
307 1.1 christos start_zone[this->dev, this->blk] = 0;
308 1.1 christos start_proj[this->dev, this->blk] = 0;
309 1.1 christos start_rw[this->dev, this->blk] = 0;
310 1.1 christos
311 1.1 christos /*
312 1.1 christos * Choose statistic to track
313 1.1 christos */
314 1.1 christos OPT_bytes ? this->value = args[0]->b_bcount : 1;
315 1.1 christos OPT_elapsed ? this->value = this->elapsed / 1000 : 1;
316 1.1 christos OPT_dtime ? this->value = this->dtime / 1000 : 1;
317 1.1 christos
318 1.1 christos /*
319 1.1 christos * Save details
320 1.1 christos */
321 1.1 christos OPT_def ? @out[this->suid, this->spid, this->sppid, self->scomm,
322 1.1 christos args[1]->dev_statname, args[1]->dev_major, args[1]->dev_minor,
323 1.1 christos self->rw] = sum(this->value) : 1;
324 1.1 christos OPT_proj ? @out[this->sproj, this->spid, this->sppid, self->scomm,
325 1.1 christos args[1]->dev_statname, args[1]->dev_major, args[1]->dev_minor,
326 1.1 christos self->rw] = sum(this->value) : 1;
327 1.1 christos OPT_zone ? @out[this->szone, this->spid, this->sppid, self->scomm,
328 1.1 christos args[1]->dev_statname, args[1]->dev_major, args[1]->dev_minor,
329 1.1 christos self->rw] = sum(this->value) : 1;
330 1.1 christos
331 1.1 christos /* save last disk event */
332 1.1 christos last_event[args[1]->dev_statname] = timestamp;
333 1.1 christos
334 1.1 christos self->scomm = 0;
335 1.1 christos self->rw = 0;
336 1.1 christos }
337 1.1 christos
338 1.1 christos /*
339 1.1 christos * Prevent pending from underflowing
340 1.1 christos * this can happen if this program is started during disk events.
341 1.1 christos */
342 1.1 christos io:genunix::done
343 1.1 christos /pending[args[1]->dev_statname] < 0/
344 1.1 christos {
345 1.1 christos pending[args[1]->dev_statname] = 0;
346 1.1 christos }
347 1.1 christos
348 1.1 christos /*
349 1.1 christos * Timer
350 1.1 christos */
351 1.1 christos profile:::tick-1sec
352 1.1 christos {
353 1.1 christos secs--;
354 1.1 christos }
355 1.1 christos
356 1.1 christos /*
357 1.1 christos * Print Report
358 1.1 christos */
359 1.1 christos profile:::tick-1sec
360 1.1 christos /secs == 0/
361 1.1 christos {
362 1.1 christos /* fetch 1 min load average */
363 1.1 christos this->load1a = `hp_avenrun[0] / 65536;
364 1.1 christos this->load1b = ((`hp_avenrun[0] % 65536) * 100) / 65536;
365 1.1 christos
366 1.1 christos /* convert counters to Kbytes */
367 1.1 christos disk_r /= 1024;
368 1.1 christos disk_w /= 1024;
369 1.1 christos
370 1.1 christos /* print status */
371 1.1 christos OPT_clear ? printf("%s", CLEAR) : 1;
372 1.1 christos printf("%Y, load: %d.%02d, disk_r: %6d KB, disk_w: %6d KB\n\n",
373 1.1 christos walltimestamp, this->load1a, this->load1b, disk_r, disk_w);
374 1.1 christos
375 1.1 christos /* print headers */
376 1.1 christos OPT_def ? printf(" UID ") : 1;
377 1.1 christos OPT_proj ? printf(" PROJ ") : 1;
378 1.1 christos OPT_zone ? printf(" ZONE ") : 1;
379 1.1 christos printf("%6s %6s %-16s %-7s %3s %3s %1s",
380 1.1 christos "PID", "PPID", "CMD", "DEVICE", "MAJ", "MIN", "D");
381 1.1 christos OPT_bytes ? printf(" %16s\n", "BYTES") : 1;
382 1.1 christos OPT_elapsed ? printf(" %16s\n", "ELAPSED") : 1;
383 1.1 christos OPT_dtime && ! OPT_percent ? printf(" %16s\n", "DISKTIME") : 1;
384 1.1 christos OPT_dtime && OPT_percent ? printf(" %6s\n", "%I/O") : 1;
385 1.1 christos
386 1.1 christos /* truncate to top lines if needed */
387 1.1 christos OPT_top ? trunc(@out, TOP) : 1;
388 1.1 christos
389 1.1 christos /* normalise to percentage if needed */
390 1.1 christos OPT_percent ? normalize(@out, INTERVAL * 10000) : 1;
391 1.1 christos
392 1.1 christos /* print data */
393 1.1 christos ! OPT_percent ?
394 1.1 christos printa("%5d %6d %6d %-16s %-7s %3d %3d %1s %16@d\n", @out) :
395 1.1 christos printa("%5d %6d %6d %-16s %-7s %3d %3d %1s %6@d\n", @out);
396 1.1 christos printf("\n");
397 1.1 christos
398 1.1 christos /* clear data */
399 1.1 christos trunc(@out);
400 1.1 christos disk_r = 0;
401 1.1 christos disk_w = 0;
402 1.1 christos secs = INTERVAL;
403 1.1 christos counts--;
404 1.1 christos }
405 1.1 christos
406 1.1 christos /*
407 1.1 christos * End of program
408 1.1 christos */
409 1.1 christos profile:::tick-1sec
410 1.1 christos /counts == 0/
411 1.1 christos {
412 1.1 christos exit(0);
413 1.1 christos }
414 1.1 christos
415 1.1 christos /*
416 1.1 christos * Cleanup for Ctrl-C
417 1.1 christos */
418 1.1 christos dtrace:::END
419 1.1 christos {
420 1.1 christos trunc(@out);
421 1.1 christos }
422 1.1 christos '
423