{anchor:top}
h1. {anchor:CHP-SH} {{sh}} Provider
The sh provider makes available probes that can be used to observe the behavior of bourne shell scripts.
{color:red}{*}This provider is in development and is not currently available{*}{color}
[Top|#top]
h2. {anchor:CHP-SH-Probes} Probes
|| Probe || Description ||
| {{builtin-entry}} | Fires on entry to a shell builtin command. |
| {{builtin-return}} | Fires on return from a shell builtin command. |
| {{command-entry}} | Fires when the shell execs an external command. |
| {{command-return}} | Fires on return from an external command. |
| {{function-entry}} | Fires on entry into a shell function. |
| {{function-return}} | Fires on return from a shell function. |
| {{line}} | Fires before commands on a particular line of code are executed. |
| {{subshell-entry}} | Fires when the shell forks a subshell. |
| {{subshell-return}} | Fires on return from a forked subshell. |
| {{script-start}} | Fires before any commands in a script are executed. |
| {{script-done}} | Fires on script exit. |
| {{variable-set}} | Fires on assignment to a variable. |
| {{variable-unset}} | Fires when a variable is unset. |
Note that the use of non-empty module or function names in a {{sh\*}} probe is undefined at this time.
[Top|#top]
h5. {anchor:TBL-SH-ARGS} {{sh}} Probe Arguments
|| Probe || {{args\[0\]}} || {{args\[1\]}} || {{args\[2\]}} || {{args\[3\]}} || {{args\[4\]}} ||
| {{builtin-entry,command-entry,function-entry}} | {{char *}} | {{char *}} | {{int}} | {{int}} | {{char \*\*}} |
| {{builtin-return,command-return,function-return}} | {{char *}} | {{char *}} | {{int}} | | |
| {{subshell-entry}} | {{char *}} | {{pid_t}} | | | |
| {{subshell-return}} | {{char *}} | {{int}} | | | |
| {{line}} | {{char *}} | {{int}} | | | |
| {{script-start}} | {{char *}} | | | | |
| {{script-done}} | {{char *}} | {{int}} | | | |
| {{variable-set}} | {{char *}} | {{char *}} | {{char *}} | | |
| {{variable-unset}} | {{char *}} | {{char *}} | | | |
[Top|#top]
h5. {anchor:CHP-SH-ARGDETAIL} {{sh}} Probe Arguments - more detail
h6. {{builtin-entry,command-entry,function-entry}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{char *}}|{{args\[1\]}}|Builtin/Command/Function Name|
|{{int}}|{{args\[2\]}}|Line Number|
|{{int}}|{{args\[3\]}}|\# Arguments|
|{{char \*\*}}|{{args\[4\]}}|Pointer to argument list|
h6. {{builtin-return,command-return,function-return}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{char *}}|{{args\[1\]}}|Builtin/Command/Function Name|
|{{int}}|{{args\[2\]}}|Return Value|
h6. {{subshell-entry}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{pid_t}}|{{args\[1\]}}|Forked Process ID|
h6. {{subshell-return}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{int}}|{{args\[1\]|Return Value|
h6. {{line}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{int}}|{{args\[1\]}}|Line Number|
h6. {{script-start}}
|{{char *}}|{{args\[0\]}}|Script Name|
h6. {{script-done}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{int}}|{{args\[1\]}}|Exit Value|
h6. {{variable-set}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{char *}}|{{args\[1\]}}|Variable Name|
|{{char *}}|{{args\[2\]}}|Value|
h6. {{variable-unset}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{char *}}|{{args\[1\]}}|Variable Name|
[Top|#top]
h2. {anchor:CHP-SH-EXAMPLES} Examples
Some simple examples of {{sh}} provider usage follow.
h6. Catching a variable assignment
Say we want to determine which line in the following script has an assignment to {{WatchedVar}}:
{noformat}
#!/bin/sh
# starting script
WatchedVar=Value
unset WatchedVar
# ending script
{noformat}
We could use the following script
{noformat}
#!/usr/sbin/dtrace -s
#pragma D option quiet
sh$target:::line { self->line = arg1; }
sh$target:::variable-set /copyinstr(arg1) == "WatchedVar"/ {
printf("%d: %s=%s\n", self->line, copyinstr(arg1),
copyinstr(arg2)); }
sh$target:::variable-unset /copyinstr(arg1) == "WatchedVar"/ {
printf("%d: unset %s\n", self->line, copyinstr(arg1)); }
{noformat}
{noformat}
$ ./watch.d -c ./var.sh
4: WatchedVar=Value
5: unset WatchedVar
{noformat}
[Top|#top]
h6. Watching the time spent in functions
{noformat}
#!/usr/sbin/dtrace -s
#pragma D option quiet
sh$target:::function-entry { self->start = vtimestamp }
sh$target:::function-return {
@[copyinstr(arg1)] = quantize(vtimestamp - self->start)
}
{noformat}
Similar for the other {{entry}}/{{return}} probes, with the exception of {{subshell}} as the probe name is unavailable.
h6. Wasted time using external functions instead of builtins
This script is copied from the DTrace toolkit. It's function and how it works should be relatively self explanatory.
{noformat}
#!/usr/sbin/dtrace -Zs
/*
* sh_wasted.d - measure Bourne shell elapsed times for "wasted" commands.
* Written for the sh DTrace provider.
*
* $Id: sh_wasted.d 25 2007-09-12 09:51:58Z brendan $
*
* USAGE: sh_wasted.d { -p PID | -c cmd } # hit Ctrl-C to end
*
* This script measures "wasted" commands - those which are called externally
* but are in fact builtins to the shell. Ever seen a script which calls
* /usr/bin/echo needlessly? This script measures that cost.
*
* FIELDS:
* FILE Filename of the shell or shellscript
* NAME Name of call
* TIME Total elapsed time for calls (us)
*
* IDEA: Mike Shapiro
*
* Filename and call names are printed if available.
*
* COPYRIGHT: Copyright (c) 2007 Brendan Gregg.
*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at Docs/cddl1.txt
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* CDDL HEADER END
*
* 09-Sep-2007 Brendan Gregg Created this.
*/
#pragma D option quiet
dtrace:::BEGIN
{
isbuiltin["echo"] = 1;
isbuiltin["test"] = 1;
/* add builtins here */
printf("Tracing... Hit Ctrl-C to end.\n");
self->start = timestamp;
}
sh$target:::command-entry
{
self->command = timestamp;
}
sh$target:::command-return
{
this->elapsed = timestamp - self->command;
this->path = copyinstr(arg1);
this->cmd = basename(this->path);
}
sh$target:::command-return
/self->command && !isbuiltin[this->cmd]/
{
@types_cmd[basename(copyinstr(arg0)), this->path] = sum(this->elapsed);
self->command = 0;
}
sh$target:::command-return
/self->command/
{
@types_wasted[basename(copyinstr(arg0)), this->path] =
sum(this->elapsed);
self->command = 0;
}
proc:::exit
/pid == $target/
{
exit(0);
}
dtrace:::END
{
this->elapsed = (timestamp - self->start) / 1000;
printf("Script duration: %d us\n", this->elapsed);
normalize(@types_cmd, 1000);
printf("\nExternal command elapsed times,\n");
printf(" %-30s %-22s %8s\n", "FILE", "NAME", "TIME(us)");
printa(" %-30s %-22s %@8d\n", @types_cmd);
normalize(@types_wasted, 1000);
printf("\nWasted command elapsed times,\n");
printf(" %-30s %-22s %8s\n", "FILE", "NAME", "TIME(us)");
printa(" %-30s %-22s %@8d\n", @types_wasted);
}
{noformat}
Given the following silly little script ({{bad.sh}}), we can look at the amount of time spent executing external commands and split out the time that has been spent on commands we've defined that could have been builtins.
{noformat}
#!/bin/sh
for i in 0 1 2 3 4 5 6 7 8 9
do for j in 0 1 2 3 4 5 6 7 8 9
do /bin/echo "$i$j \c"
/bin/date
done
done
{noformat}
{noformat}
$ ./sh_wasted.d -c ./bad.sh
Tracing... Hit Ctrl-C to end.
00 Wed Jan 9 10:53:02 EST 2008
01 Wed Jan 9 10:53:03 EST 2008
02 Wed Jan 9 10:53:03 EST 2008
...
98 Wed Jan 9 10:53:20 EST 2008
99 Wed Jan 9 10:53:20 EST 2008
Script duration: 17998139 us
External command elapsed times,
FILE NAME TIME(us)
bad.sh /bin/date 1067426
Wasted command elapsed times,
FILE NAME TIME(us)
bad.sh /bin/echo 1040886
{noformat}
[Top|#top]
h2. {anchor:CHP-SH-STABILITY} Stability
The {{sh}} provider uses DTrace's stability mechanism to describe its stabilities, as shown in the following table. For more information about the stability mechanism, see [Chapter 39, Stability|Stability].
||Element||Name stability||Data stability||Dependency class||
|Provider|Unstable|Unstable|Common|
|Module|Private|Private|Unknown|
|Function|Private|Private|Unknown|
|Name|Unstable|Unstable|Common|
|Arguments|Unstable|Unstable|Common|
h1. {anchor:CHP-SH} {{sh}} Provider
The sh provider makes available probes that can be used to observe the behavior of bourne shell scripts.
{color:red}{*}This provider is in development and is not currently available{*}{color}
[Top|#top]
h2. {anchor:CHP-SH-Probes} Probes
|| Probe || Description ||
| {{builtin-entry}} | Fires on entry to a shell builtin command. |
| {{builtin-return}} | Fires on return from a shell builtin command. |
| {{command-entry}} | Fires when the shell execs an external command. |
| {{command-return}} | Fires on return from an external command. |
| {{function-entry}} | Fires on entry into a shell function. |
| {{function-return}} | Fires on return from a shell function. |
| {{line}} | Fires before commands on a particular line of code are executed. |
| {{subshell-entry}} | Fires when the shell forks a subshell. |
| {{subshell-return}} | Fires on return from a forked subshell. |
| {{script-start}} | Fires before any commands in a script are executed. |
| {{script-done}} | Fires on script exit. |
| {{variable-set}} | Fires on assignment to a variable. |
| {{variable-unset}} | Fires when a variable is unset. |
Note that the use of non-empty module or function names in a {{sh\*}} probe is undefined at this time.
[Top|#top]
h5. {anchor:TBL-SH-ARGS} {{sh}} Probe Arguments
|| Probe || {{args\[0\]}} || {{args\[1\]}} || {{args\[2\]}} || {{args\[3\]}} || {{args\[4\]}} ||
| {{builtin-entry,command-entry,function-entry}} | {{char *}} | {{char *}} | {{int}} | {{int}} | {{char \*\*}} |
| {{builtin-return,command-return,function-return}} | {{char *}} | {{char *}} | {{int}} | | |
| {{subshell-entry}} | {{char *}} | {{pid_t}} | | | |
| {{subshell-return}} | {{char *}} | {{int}} | | | |
| {{line}} | {{char *}} | {{int}} | | | |
| {{script-start}} | {{char *}} | | | | |
| {{script-done}} | {{char *}} | {{int}} | | | |
| {{variable-set}} | {{char *}} | {{char *}} | {{char *}} | | |
| {{variable-unset}} | {{char *}} | {{char *}} | | | |
[Top|#top]
h5. {anchor:CHP-SH-ARGDETAIL} {{sh}} Probe Arguments - more detail
h6. {{builtin-entry,command-entry,function-entry}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{char *}}|{{args\[1\]}}|Builtin/Command/Function Name|
|{{int}}|{{args\[2\]}}|Line Number|
|{{int}}|{{args\[3\]}}|\# Arguments|
|{{char \*\*}}|{{args\[4\]}}|Pointer to argument list|
h6. {{builtin-return,command-return,function-return}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{char *}}|{{args\[1\]}}|Builtin/Command/Function Name|
|{{int}}|{{args\[2\]}}|Return Value|
h6. {{subshell-entry}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{pid_t}}|{{args\[1\]}}|Forked Process ID|
h6. {{subshell-return}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{int}}|{{args\[1\]|Return Value|
h6. {{line}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{int}}|{{args\[1\]}}|Line Number|
h6. {{script-start}}
|{{char *}}|{{args\[0\]}}|Script Name|
h6. {{script-done}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{int}}|{{args\[1\]}}|Exit Value|
h6. {{variable-set}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{char *}}|{{args\[1\]}}|Variable Name|
|{{char *}}|{{args\[2\]}}|Value|
h6. {{variable-unset}}
|{{char *}}|{{args\[0\]}}|Script Name|
|{{char *}}|{{args\[1\]}}|Variable Name|
[Top|#top]
h2. {anchor:CHP-SH-EXAMPLES} Examples
Some simple examples of {{sh}} provider usage follow.
h6. Catching a variable assignment
Say we want to determine which line in the following script has an assignment to {{WatchedVar}}:
{noformat}
#!/bin/sh
# starting script
WatchedVar=Value
unset WatchedVar
# ending script
{noformat}
We could use the following script
{noformat}
#!/usr/sbin/dtrace -s
#pragma D option quiet
sh$target:::line { self->line = arg1; }
sh$target:::variable-set /copyinstr(arg1) == "WatchedVar"/ {
printf("%d: %s=%s\n", self->line, copyinstr(arg1),
copyinstr(arg2)); }
sh$target:::variable-unset /copyinstr(arg1) == "WatchedVar"/ {
printf("%d: unset %s\n", self->line, copyinstr(arg1)); }
{noformat}
{noformat}
$ ./watch.d -c ./var.sh
4: WatchedVar=Value
5: unset WatchedVar
{noformat}
[Top|#top]
h6. Watching the time spent in functions
{noformat}
#!/usr/sbin/dtrace -s
#pragma D option quiet
sh$target:::function-entry { self->start = vtimestamp }
sh$target:::function-return {
@[copyinstr(arg1)] = quantize(vtimestamp - self->start)
}
{noformat}
Similar for the other {{entry}}/{{return}} probes, with the exception of {{subshell}} as the probe name is unavailable.
h6. Wasted time using external functions instead of builtins
This script is copied from the DTrace toolkit. It's function and how it works should be relatively self explanatory.
{noformat}
#!/usr/sbin/dtrace -Zs
/*
* sh_wasted.d - measure Bourne shell elapsed times for "wasted" commands.
* Written for the sh DTrace provider.
*
* $Id: sh_wasted.d 25 2007-09-12 09:51:58Z brendan $
*
* USAGE: sh_wasted.d { -p PID | -c cmd } # hit Ctrl-C to end
*
* This script measures "wasted" commands - those which are called externally
* but are in fact builtins to the shell. Ever seen a script which calls
* /usr/bin/echo needlessly? This script measures that cost.
*
* FIELDS:
* FILE Filename of the shell or shellscript
* NAME Name of call
* TIME Total elapsed time for calls (us)
*
* IDEA: Mike Shapiro
*
* Filename and call names are printed if available.
*
* COPYRIGHT: Copyright (c) 2007 Brendan Gregg.
*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at Docs/cddl1.txt
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* CDDL HEADER END
*
* 09-Sep-2007 Brendan Gregg Created this.
*/
#pragma D option quiet
dtrace:::BEGIN
{
isbuiltin["echo"] = 1;
isbuiltin["test"] = 1;
/* add builtins here */
printf("Tracing... Hit Ctrl-C to end.\n");
self->start = timestamp;
}
sh$target:::command-entry
{
self->command = timestamp;
}
sh$target:::command-return
{
this->elapsed = timestamp - self->command;
this->path = copyinstr(arg1);
this->cmd = basename(this->path);
}
sh$target:::command-return
/self->command && !isbuiltin[this->cmd]/
{
@types_cmd[basename(copyinstr(arg0)), this->path] = sum(this->elapsed);
self->command = 0;
}
sh$target:::command-return
/self->command/
{
@types_wasted[basename(copyinstr(arg0)), this->path] =
sum(this->elapsed);
self->command = 0;
}
proc:::exit
/pid == $target/
{
exit(0);
}
dtrace:::END
{
this->elapsed = (timestamp - self->start) / 1000;
printf("Script duration: %d us\n", this->elapsed);
normalize(@types_cmd, 1000);
printf("\nExternal command elapsed times,\n");
printf(" %-30s %-22s %8s\n", "FILE", "NAME", "TIME(us)");
printa(" %-30s %-22s %@8d\n", @types_cmd);
normalize(@types_wasted, 1000);
printf("\nWasted command elapsed times,\n");
printf(" %-30s %-22s %8s\n", "FILE", "NAME", "TIME(us)");
printa(" %-30s %-22s %@8d\n", @types_wasted);
}
{noformat}
Given the following silly little script ({{bad.sh}}), we can look at the amount of time spent executing external commands and split out the time that has been spent on commands we've defined that could have been builtins.
{noformat}
#!/bin/sh
for i in 0 1 2 3 4 5 6 7 8 9
do for j in 0 1 2 3 4 5 6 7 8 9
do /bin/echo "$i$j \c"
/bin/date
done
done
{noformat}
{noformat}
$ ./sh_wasted.d -c ./bad.sh
Tracing... Hit Ctrl-C to end.
00 Wed Jan 9 10:53:02 EST 2008
01 Wed Jan 9 10:53:03 EST 2008
02 Wed Jan 9 10:53:03 EST 2008
...
98 Wed Jan 9 10:53:20 EST 2008
99 Wed Jan 9 10:53:20 EST 2008
Script duration: 17998139 us
External command elapsed times,
FILE NAME TIME(us)
bad.sh /bin/date 1067426
Wasted command elapsed times,
FILE NAME TIME(us)
bad.sh /bin/echo 1040886
{noformat}
[Top|#top]
h2. {anchor:CHP-SH-STABILITY} Stability
The {{sh}} provider uses DTrace's stability mechanism to describe its stabilities, as shown in the following table. For more information about the stability mechanism, see [Chapter 39, Stability|Stability].
||Element||Name stability||Data stability||Dependency class||
|Provider|Unstable|Unstable|Common|
|Module|Private|Private|Unknown|
|Function|Private|Private|Unknown|
|Name|Unstable|Unstable|Common|
|Arguments|Unstable|Unstable|Common|