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# $Id: cpudists 3 2007-08-01 10:50:08Z brendan $
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# 22-Sep-2005	   "      "	Last update.
52#
53
54
55##############################
56# --- Process Arguments ---
57#
58opt_all=0; opt_time=1; opt_top=0; top=0; interval=1; count=1
59
60while getopts aht:V name
61do
62        case $name in
63        a)      opt_all=1 ;;
64        V)      opt_time=0 ;;
65        t)      opt_top=1; top=$OPTARG ;;
66        h|?)    cat <<-END >&2
67		USAGE: cpudists [-ahV] [-t top] [interval [count]]
68		       cpudists                # default output
69		               -a              # print all processes
70		               -V              # don't print times
71		               -t num          # print top num only
72		END
73		exit 1
74        esac
75done
76shift `expr $OPTIND - 1`
77
78if [ "$1" -gt 0 ]; then
79        interval=$1; count=-1; shift
80fi
81if [ "$1" -gt 0 ]; then
82	count=$1; shift
83fi
84
85
86#################################
87# --- Main Program, DTrace ---
88#
89/usr/sbin/dtrace -n '
90 #pragma D option quiet
91
92 /*
93  * Command line arguments
94  */
95 inline int OPT_all    = '$opt_all';
96 inline int OPT_time   = '$opt_time';
97 inline int OPT_top    = '$opt_top';
98 inline int TOP        = '$top';
99 inline int INTERVAL   = '$interval';
100 inline int COUNTER    = '$count';
101
102 /* Initialise variables */
103 dtrace:::BEGIN
104 {
105	cpustart[cpu] = 0;
106	counts = COUNTER;
107	secs = INTERVAL;
108 }
109
110 /* Flag this thread as idle */
111 sysinfo:unix:idle_enter:idlethread
112 {
113	idle[cpu] = 1;
114 }
115
116 /* Save kernel time between running threads */
117 sched:::on-cpu 
118 /cpustart[cpu]/
119 {
120	this->elapsed = timestamp - cpustart[cpu];
121	@Procs["KERNEL"] = quantize(this->elapsed);
122 }
123
124 /* Save the elapsed time of a thread */
125 sched:::off-cpu,
126 sched:::remain-cpu,
127 profile:::profile-1sec
128 /cpustart[cpu]/
129 {
130	/* determine the name for this thread */
131	program[cpu] = pid == 0 ? idle[cpu] ? "IDLE" : "KERNEL" :
132	    OPT_all ? execname : "PROCESS";
133
134	/* save elapsed */
135	this->elapsed = timestamp - cpustart[cpu];
136	@Procs[program[cpu]] = quantize(this->elapsed);
137	cpustart[cpu] = timestamp;
138 }
139
140 /* Record the start time of a thread */
141 sched:::on-cpu,
142 sched:::remain-cpu
143 {
144	idle[cpu] = 0;
145	cpustart[cpu] = timestamp;
146 }
147
148 profile:::tick-1sec
149 {
150	secs--;
151 }
152
153 /* Print time */
154 profile:::tick-1sec 
155 /secs == 0 && OPT_time/ 
156 { 
157	printf("%Y,\n", walltimestamp);
158 }
159
160 /* Print report */
161 profile:::tick-1sec 
162 /secs == 0/ 
163 { 
164	OPT_top ? trunc(@Procs, TOP) : 1;
165	printa("%16s %@16d\n", @Procs);
166	trunc(@Procs);
167	secs = INTERVAL;
168	counts--;
169 }
170
171 /* End of program */
172 profile:::tick-1sec 
173 /counts == 0/ 
174 {
175	exit(0);
176 }
177
178 /* cleanup for Ctrl-C */
179 dtrace:::END
180 {
181	trunc(@Procs);
182 }
183'
184
185