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