234 lines
6.2 KiB
Bash
Executable File
234 lines
6.2 KiB
Bash
Executable File
#!/bin/sh
|
|
#
|
|
# procsystime - print process system call time details.
|
|
# Written using DTrace (Solaris 10 3/05).
|
|
#
|
|
# $Id: procsystime 4 2007-08-01 11:01:38Z brendan $
|
|
#
|
|
# USAGE: procsystime [-acehoT] [ -p PID | -n name | command ]
|
|
#
|
|
# -p PID # examine this PID
|
|
# -n name # examine this process name
|
|
# -a # print all details
|
|
# -c # print syscall counts
|
|
# -e # print elapsed times
|
|
# -o # print CPU times
|
|
# -T # print totals
|
|
# eg,
|
|
# procsystime -p 1871 # examine PID 1871
|
|
# procsystime -n tar # examine processes called "tar"
|
|
# procsystime -aTn bash # print all details for bash shells
|
|
# procsystime df -h # run and examine "df -h"
|
|
#
|
|
# The elapsed times are interesting, to help identify syscalls that take
|
|
# some time to complete (during which the process may have slept). CPU time
|
|
# helps us identify syscalls that are consuming CPU cycles to run.
|
|
#
|
|
# FIELDS:
|
|
# SYSCALL System call name
|
|
# TIME (ns) Total time, nanoseconds
|
|
# COUNT Number of occurrences
|
|
#
|
|
# COPYRIGHT: Copyright (c) 2005 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
|
|
#
|
|
# Author: Brendan Gregg [Sydney, Australia]
|
|
#
|
|
# 27-Apr-2005 Brendan Gregg Created this.
|
|
# 08-Jun-2005 " " Added command option.
|
|
# 22-Sep-2005 " " Allowed systemwide tracing.
|
|
# 22-Sep-2005 " " Last update.
|
|
#
|
|
|
|
|
|
##############################
|
|
# --- Process Arguments ---
|
|
#
|
|
|
|
### Default variables
|
|
opt_filter=0; opt_pid=0; opt_name=0; pid=0; pname=".";
|
|
opt_elapsed=0; opt_cpu=0; opt_counts=0; opt_totals=0
|
|
opt_command=0; command="";
|
|
|
|
### Process options
|
|
while getopts acehn:op:T name
|
|
do
|
|
case $name in
|
|
p) opt_filter=1; opt_pid=1; pid=$OPTARG ;;
|
|
n) opt_filter=1; opt_name=1; pname=$OPTARG ;;
|
|
a) opt_totals=1; opt_elapsed=1; opt_cpu=1; opt_counts=1 ;;
|
|
e) opt_elapsed=1 ;;
|
|
c) opt_counts=1 ;;
|
|
o) opt_cpu=1 ;;
|
|
T) opt_totals=1 ;;
|
|
h|?) cat <<-END >&2
|
|
USAGE: procsystime [-aceho] [ -p PID | -n name | command ]
|
|
-p PID # examine this PID
|
|
-n name # examine this process name
|
|
-a # print all details
|
|
-e # print elapsed times
|
|
-c # print syscall counts
|
|
-o # print CPU times
|
|
-T # print totals
|
|
eg,
|
|
procsystime -p 1871 # examine PID 1871
|
|
procsystime -n tar # examine processes called "tar"
|
|
procsystime -aTn bash # print all details for bash
|
|
procsystime df -h # run and examine "df -h"
|
|
END
|
|
exit 1
|
|
esac
|
|
done
|
|
shift `expr $OPTIND - 1`
|
|
|
|
### Option logic
|
|
if [ $opt_pid -eq 0 -a $opt_name -eq 0 -a "$*" != "" ]; then
|
|
opt_filter=1
|
|
opt_command=1
|
|
command="$*"
|
|
fi
|
|
if [ $opt_elapsed -eq 0 -a $opt_cpu -eq 0 -a $opt_counts -eq 0 ]; then
|
|
opt_elapsed=1;
|
|
fi
|
|
|
|
|
|
#################################
|
|
# --- Main Program, DTrace ---
|
|
#
|
|
dtrace='
|
|
#pragma D option quiet
|
|
|
|
/*
|
|
* Command line arguments
|
|
*/
|
|
inline int OPT_elapsed = '$opt_elapsed';
|
|
inline int OPT_cpu = '$opt_cpu';
|
|
inline int OPT_counts = '$opt_counts';
|
|
inline int OPT_filter = '$opt_filter';
|
|
inline int OPT_pid = '$opt_pid';
|
|
inline int OPT_name = '$opt_name';
|
|
inline int OPT_totals = '$opt_totals';
|
|
inline int OPT_command = '$opt_command';
|
|
inline int PID = '$pid';
|
|
inline string NAME = "'$pname'";
|
|
inline string COMMAND = "'$command'";
|
|
|
|
dtrace:::BEGIN
|
|
{
|
|
self->start = 0;
|
|
self->vstart = 0;
|
|
}
|
|
dtrace:::BEGIN
|
|
/! OPT_command/
|
|
{
|
|
printf("Tracing... Hit Ctrl-C to end...\n");
|
|
}
|
|
|
|
/*
|
|
* Set start timestamp and counts
|
|
*/
|
|
syscall:::entry
|
|
/(! OPT_filter) ||
|
|
(OPT_pid && pid == PID) ||
|
|
(OPT_name && execname == NAME) ||
|
|
(OPT_command && pid == $target)/
|
|
{
|
|
self->ok = 1;
|
|
}
|
|
syscall:::entry
|
|
/self->ok/
|
|
{
|
|
OPT_counts ? @Counts[probefunc] = count() : 1;
|
|
(OPT_counts && OPT_totals) ? @Counts["TOTAL:"] = count() : 1;
|
|
OPT_elapsed ? self->start = timestamp : 1;
|
|
OPT_cpu ? self->vstart = vtimestamp : 1;
|
|
self->ok = 0;
|
|
}
|
|
|
|
/*
|
|
* Calculate time deltas
|
|
*/
|
|
syscall:::return
|
|
/self->start/
|
|
{
|
|
this->elapsed = timestamp - self->start;
|
|
@Elapsed[probefunc] = sum(this->elapsed);
|
|
OPT_totals ? @Elapsed["TOTAL:"] = sum(this->elapsed) : 1;
|
|
self->start = 0;
|
|
}
|
|
syscall:::return
|
|
/self->vstart/
|
|
{
|
|
this->cpu = vtimestamp - self->vstart;
|
|
@CPU[probefunc] = sum(this->cpu);
|
|
OPT_totals ? @CPU["TOTAL:"] = sum(this->cpu) : 1;
|
|
self->vstart = 0;
|
|
}
|
|
|
|
/*
|
|
* Elapsed time report
|
|
*/
|
|
dtrace:::END
|
|
/OPT_elapsed/
|
|
{
|
|
printf("\nElapsed Times for ");
|
|
OPT_pid ? printf("PID %d,\n\n",PID) : 1;
|
|
OPT_name ? printf("processes %s,\n\n",NAME) : 1;
|
|
OPT_command ? printf("command %s,\n\n",COMMAND) : 1;
|
|
(! OPT_filter) ? printf("all processes,\n\n") : 1;
|
|
printf("%16s %18s\n","SYSCALL","TIME (ns)");
|
|
printa("%16s %@18d\n",@Elapsed);
|
|
}
|
|
|
|
/*
|
|
* CPU time report
|
|
*/
|
|
dtrace:::END
|
|
/OPT_cpu/
|
|
{
|
|
printf("\nCPU Times for ");
|
|
OPT_pid ? printf("PID %d,\n\n",PID) : 1;
|
|
OPT_name ? printf("processes %s,\n\n",NAME) : 1;
|
|
OPT_command ? printf("command %s,\n\n",COMMAND) : 1;
|
|
(! OPT_filter) ? printf("all processes,\n\n") : 1;
|
|
printf("%16s %18s\n","SYSCALL","TIME (ns)");
|
|
printa("%16s %@18d\n",@CPU);
|
|
}
|
|
|
|
/*
|
|
* Syscall count report
|
|
*/
|
|
dtrace:::END
|
|
/OPT_counts/
|
|
{
|
|
printf("\nSyscall Counts for ");
|
|
OPT_pid ? printf("PID %d,\n\n",PID) : 1;
|
|
OPT_name ? printf("processes %s,\n\n",NAME) : 1;
|
|
OPT_command ? printf("command %s,\n\n",COMMAND) : 1;
|
|
(! OPT_filter) ? printf("all processes,\n\n") : 1;
|
|
printf("%16s %18s\n","SYSCALL","COUNT");
|
|
OPT_counts ? printa("%16s %@18d\n",@Counts) : 1;
|
|
}
|
|
'
|
|
|
|
### Run DTrace
|
|
if [ $opt_command -eq 1 ]; then
|
|
/usr/sbin/dtrace -n "$dtrace" -x evaltime=exec -c "$command" >&2
|
|
else
|
|
/usr/sbin/dtrace -n "$dtrace" >&2
|
|
fi
|
|
|