1235368Sgnn#!/usr/bin/sh
2235368Sgnn#
3235368Sgnn# cputimes - print CPU time consumed by Kernel/Idle/Processes.
4235368Sgnn#            Written using DTrace (Solaris 10 3/05).
5235368Sgnn#
6235368Sgnn# $Id: cputimes 3 2007-08-01 10:50:08Z brendan $
7235368Sgnn#
8235368Sgnn# This program accurately measures time consumed by the kernel, but in
9235368Sgnn# doing so creates extra kernel load of it's own. The extra kernel
10235368Sgnn# activity can be measured by running one cputimes and then another, and
11235368Sgnn# comparing the difference in kernel consumed time. This method can be
12235368Sgnn# used to estimate the load created by other DTrace scripts.
13235368Sgnn#
14235368Sgnn# USAGE:	cputimes [-ahTV] [-t top] [interval [count]]
15235368Sgnn#
16235368Sgnn#		-a                # print all processes
17235368Sgnn#		-T                # print totals
18235368Sgnn#		-V                # don't print timestamps
19235368Sgnn#		-t num            # print top num lines only
20235368Sgnn#  eg,
21235368Sgnn#		cputimes 1        # print every 1 second
22235368Sgnn#		cputimes -a 10    # print all processes every 10 secs
23235368Sgnn#		cputimes -at 8 5  # print top 8 lines every 5 secs
24235368Sgnn#
25235368Sgnn#
26235368Sgnn# FIELDS: 
27235368Sgnn#		THREADS         The following or the process name,
28235368Sgnn#		IDLE            Idle time - CPU running idle thread
29235368Sgnn#		KERNEL          Kernel time - Kernel servicing interrupts, ...
30235368Sgnn#		PROCESS         Process time - PIDs running on the system
31235368Sgnn#		TIME (ns)       Sum of the CPU time, ns (nanoseconds)
32235368Sgnn#
33235368Sgnn# NOTES:
34235368Sgnn# * This takes into account multiple CPU servers, the total 
35235368Sgnn# seconds consumed will be a multiple of the CPU count and interval.
36235368Sgnn#
37235368Sgnn# SEE ALSO: cpudists
38235368Sgnn#           Heisenberg's uncertainty principle.
39235368Sgnn#
40235368Sgnn# COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
41235368Sgnn#
42235368Sgnn# CDDL HEADER START
43235368Sgnn#
44235368Sgnn#  The contents of this file are subject to the terms of the
45235368Sgnn#  Common Development and Distribution License, Version 1.0 only
46235368Sgnn#  (the "License").  You may not use this file except in compliance
47235368Sgnn#  with the License.
48235368Sgnn#
49235368Sgnn#  You can obtain a copy of the license at Docs/cddl1.txt
50235368Sgnn#  or http://www.opensolaris.org/os/licensing.
51235368Sgnn#  See the License for the specific language governing permissions
52235368Sgnn#  and limitations under the License.
53235368Sgnn#
54235368Sgnn# CDDL HEADER END
55235368Sgnn#
56235368Sgnn# Author: Brendan Gregg  [Sydney, Australia]
57235368Sgnn#
58235368Sgnn# 27-Apr-2005   Brendan Gregg   Created this.
59235368Sgnn# 22-Sep-2005      "      "	Fixed a key corruption bug.
60235368Sgnn# 22-Sep-2005      "      "	Last update.
61235368Sgnn#
62235368Sgnn
63235368Sgnn
64235368Sgnn##############################
65235368Sgnn# --- Process Arguments ---
66235368Sgnn#
67235368Sgnnopt_all=0; opt_time=1; opt_top=0; opt_totals=0
68235368Sgnntop=0; interval=1; count=1
69235368Sgnn
70235368Sgnnwhile getopts aht:TV name
71235368Sgnndo
72235368Sgnn        case $name in
73235368Sgnn        a)      opt_all=1 ;;
74235368Sgnn        T)      opt_totals=1 ;;
75235368Sgnn        V)      opt_time=0 ;;
76235368Sgnn        t)      opt_top=1; top=$OPTARG ;;
77235368Sgnn        h|?)    cat <<-END >&2
78235368Sgnn		USAGE: cputimes [-ahTV] [-t top] [interval [count]]
79235368Sgnn		       cputimes                  # default output
80235368Sgnn		               -a                # print all processes
81235368Sgnn		               -T                # print totals
82235368Sgnn		               -V                # don't print times
83235368Sgnn		               -t num            # print top num lines only
84235368Sgnn		          eg,
85235368Sgnn		               cputimes 1        # print every 1 second
86235368Sgnn		               cputimes -a 10    # all processes per 10 sec
87235368Sgnn		               cputimes -at 8 5  # top 8 lines every 5 secs
88235368Sgnn		END
89235368Sgnn		exit 1
90235368Sgnn        esac
91235368Sgnndone
92235368Sgnnshift `expr $OPTIND - 1`
93235368Sgnn
94235368Sgnnif [ "$1" -gt 0 ]; then
95235368Sgnn        interval=$1; count=-1; shift
96235368Sgnnfi
97235368Sgnnif [ "$1" -gt 0 ]; then
98235368Sgnn	count=$1; shift
99235368Sgnnfi
100235368Sgnn
101235368Sgnn
102235368Sgnn#################################
103235368Sgnn# --- Main Program, DTrace ---
104235368Sgnn#
105235368Sgnn/usr/sbin/dtrace -n '
106235368Sgnn #pragma D option quiet
107235368Sgnn
108235368Sgnn /*
109235368Sgnn  * Command line arguments
110235368Sgnn  */
111235368Sgnn inline int OPT_all    = '$opt_all';
112235368Sgnn inline int OPT_time   = '$opt_time';
113235368Sgnn inline int OPT_totals = '$opt_totals';
114235368Sgnn inline int OPT_top    = '$opt_top';
115235368Sgnn inline int TOP        = '$top';
116235368Sgnn inline int INTERVAL   = '$interval';
117235368Sgnn inline int COUNTER    = '$count';
118235368Sgnn
119235368Sgnn /* Initialise variables */
120235368Sgnn dtrace:::BEGIN
121235368Sgnn {
122235368Sgnn	cpustart[cpu] = 0;
123235368Sgnn	counts = COUNTER;
124235368Sgnn	secs = INTERVAL;
125235368Sgnn }
126235368Sgnn
127235368Sgnn /* Flag this thread as idle */
128235368Sgnn sysinfo:unix:idle_enter:idlethread
129235368Sgnn {
130235368Sgnn	idle[cpu] = 1;
131235368Sgnn }
132235368Sgnn
133235368Sgnn /* Save kernel time between running threads */
134235368Sgnn sched:::on-cpu 
135235368Sgnn /cpustart[cpu]/
136235368Sgnn {
137235368Sgnn	this->elapsed = timestamp - cpustart[cpu];
138235368Sgnn	@Procs["KERNEL"] = sum(this->elapsed);
139235368Sgnn }
140235368Sgnn
141235368Sgnn /* Save the elapsed time of a thread */
142235368Sgnn sched:::off-cpu,
143235368Sgnn sched:::remain-cpu,
144235368Sgnn profile:::profile-1sec
145235368Sgnn /cpustart[cpu]/
146235368Sgnn {
147235368Sgnn	/* determine the name for this thread */
148235368Sgnn	program[cpu] = pid == 0 ? idle[cpu] ? "IDLE" : "KERNEL" :
149235368Sgnn	    OPT_all ? execname : "PROCESS";
150235368Sgnn
151235368Sgnn	/* save elapsed */
152235368Sgnn	this->elapsed = timestamp - cpustart[cpu];
153235368Sgnn	@Procs[program[cpu]] = sum(this->elapsed);
154235368Sgnn	cpustart[cpu] = timestamp;
155235368Sgnn }
156235368Sgnn
157235368Sgnn /* Record the start time of a thread */
158235368Sgnn sched:::on-cpu,
159235368Sgnn sched:::remain-cpu
160235368Sgnn {
161235368Sgnn	idle[cpu] = 0;
162235368Sgnn	cpustart[cpu] = timestamp;
163235368Sgnn }
164235368Sgnn
165235368Sgnn
166235368Sgnn profile:::tick-1sec
167235368Sgnn {
168235368Sgnn	secs--;
169235368Sgnn }
170235368Sgnn
171235368Sgnn /* Print time */
172235368Sgnn profile:::tick-1sec 
173235368Sgnn /secs == 0/
174235368Sgnn { 
175235368Sgnn	OPT_time ? printf("%Y,\n", walltimestamp) : 1;
176235368Sgnn	printf("%16s %16s\n", "THREADS", "TIME (ns)");
177235368Sgnn }
178235368Sgnn
179235368Sgnn /* Print report */
180235368Sgnn profile:::tick-1sec 
181235368Sgnn /secs == 0/ 
182235368Sgnn { 
183235368Sgnn	OPT_top ? trunc(@Procs, TOP) : 1;
184235368Sgnn	printa("%16s %@16d\n", @Procs);
185235368Sgnn	trunc(@Procs);
186235368Sgnn	secs = INTERVAL;
187235368Sgnn	counts--;
188235368Sgnn }
189235368Sgnn
190235368Sgnn /* End of program */
191235368Sgnn profile:::tick-1sec 
192235368Sgnn /counts == 0/ 
193235368Sgnn {
194235368Sgnn	exit(0);
195235368Sgnn }
196235368Sgnn
197235368Sgnn /* cleanup for Ctrl-C */
198235368Sgnn dtrace:::END
199235368Sgnn {
200235368Sgnn	trunc(@Procs);
201235368Sgnn }
202235368Sgnn'
203235368Sgnn
204