1#!/usr/sbin/dtrace -Zs
2/*
3 * sh_wasted.d - measure Bourne shell elapsed times for "wasted" commands.
4 *               Written for the sh DTrace provider.
5 *
6 * $Id: sh_wasted.d 25 2007-09-12 09:51:58Z brendan $
7 *
8 * USAGE: sh_wasted.d { -p PID | -c cmd }	# hit Ctrl-C to end
9 *
10 * This script measures "wasted" commands - those which are called externally
11 * but are in fact builtins to the shell. Ever seen a script which calls
12 * /usr/bin/echo needlessly? This script measures that cost.
13 *
14 * FIELDS:
15 *		FILE		Filename of the shell or shellscript
16 *		NAME		Name of call
17 *		TIME		Total elapsed time for calls (us)
18 *
19 * IDEA: Mike Shapiro
20 *
21 * Filename and call names are printed if available.
22 *
23 * COPYRIGHT: Copyright (c) 2007 Brendan Gregg.
24 *
25 * CDDL HEADER START
26 *
27 *  The contents of this file are subject to the terms of the
28 *  Common Development and Distribution License, Version 1.0 only
29 *  (the "License").  You may not use this file except in compliance
30 *  with the License.
31 *
32 *  You can obtain a copy of the license at Docs/cddl1.txt
33 *  or http://www.opensolaris.org/os/licensing.
34 *  See the License for the specific language governing permissions
35 *  and limitations under the License.
36 *
37 * CDDL HEADER END
38 *
39 * 09-Sep-2007	Brendan Gregg	Created this.
40 */
41
42#pragma D option quiet
43
44dtrace:::BEGIN
45{
46	isbuiltin["echo"] = 1;
47	isbuiltin["test"] = 1;
48	/* add builtins here */
49
50	printf("Tracing... Hit Ctrl-C to end.\n");
51	self->start = timestamp;
52}
53
54sh$target:::command-entry
55{
56	self->command = timestamp;
57}
58
59sh$target:::command-return
60{
61	this->elapsed = timestamp - self->command;
62	this->path = copyinstr(arg1);
63	this->cmd = basename(this->path);
64}
65
66sh$target:::command-return
67/self->command && !isbuiltin[this->cmd]/
68{
69	@types_cmd[basename(copyinstr(arg0)), this->path] = sum(this->elapsed);
70	self->command = 0;
71}
72
73sh$target:::command-return
74/self->command/
75{
76	@types_wasted[basename(copyinstr(arg0)), this->path] =
77	    sum(this->elapsed);
78	self->command = 0;
79}
80
81proc:::exit
82/pid == $target/
83{
84	exit(0);
85}
86
87dtrace:::END
88{
89	this->elapsed = (timestamp - self->start) / 1000;
90	printf("Script duration: %d us\n", this->elapsed);
91
92	normalize(@types_cmd, 1000);
93	printf("\nExternal command elapsed times,\n");
94	printf("   %-30s %-22s %8s\n", "FILE", "NAME", "TIME(us)");
95	printa("   %-30s %-22s %@8d\n", @types_cmd);
96
97	normalize(@types_wasted, 1000);
98	printf("\nWasted command elapsed times,\n");
99	printf("   %-30s %-22s %8s\n", "FILE", "NAME", "TIME(us)");
100	printa("   %-30s %-22s %@8d\n", @types_wasted);
101}
102