1235368Sgnn#!/usr/bin/ksh
2235368Sgnn#
3235368Sgnn# dexplorer - DTrace system explorer, runs a collection of scripts.
4235368Sgnn#             Written using DTrace (Solaris 10 3/05).
5235368Sgnn#
6235368Sgnn# This program automatically runs a collection of DTrace scripts to examine
7235368Sgnn# many areas of the system, and places the output in a meaningful directory
8235368Sgnn# structure that is tar'd and gzip'd.
9235368Sgnn#
10235368Sgnn# $Id: dexplorer 3 2007-08-01 10:50:08Z brendan $
11235368Sgnn#
12235368Sgnn# USAGE:	dexplorer [-yDT] [-d outputdir] [-i interval]
13235368Sgnn#
14235368Sgnn#                  -q              # quiet mode
15235368Sgnn#                  -y              # "yes", don't prompt for confirmation
16235368Sgnn#                  -D              # don't delete output dir
17235368Sgnn#                  -T              # don't create output tar.gz
18235368Sgnn#                  -d outputdir    # output directory
19235368Sgnn#                  -i interval     # interval for each sample
20235368Sgnn#    eg,
21235368Sgnn#               dexplorer          # default is 5 second samples
22235368Sgnn#               dexplorer -y -i30  # no prompting, with 30 second samples
23235368Sgnn#
24235368Sgnn# SEE ALSO:	DTraceToolkit
25235368Sgnn#
26235368Sgnn# THANKS: David Visser, et all. for the idea and encouragement.
27235368Sgnn#
28235368Sgnn# COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
29235368Sgnn#
30235368Sgnn# CDDL HEADER START
31235368Sgnn#
32235368Sgnn#  The contents of this file are subject to the terms of the
33235368Sgnn#  Common Development and Distribution License, Version 1.0 only
34235368Sgnn#  (the "License").  You may not use this file except in compliance
35235368Sgnn#  with the License.
36235368Sgnn#
37235368Sgnn#  You can obtain a copy of the license at Docs/cddl1.txt
38235368Sgnn#  or http://www.opensolaris.org/os/licensing.
39235368Sgnn#  See the License for the specific language governing permissions
40235368Sgnn#  and limitations under the License.
41235368Sgnn#
42235368Sgnn# CDDL HEADER END
43235368Sgnn#
44235368Sgnn# CODE:
45235368Sgnn#
46235368Sgnn#  This is currently a monolithic script, and while it contains only
47235368Sgnn#  a few dozen straigftforward DTrace scripts I think it's desirable to
48235368Sgnn#  keep it that way. The scripts themselves have designed to be very
49235368Sgnn#  generic (eg, switching on all sdt:::), and are aggregations to keep a 
50235368Sgnn#  limit on the size of the output.
51235368Sgnn#
52235368Sgnn# Author: Brendan Gregg  [Sydney, Australia]
53235368Sgnn#
54235368Sgnn# 23-Jun-2005	Brendan Gregg	Created this.
55235368Sgnn# 28-Jun-2005	   "      "	Last update.
56235368Sgnn
57235368Sgnn#
58235368Sgnn#  Default variables
59235368Sgnn#
60235368Sgnninterval=5				# time of each sample
61235368Sgnnverbose=1				# print screen output
62235368Sgnnprompt=1				# prompt before run
63235368Sgnntar=1					# create tar file
64235368Sgnndelete=1				# delete output dirs
65235368Sgnndtrace=/usr/sbin/dtrace			# path to dtrace
66235368Sgnnroot=.					# default output dir
67235368SgnnPATH=/usr/bin:/usr/sbin			# safe path
68235368Sgnndir=de_`uname -n`_`date +%Y%m%d%H%M`	# OUTPUT FILENAME
69235368Sgnnsamples=20				# max number of tests
70235368Sgnncurrent=0				# current sample
71235368Sgnn
72235368Sgnn#
73235368Sgnn#  Process options
74235368Sgnn#
75235368Sgnnwhile getopts d:hi:qyDT name
76235368Sgnndo
77235368Sgnn	case $name in
78235368Sgnn	d)      root=$OPTARG ;;
79235368Sgnn	i)      interval=$OPTARG ;;
80235368Sgnn	q)      verbose=0 ;;
81235368Sgnn	y)      prompt=0 ;;
82235368Sgnn	D)      delete=0 ;;
83235368Sgnn	T)      tar=0 ;;
84235368Sgnn	h|?)    cat <<-END >&2
85235368Sgnn		USAGE: dexplorer [-qyDT] [-d outputdir] [-i interval]
86235368Sgnn		 
87235368Sgnn		        -q               # quiet mode
88235368Sgnn		        -y               # "yes", don't prompt for confirmation
89235368Sgnn		        -D               # don't delete output dir
90235368Sgnn		        -T               # don't create output tar.gz
91235368Sgnn		        -d outputdir     # output directory
92235368Sgnn		        -i interval      # interval for each sample
93235368Sgnn		   eg,
94235368Sgnn		       dexplorer         # default is 5 second samples
95235368Sgnn		       dexplorer -y -i30 # no prompting, with 30 second samples
96235368Sgnn		END
97235368Sgnn		exit 1
98235368Sgnn	esac
99235368Sgnndone
100235368Sgnnshift $(( OPTIND - 1 ))
101235368Sgnn
102235368Sgnn#
103235368Sgnn#  Confirm path
104235368Sgnn#
105235368Sgnnif [[ "$prompt" == "1" ]] ; then
106235368Sgnn	if [[ "$root" == "." ]]; then
107235368Sgnn		print "Output dir will be the current dir ($PWD)."
108235368Sgnn	else
109235368Sgnn		print "Output dir will be $root"
110235368Sgnn	fi
111235368Sgnn	print -n "Hit enter for yes, or type path: "
112235368Sgnn	read ans junk
113235368Sgnn	if [[ "$ans" == [yY] || "$ans" == [yY]es ]]; then
114235368Sgnn		print "WARNING: I didn't ask for \"$ans\"!"
115235368Sgnn		print "\tI was asking for the path or just enter."
116235368Sgnn		print "\tignoring \"$ans\"..."
117235368Sgnn	fi
118235368Sgnn	if [[ "$ans" != "" ]]; then
119235368Sgnn		root=$ans
120235368Sgnn		print "Output is now $root."
121235368Sgnn	fi
122235368Sgnnfi
123235368Sgnn
124235368Sgnn#
125235368Sgnn#  Sanity checks
126235368Sgnn#
127235368Sgnnif [[ "$interval" == *[a-zA-Z]* ]]; then
128235368Sgnn	print "ERROR2: Invalid interval $interval.\n"
129235368Sgnn	print "Please use a number of seconds."
130235368Sgnn	exit 2
131235368Sgnnfi
132235368Sgnnif (( ${#interval} < 1 )); then
133235368Sgnn	print "ERROR3: Length of interval $interval too short.\n"
134235368Sgnn	print "Minimum 1 second."
135235368Sgnn	exit 3
136235368Sgnnfi
137235368Sgnnif [[ ! -d "$root" ]]; then
138235368Sgnn	print "ERROR4: Output directory \"$root\" does not exist.\n"
139235368Sgnn	print "Perhaps try a mkdir first?"
140235368Sgnn	print "or use an existing dir, eg \"/tmp\""
141235368Sgnn	exit 4
142235368Sgnnfi
143235368Sgnnif [[ ! -w "$root" ]]; then
144235368Sgnn	print "ERROR5: Can't write to output directory \"$root\".\n"
145235368Sgnn	print "Are you logged in as root?"
146235368Sgnn	print "Perhaps try another directory, eg \"/tmp\""
147235368Sgnn	exit 5
148235368Sgnnfi
149235368Sgnnif [[ `$dtrace -b1k -qn 'BEGIN { trace(pid); exit(0); }'` == "" ]]; then
150235368Sgnn	print "ERROR6: Unable to run dtrace!\n"
151235368Sgnn	print "Perhaps this is a permission problem? Try running as root."
152235368Sgnn	exit 6
153235368Sgnnfi
154235368Sgnn
155235368Sgnn# calculate total time
156235368Sgnn(( total = interval * samples ))
157235368Sgnnif (( total > 180 )); then
158235368Sgnn	(( total = total / 60 ))
159235368Sgnn	total="$total minutes"
160235368Sgnnelse
161235368Sgnn	total="$total seconds"
162235368Sgnnfi
163235368Sgnn
164235368Sgnn#
165235368Sgnn#  Common Functions
166235368Sgnn#
167235368Sgnnfunction decho {
168235368Sgnn	if (( verbose )); then print "$*"; fi
169235368Sgnn}
170235368Sgnnclean="sed /^\$/d"
171235368Sgnnheader='dtrace:::BEGIN {
172235368Sgnn		printf("%Y, ", walltimestamp);
173235368Sgnn		printf("%s %s %s %s %s, ", `utsname.sysname, `utsname.nodename,
174235368Sgnn		    `utsname.release, `utsname.version, `utsname.machine);
175235368Sgnn		printf("%d secs\n",'$interval');
176235368Sgnn	}
177235368Sgnn	profile:::tick-'$interval'sec { exit(0); }
178235368Sgnn	'
179235368Sgnnfunction dstatus {
180235368Sgnn	if (( verbose )); then 
181235368Sgnn		(( percent = current * 100 / samples ))
182235368Sgnn		printf "%3d%% $*\n" $percent
183235368Sgnn		(( current = current + 1 ))
184235368Sgnn	fi
185235368Sgnn}
186235368Sgnn
187235368Sgnn########################################
188235368Sgnn#  START                               #
189235368Sgnn########################################
190235368Sgnn
191235368Sgnn#
192235368Sgnn#  Make dirs
193235368Sgnn#
194235368Sgnnerr=0
195235368Sgnncd $root
196235368Sgnn(( err = err + $? ))
197235368Sgnnmkdir $dir
198235368Sgnn(( err = err + $? ))
199235368Sgnncd $dir
200235368Sgnn(( err = err + $? ))
201235368Sgnnbase1=${PWD##*/}
202235368Sgnnbase2=${dir##*/}
203235368Sgnnif [[ "$base1" != "$base2" || "$err" != "0" ]]; then
204235368Sgnn	print "ERROR7: tried to mkdir $dir from $root, but something failed.\n"
205235368Sgnn	print "Check directories before rerunning."
206235368Sgnn	exit 7
207235368Sgnnfi
208235368Sgnnmkdir Cpu
209235368Sgnnmkdir Disk
210235368Sgnnmkdir Mem
211235368Sgnnmkdir Net
212235368Sgnnmkdir Proc
213235368Sgnnmkdir Info
214235368Sgnn
215235368Sgnn#
216235368Sgnn#  Create Log
217235368Sgnn#
218235368Sgnndecho "Starting dexplorer ver 0.76."
219235368Sgnndecho "Sample interval is $interval seconds. Total run is > $total."
220235368Sgnn( print "dexplorer ver 0.76\n------------------"
221235368Sgnnprint -n "System: "
222235368Sgnnuname -a
223235368Sgnnprint -n "Start:  "
224235368Sgnndate ) > log
225235368Sgnn
226235368Sgnn#
227235368Sgnn#  Capture Standard Info
228235368Sgnn#
229235368Sgnnargs='pid,ppid,uid,gid,projid,zoneid,pset,pri,nice,'
230235368Sgnnargs=$args'class,vsz,rss,time,pcpu,pmem,args'
231235368Sgnnuname -a > Info/uname-a		# System
232235368Sgnnpsrinfo -v > Info/psrinfo-v	# CPU
233235368Sgnnprtconf > Info/prtconf		# Memory (+ devices)
234235368Sgnndf -k > Info/df-k		# Disk
235235368Sgnnifconfig -a > Info/ifconfig-a	# Network
236235368Sgnnps -eo $args > Info/ps-o	# Processes
237235368Sgnnuptime > Info/uptime		# Load
238235368Sgnn
239235368Sgnn#
240235368Sgnn#  Cpu Tests, DTrace
241235368Sgnn#
242235368Sgnn
243235368Sgnndstatus "Interrupts by CPU..."
244235368Sgnn$dtrace -qn "$header"'
245235368Sgnn	sdt:::interrupt-start { @num[cpu] = count(); }
246235368Sgnn	dtrace:::END
247235368Sgnn	{ 
248235368Sgnn		printf("%-16s %16s\n", "CPU", "INTERRUPTS");
249235368Sgnn		printa("%-16d %@16d\n", @num);
250235368Sgnn	}
251235368Sgnn' | $clean > Cpu/interrupt_by_cpu
252235368Sgnn
253235368Sgnndstatus "Interrupt times..."
254235368Sgnn$dtrace -qn "$header"'
255235368Sgnn	sdt:::interrupt-start { self->ts = vtimestamp; }
256235368Sgnn	sdt:::interrupt-complete
257235368Sgnn	/self->ts && arg0 != 0/
258235368Sgnn	{
259235368Sgnn		this->devi = (struct dev_info *)arg0;
260235368Sgnn		self->name = this->devi != 0 ?
261235368Sgnn		    stringof(`devnamesp[this->devi->devi_major].dn_name) : "?";
262235368Sgnn		this->inst = this->devi != 0 ? this->devi->devi_instance : 0;
263235368Sgnn		@num[self->name, this->inst] = sum(vtimestamp - self->ts);
264235368Sgnn		self->name = 0;
265235368Sgnn	}
266235368Sgnn	sdt:::interrupt-complete { self->ts = 0; }
267235368Sgnn	dtrace:::END
268235368Sgnn	{ 
269235368Sgnn		printf("%11s    %16s\n", "DEVICE", "TIME (ns)");
270235368Sgnn		printa("%10s%-3d %@16d\n", @num);
271235368Sgnn	}
272235368Sgnn' | $clean > Cpu/interrupt_time
273235368Sgnn
274235368Sgnndstatus "Dispatcher queue length by CPU..."
275235368Sgnn$dtrace -qn "$header"'
276235368Sgnn	profile:::profile-1000
277235368Sgnn	{
278235368Sgnn		this->num = curthread->t_cpu->cpu_disp->disp_nrunnable;
279235368Sgnn		@length[cpu] = lquantize(this->num, 0, 100, 1);
280235368Sgnn	}
281235368Sgnn	dtrace:::END { printa(" CPU %d%@d\n", @length); }
282235368Sgnn' | $clean > Cpu/dispqlen_by_cpu
283235368Sgnn
284235368Sgnndstatus "Sdt counts..."
285235368Sgnn$dtrace -qn "$header"'
286235368Sgnn	sdt:::{ @num[probefunc, probename] = count(); }
287235368Sgnn	dtrace:::END
288235368Sgnn	{ 
289235368Sgnn		printf("%-32s %-32s %10s\n", "FUNC", "NAME", "COUNT");
290235368Sgnn		printa("%-32s %-32s %@10d\n", @num);
291235368Sgnn	}
292235368Sgnn' | $clean > Cpu/sdt_count
293235368Sgnn
294235368Sgnn#
295235368Sgnn#  Disk Tests, DTrace
296235368Sgnn#
297235368Sgnn
298235368Sgnndstatus "Pages paged in by process..."
299235368Sgnn$dtrace -qn "$header"'
300235368Sgnn	vminfo:::pgpgin { @pg[pid, execname] = sum(arg0); }
301235368Sgnn	dtrace:::END
302235368Sgnn	{ 
303235368Sgnn		printf("%6s %-16s %16s\n", "PID", "CMD", "PAGES");
304235368Sgnn		printa("%6d %-16s %@16d\n", @pg);
305235368Sgnn	}
306235368Sgnn' | $clean > Disk/pgpgin_by_process
307235368Sgnn
308235368Sgnndstatus "Files opened successfully count..."
309235368Sgnn$dtrace -qn "$header"'
310235368Sgnn	syscall::open*:entry { self->file = copyinstr(arg0); self->ok = 1; }
311235368Sgnn	syscall::open*:return /self->ok && arg0 != -1/ 
312235368Sgnn	{ 
313235368Sgnn		@num[self->file] = count();
314235368Sgnn	}
315235368Sgnn	syscall::open*:return /self->ok/ { self->file = 0; self->ok = 0; }
316235368Sgnn	dtrace:::END
317235368Sgnn	{ 
318235368Sgnn		printf("%-64s %8s\n", "FILE", "COUNT");
319235368Sgnn		printa("%-64s %@8d\n", @num);
320235368Sgnn	}
321235368Sgnn' | $clean > Disk/fileopen_count
322235368Sgnn
323235368Sgnndstatus "Disk I/O size distribution by process..."
324235368Sgnn$dtrace -qn "$header"'
325235368Sgnn	io:::start { @size[pid, execname] = quantize(args[0]->b_bcount); }
326235368Sgnn' | $clean > Disk/sizedist_by_process
327235368Sgnn
328235368Sgnn#
329235368Sgnn#  Mem Tests, DTrace
330235368Sgnn#
331235368Sgnn
332235368Sgnndstatus "Minor faults by process..."
333235368Sgnn$dtrace -qn "$header"'
334235368Sgnn	vminfo:::as_fault { @mem[pid, execname] = sum(arg0); }
335235368Sgnn	dtrace:::END
336235368Sgnn	{ 
337235368Sgnn		printf("%6s %-16s %16s\n", "PID", "CMD", "MINFAULTS");
338235368Sgnn		printa("%6d %-16s %@16d\n", @mem);
339235368Sgnn	}
340235368Sgnn' | $clean > Mem/minf_by_process
341235368Sgnn
342235368Sgnn
343235368Sgnndstatus "Vminfo data by process..."
344235368Sgnn$dtrace -qn "$header"'
345235368Sgnn	vminfo::: { @data[pid, execname, probename] = sum(arg0); }
346235368Sgnn	dtrace:::END
347235368Sgnn	{ 
348235368Sgnn		printf("%6s %-16s %-16s %16s\n",
349235368Sgnn		    "PID", "CMD", "STATISTIC", "VALUE");
350235368Sgnn		printa("%6d %-16s %-16s %@16d\n", @data);
351235368Sgnn	}
352235368Sgnn' | $clean > Mem/vminfo_by_process
353235368Sgnn
354235368Sgnn#
355235368Sgnn#  Net Tests, DTrace
356235368Sgnn#
357235368Sgnn
358235368Sgnndstatus "Mib data by mib statistic..."
359235368Sgnn$dtrace -qn "$header"'
360235368Sgnn	mib::: { @data[probename] = sum(arg0); }
361235368Sgnn	dtrace:::END
362235368Sgnn	{ 
363235368Sgnn		printf("%-32s %16s\n", "STATISTIC", "VALUE");
364235368Sgnn		printa("%-32s %@16d\n", @data);
365235368Sgnn	}
366235368Sgnn' | $clean > Net/mib_data
367235368Sgnn
368235368Sgnndstatus "TCP write bytes by process..."
369235368Sgnn$dtrace -qn "$header"'
370235368Sgnn	fbt:ip:tcp_output:entry
371235368Sgnn	{
372235368Sgnn		this->size = msgdsize(args[1]);
373235368Sgnn		@size[pid, execname] = sum(this->size);
374235368Sgnn	}
375235368Sgnn	dtrace:::END
376235368Sgnn	{ 
377235368Sgnn		printf("%6s %-16s %12s\n", "PID", "CMD", "BYTES");
378235368Sgnn		printa("%6d %-16s %@12d\n", @size);
379235368Sgnn	}
380235368Sgnn' | $clean > Net/tcpw_by_process
381235368Sgnn
382235368Sgnn#
383235368Sgnn#  Proc Tests, DTrace
384235368Sgnn#
385235368Sgnn
386235368Sgnndstatus "Sample process @ 1000 Hz..."
387235368Sgnn$dtrace -qn "$header"'
388235368Sgnn	profile:::profile-1000
389235368Sgnn	{
390235368Sgnn		@num[pid, curpsinfo->pr_psargs] = count();
391235368Sgnn	}
392235368Sgnn	dtrace:::END
393235368Sgnn	{ 
394235368Sgnn		printf("%6s %12s %s\n", "PID", "SAMPLES", "ARGS");
395235368Sgnn		printa("%6d %@12d %S\n", @num);
396235368Sgnn	}
397235368Sgnn' | $clean > Proc/sample_process
398235368Sgnn
399235368Sgnndstatus "Syscall count by process..."
400235368Sgnn$dtrace -qn "$header"'
401235368Sgnn	syscall:::entry { @num[pid, execname, probefunc] = count(); }
402235368Sgnn	dtrace:::END
403235368Sgnn	{ 
404235368Sgnn		printf("%6s %-24s %-24s %8s\n",
405235368Sgnn		    "PID", "CMD", "SYSCALL", "COUNT");
406235368Sgnn		printa("%6d %-24s %-24s %@8d\n", @num);
407235368Sgnn	}
408235368Sgnn' | $clean > Proc/syscall_by_process
409235368Sgnn
410235368Sgnndstatus "Syscall count by syscall..."
411235368Sgnn$dtrace -qn "$header"'
412235368Sgnn	syscall:::entry { @num[probefunc] = count(); }
413235368Sgnn	dtrace:::END
414235368Sgnn	{ 
415235368Sgnn		printf("%-32s %16s\n", "SYSCALL", "COUNT");
416235368Sgnn		printa("%-32s %@16d\n", @num);
417235368Sgnn	}
418235368Sgnn' | $clean > Proc/syscall_count
419235368Sgnn
420235368Sgnndstatus "Read bytes by process..."
421235368Sgnn$dtrace -qn "$header"'
422235368Sgnn	sysinfo:::readch { @bytes[pid, execname] = sum(arg0); }
423235368Sgnn	dtrace:::END
424235368Sgnn	{ 
425235368Sgnn		printf("%6s %-16s %16s\n", "PID", "CMD", "BYTES");
426235368Sgnn		printa("%6d %-16s %@16d\n", @bytes);
427235368Sgnn	}
428235368Sgnn' | $clean > Proc/readb_by_process
429235368Sgnn
430235368Sgnndstatus "Write bytes by process..."
431235368Sgnn$dtrace -qn "$header"'
432235368Sgnn	sysinfo:::writech { @bytes[pid, execname] = sum(arg0); }
433235368Sgnn	dtrace:::END
434235368Sgnn	{ 
435235368Sgnn		printf("%6s %-16s %16s\n", "PID", "CMD", "BYTES");
436235368Sgnn		printa("%6d %-16s %@16d\n", @bytes);
437235368Sgnn	}
438235368Sgnn' | $clean > Proc/writeb_by_process
439235368Sgnn
440235368Sgnndstatus "Sysinfo counts by process..."
441235368Sgnn$dtrace -qn "$header"'
442235368Sgnn	sysinfo::: { @num[pid, execname, probename] = sum(arg0); }
443235368Sgnn	dtrace:::END
444235368Sgnn	{ 
445235368Sgnn		printf("%6s %-16s %-16s %16s\n", 
446235368Sgnn		    "PID", "CMD", "STATISTIC", "COUNT");
447235368Sgnn		printa("%6d %-16s %-16s %@16d\n", @num);
448235368Sgnn	}
449235368Sgnn' | $clean > Proc/sysinfo_by_process
450235368Sgnn
451235368Sgnndstatus "New process counts with arguments..."
452235368Sgnn$dtrace -qn "$header"'
453235368Sgnn	proc:::exec-success
454235368Sgnn	{
455235368Sgnn		@num[pid, ppid, curpsinfo->pr_psargs] = count();
456235368Sgnn	}
457235368Sgnn	dtrace:::END
458235368Sgnn	{ 
459235368Sgnn		printf("%6s %6s %8s %s\n", "PID", "PPID", "COUNT", "ARGS");
460235368Sgnn		printa("%6d %6d %@8d %S\n", @num);
461235368Sgnn	}
462235368Sgnn' | $clean > Proc/newprocess_count
463235368Sgnn
464235368Sgnndstatus "Signal counts..."
465235368Sgnn$dtrace -qn "$header"'
466235368Sgnn	proc:::signal-send { 
467235368Sgnn		@num[execname,args[2],stringof(args[1]->pr_fname)] = count();
468235368Sgnn	}
469235368Sgnn	dtrace:::END
470235368Sgnn	{ 
471235368Sgnn		printf("%-16s %-8s %-16s %8s\n",
472235368Sgnn		    "FROM", "SIG", "TO", "COUNT");
473235368Sgnn		printa("%-16s %-8d %-16s %@8d\n", @num);
474235368Sgnn	}
475235368Sgnn' | $clean > Proc/signal_count
476235368Sgnn
477235368Sgnndstatus "Syscall error counts..."
478235368Sgnn$dtrace -qn "$header"'
479235368Sgnn	syscall:::return /(int)arg0 == -1/
480235368Sgnn	{
481235368Sgnn		@num[pid, execname, probefunc, errno] = count();
482235368Sgnn	}
483235368Sgnn	dtrace:::END
484235368Sgnn	{ 
485235368Sgnn		printf("%6s %-16s %-32s %-6s %8s\n",
486235368Sgnn		    "PID", "CMD", "SYSCALL", "ERRNO", "COUNT");
487235368Sgnn		printa("%6d %-16s %-32s %-6d %@8d\n", @num);
488235368Sgnn	}
489235368Sgnn' | $clean > Proc/syscall_errors
490235368Sgnn
491235368Sgnn
492235368Sgnn###########
493235368Sgnn#  Done
494235368Sgnn#
495235368Sgnn( print -n "End:    "
496235368Sgnndate ) >> log
497235368Sgnndecho "100% Done."
498235368Sgnnif (( tar )); then
499235368Sgnn	cd ..
500235368Sgnn	tar cf $dir.tar $dir
501235368Sgnn	gzip $dir.tar
502235368Sgnn	decho "File is $dir.tar.gz"
503235368Sgnnfi
504235368Sgnnif (( delete && tar )); then
505235368Sgnn	cd $dir
506235368Sgnn	# this could be all an "rm -r $dir", but since it will be run 
507235368Sgnn	# as root on production servers - lets be analy cautious,
508235368Sgnn	rm Cpu/interrupt_by_cpu
509235368Sgnn	rm Cpu/interrupt_time
510235368Sgnn	rm Cpu/dispqlen_by_cpu
511235368Sgnn	rm Cpu/sdt_count
512235368Sgnn	rm Disk/pgpgin_by_process
513235368Sgnn	rm Disk/fileopen_count
514235368Sgnn	rm Disk/sizedist_by_process
515235368Sgnn	rm Mem/minf_by_process
516235368Sgnn	rm Mem/vminfo_by_process
517235368Sgnn	rm Net/mib_data
518235368Sgnn	rm Net/tcpw_by_process
519235368Sgnn	rm Proc/sample_process
520235368Sgnn	rm Proc/syscall_by_process
521235368Sgnn	rm Proc/syscall_count
522235368Sgnn	rm Proc/readb_by_process
523235368Sgnn	rm Proc/writeb_by_process
524235368Sgnn	rm Proc/sysinfo_by_process
525235368Sgnn	rm Proc/newprocess_count
526235368Sgnn	rm Proc/signal_count
527235368Sgnn	rm Proc/syscall_errors
528235368Sgnn	rmdir Cpu
529235368Sgnn	rmdir Disk
530235368Sgnn	rmdir Mem
531235368Sgnn	rmdir Net
532235368Sgnn	rmdir Proc
533235368Sgnn	rm Info/uname-a
534235368Sgnn	rm Info/psrinfo-v
535235368Sgnn	rm Info/prtconf
536235368Sgnn	rm Info/df-k
537235368Sgnn	rm Info/ifconfig-a
538235368Sgnn	rm Info/ps-o
539235368Sgnn	rm Info/uptime
540235368Sgnn	rmdir Info
541235368Sgnn	rm log
542235368Sgnn	cd ..
543235368Sgnn	rmdir $dir
544235368Sgnnelse
545235368Sgnn	decho "Directory is $dir"
546235368Sgnnfi
547235368Sgnn
548