1#!/usr/bin/sh
2#
3# cpudists - print CPU time distributions by Kernel/Idle/Processes.
4#            Written using DTrace (Solaris 10 3/05).
5#
6# 22-Sep-2005, ver 0.73         (check for newer versions)
7#
8# USAGE:	cpudists [-ahV] [-t top] [interval [count]]
9#
10#		-a              # print all processes
11#		-V              # don't print timestamps
12#		-t num          # print top num  only
13#  eg,
14#		cpudists 1      # print every 1 second
15#		cpudists -a 10  # print all processes every 10 secs
16#
17#
18# FIELDS: 
19#		value           The following or the process name,
20#		IDLE            Idle time - CPU running idle thread
21#		KERNEL          Kernel time - Kernel servicing interrupts, ...
22#		PROCESS         Process time - PIDs running on the system
23#		count           Number of occurances at least this duration (ns)
24#
25# NOTES:
26# * This takes into account multiple CPU servers, the total 
27# seconds consumed will be a multiple of the CPU count and interval.
28#
29# SEE ALSO: cputimes
30#
31# COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
32#
33# CDDL HEADER START
34#
35#  The contents of this file are subject to the terms of the
36#  Common Development and Distribution License, Version 1.0 only
37#  (the "License").  You may not use this file except in compliance
38#  with the License.
39#
40#  You can obtain a copy of the license at Docs/cddl1.txt
41#  or http://www.opensolaris.org/os/licensing.
42#  See the License for the specific language governing permissions
43#  and limitations under the License.
44#
45# CDDL HEADER END
46#
47# Author: Brendan Gregg  [Sydney, Australia]
48#
49# 27-Apr-2005   Brendan Gregg   Created this.
50# 22-Sep-2005	   "      "	Fixed key corruption bug.
51#
52
53
54##############################
55# --- Process Arguments ---
56#
57opt_all=0; opt_time=1; opt_top=0; top=0; interval=1; count=1
58
59while getopts aht:V name
60do
61        case $name in
62        a)      opt_all=1 ;;
63        V)      opt_time=0 ;;
64        t)      opt_top=1; top=$OPTARG ;;
65        h|?)    cat <<-END >&2
66		USAGE: cpudists [-ahV] [-t top] [interval [count]]
67		       cpudists                # default output
68		               -a              # print all processes
69		               -V              # don't print times
70		               -t num          # print top num only
71		END
72		exit 1
73        esac
74done
75shift `expr $OPTIND - 1`
76
77if [ "$1" -gt 0 ]; then
78        interval=$1; count=-1; shift
79fi
80if [ "$1" -gt 0 ]; then
81	count=$1; shift
82fi
83
84
85#################################
86# --- Main Program, DTrace ---
87#
88/usr/sbin/dtrace -n '
89 #pragma D option quiet
90
91 /*
92  * Command line arguments
93  */
94 inline int OPT_all    = '$opt_all';
95 inline int OPT_time   = '$opt_time';
96 inline int OPT_top    = '$opt_top';
97 inline int TOP        = '$top';
98 inline int INTERVAL   = '$interval';
99 inline int COUNTER    = '$count';
100
101 /* Initialise variables */
102 dtrace:::BEGIN
103 {
104	cpustart[cpu] = 0;
105	counts = COUNTER;
106	secs = INTERVAL;
107 }
108
109 /* Flag this thread as idle */
110 sysinfo:unix:idle_enter:idlethread
111 {
112	idle[cpu] = 1;
113 }
114
115 /* Save kernel time between running threads */
116 sched:::on-cpu 
117 /cpustart[cpu]/
118 {
119	this->elapsed = timestamp - cpustart[cpu];
120	@Procs["KERNEL"] = quantize(this->elapsed);
121 }
122
123 /* Save the elapsed time of a thread */
124 sched:::off-cpu,
125 sched:::remain-cpu,
126 profile:::profile-1sec
127 /cpustart[cpu]/
128 {
129	/* determine the name for this thread */
130	program[cpu] = pid == 0 ? idle[cpu] ? "IDLE" : "KERNEL" :
131	    OPT_all ? execname : "PROCESS";
132
133	/* save elapsed */
134	this->elapsed = timestamp - cpustart[cpu];
135	@Procs[program[cpu]] = quantize(this->elapsed);
136	cpustart[cpu] = timestamp;
137 }
138
139 /* Record the start time of a thread */
140 sched:::on-cpu,
141 sched:::remain-cpu
142 {
143	idle[cpu] = 0;
144	cpustart[cpu] = timestamp;
145 }
146
147 profile:::tick-1sec
148 {
149	secs--;
150 }
151
152 /* Print time */
153 profile:::tick-1sec 
154 /secs == 0 && OPT_time/ 
155 { 
156	printf("%Y,\n", walltimestamp);
157 }
158
159 /* Print report */
160 profile:::tick-1sec 
161 /secs == 0/ 
162 { 
163	OPT_top ? trunc(@Procs, TOP) : 1;
164	printa("%16s %@16d\n", @Procs);
165	trunc(@Procs);
166	secs = INTERVAL;
167	counts--;
168 }
169
170 /* End of program */
171 profile:::tick-1sec 
172 /counts == 0/ 
173 {
174	exit(0);
175 }
176
177 /* cleanup for Ctrl-C */
178 dtrace:::END
179 {
180	trunc(@Procs);
181 }
182'
183
184