Im working on a bash profiling tool called timep
that gives per-command runtime profile for bash scripts and functions. It does this using a DEBUG trap to record start time and stop time for each command plus various info/metadata ($LINENO, $BASHPID, $FUNCNAME, $BASH_COMMAND, etc.) about the command being run. The current version can be found on github.
Im trying to group together the commands so that the profile(s) generated match the way the code being profiled is written. In particular:
- function calls are split off into a separate line-by-line profile, and the profile for the caller gets a single line for the function call that includes the total time spent running each command run in the function (i.e., function runtime without timing instrumentation time)
- commands that get forked but are automatically waited on by the shell (subshells, command substitutions, pipelines, etc.) will NOT be split off into separate profiles. These commands will, however, list their PIDs hierarchically (PID0->PID1[->PID2[...]])
- commands that are explicitly forked and not automatically waited on (
cmd &
,coproc cmd
) will be split off into separate profiles and their runtime (except for the time taken by the forking operation) will not be included in the caller's profile
#3 is the one im trying to figure out here. Specifically, how can the forked process immediately identify (e.g., the first time its debug trap fires) that it was just forked so that it can write its timing log data to a different tmpfile?
I can figure this out in the parent function by recording $!
in a variable every time the debug trap fires and if this doesnt match $!
in the next debug trap then I know something was forked. But, $!
isnt updated in the forked process, only in the parent. I could have the parent save a list of forked processes in a tmpfile and then have all processes check for their $BASHPID in this list. This almost work, but the first few debug trap events in the forked process tend to get missed.
EDIT: here is an example of the sort of time profile im trying to create. In this example there is something not quite right with how subshells get accounted for, but the issue in trying to figure out a fix for with this post is that all the forked echo _d
ommands should be split off into their own profiles, since their parent isnt waiting for them and thus their runtime shouldnt be included in the parents runtime.
Im working on a bash profiling tool called timep
that gives per-command runtime profile for bash scripts and functions. It does this using a DEBUG trap to record start time and stop time for each command plus various info/metadata ($LINENO, $BASHPID, $FUNCNAME, $BASH_COMMAND, etc.) about the command being run. The current version can be found on github.
Im trying to group together the commands so that the profile(s) generated match the way the code being profiled is written. In particular:
- function calls are split off into a separate line-by-line profile, and the profile for the caller gets a single line for the function call that includes the total time spent running each command run in the function (i.e., function runtime without timing instrumentation time)
- commands that get forked but are automatically waited on by the shell (subshells, command substitutions, pipelines, etc.) will NOT be split off into separate profiles. These commands will, however, list their PIDs hierarchically (PID0->PID1[->PID2[...]])
- commands that are explicitly forked and not automatically waited on (
cmd &
,coproc cmd
) will be split off into separate profiles and their runtime (except for the time taken by the forking operation) will not be included in the caller's profile
#3 is the one im trying to figure out here. Specifically, how can the forked process immediately identify (e.g., the first time its debug trap fires) that it was just forked so that it can write its timing log data to a different tmpfile?
I can figure this out in the parent function by recording $!
in a variable every time the debug trap fires and if this doesnt match $!
in the next debug trap then I know something was forked. But, $!
isnt updated in the forked process, only in the parent. I could have the parent save a list of forked processes in a tmpfile and then have all processes check for their $BASHPID in this list. This almost work, but the first few debug trap events in the forked process tend to get missed.
EDIT: here is an example of the sort of time profile im trying to create. In this example there is something not quite right with how subshells get accounted for, but the issue in trying to figure out a fix for with this post is that all the forked echo _d
ommands should be split off into their own profiles, since their parent isnt waiting for them and thus their runtime shouldnt be included in the parents runtime.
1 Answer
Reset to default 2Use one of these builtin variables:
BASH_SUBSHELL
Incremented by one within each subshell or subshell environment when the shell begins executing in that environment. The initial value is 0. If
BASH_SUBSHELL
is unset, it loses its special properties, even if it is subsequently reset.
SHLVL
Incremented by one each time a new instance of Bash is started. This is intended to be a count of how deeply your Bash shells are nested.
set -T
. You can test via( set -T; trap 'echo "$BASH_COMMAND --from-- $BASHPID" >>/tmp/test.log' DEBUG; { sleep 1; trap -p; echo $BASHPID; } & echo $BASHPID; ); sleep 1; cat /tmp/test.log
. Also, I edited in an example into the main post that hopefully clarifies what Im trying to do. – jkool702 Commented Mar 26 at 13:24set -T
overrides that with respect to shell functions for DEBUG and RETURN traps, but not with respect to other simple commands. Maybe that's ok with you, though. – John Bollinger Commented Mar 26 at 19:01set -T
: "If set, any trap on DEBUG and RETURN are inherited by shell functions, command substitutions, and commands executed in a subshell environment." Forked commands and coprocs arent explicitly listed, but the test code in my previous comment pretty clearly indicated they should be included in that list. – jkool702 Commented Mar 26 at 22:18