aboutsummaryrefslogtreecommitdiff
path: root/Apps
diff options
context:
space:
mode:
Diffstat (limited to 'Apps')
-rw-r--r--Apps/Readme5
-rwxr-xr-xApps/httpdstat.d132
-rwxr-xr-xApps/nfswizard.d102
-rwxr-xr-xApps/shellsnoop268
-rwxr-xr-xApps/weblatency.d186
5 files changed, 693 insertions, 0 deletions
diff --git a/Apps/Readme b/Apps/Readme
new file mode 100644
index 000000000000..3a6812f4bfa2
--- /dev/null
+++ b/Apps/Readme
@@ -0,0 +1,5 @@
+Apps - Specific Application based analysis
+
+ These are DTrace scripts that are written to analyse a particular
+ application or applictaion layer protocol. For example, Apache or NFS
+ scripts would appear here.
diff --git a/Apps/httpdstat.d b/Apps/httpdstat.d
new file mode 100755
index 000000000000..a053482a6c15
--- /dev/null
+++ b/Apps/httpdstat.d
@@ -0,0 +1,132 @@
+#!/usr/sbin/dtrace -s
+/*
+ * httpdstat.d - realtime httpd statistics. Uses DTrace.
+ *
+ * $Id: httpdstat.d 2 2007-08-01 10:01:43Z brendan $
+ *
+ * USAGE: httpdstat.d [interval [count]]
+ *
+ * interval seconds
+ * count number of samples
+ *
+ * FIELDS:
+ * TIME Time, string
+ * NUM Number of connections
+ * GET Number of "GET"s
+ * POST Number of "POST"s
+ * HEAD Number of "HEAD"s
+ * TRACE Number of "TRACE"s
+ *
+ * All of the statistics are printed as a value per interval (not per second).
+ *
+ * NOTE: This version does not process subsequent operations on keepalives.
+ *
+ * IDEA: Ryan Matteson (who first wrote a solution to this).
+ *
+ * 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
+ *
+ * 20-Nov-2005 Brendan Gregg Created this.
+ */
+
+#pragma D option quiet
+#pragma D option defaultargs
+
+inline int SCREEN = 21;
+
+/*
+ * Program Start
+ */
+dtrace:::BEGIN
+{
+ num = 0; get = 0; head = 0; post = 0; trac = 0;
+ lines = SCREEN + 1;
+ secs = $1 ? $1 : 1;
+ counts = $2 ? $2 : -1;
+ first = 1;
+}
+
+profile:::tick-1sec
+{
+ secs--;
+}
+
+/*
+ * Print Header
+ */
+dtrace:::BEGIN,
+profile:::tick-1sec
+/first || (secs == 0 && lines > SCREEN)/
+{
+ printf("%-20s %6s %6s %5s %5s %5s\n", "TIME",
+ "NUM", "GET", "POST", "HEAD", "TRACE");
+ lines = 0;
+ first = 0;
+}
+
+/*
+ * Track Accept Events
+ */
+syscall::accept:return
+/execname == "httpd"/
+{
+ self->buf = 1;
+}
+
+syscall::read:entry
+/self->buf/
+{
+ self->buf = arg1;
+}
+
+/*
+ * Tally Data
+ */
+syscall::read:return
+/self->buf && arg0/
+{
+ this->str = (char *)copyin(self->buf, arg0);
+ this->str[4] = '\0';
+ get += stringof(this->str) == "GET " ? 1 : 0;
+ post += stringof(this->str) == "POST" ? 1 : 0;
+ head += stringof(this->str) == "HEAD" ? 1 : 0;
+ trac += stringof(this->str) == "TRAC" ? 1 : 0;
+ num++;
+ self->buf = 0;
+}
+
+/*
+ * Print Output
+ */
+profile:::tick-1sec
+/secs == 0/
+{
+ printf("%-20Y %6d %6d %5d %5d %5d\n", walltimestamp,
+ num, get, post, head, trac);
+ num = 0; get = 0; head = 0; post = 0; trac = 0;
+ secs = $1 ? $1 : 1;
+ lines++;
+ counts--;
+}
+
+/*
+ * End
+ */
+profile:::tick-1sec
+/counts == 0/
+{
+ exit(0);
+}
diff --git a/Apps/nfswizard.d b/Apps/nfswizard.d
new file mode 100755
index 000000000000..c63bc33dfa4e
--- /dev/null
+++ b/Apps/nfswizard.d
@@ -0,0 +1,102 @@
+#!/usr/sbin/dtrace -s
+/*
+ * nfswizard.d - nfs client activity wizard.
+ * Written using DTrace (Solaris 10 3/05).
+ *
+ * This examines activity caused by NFS client processes on the same server
+ * that you are running this script on. A detailed report is generated
+ * to explain various details of NFS client activity, including response
+ * times and file access.
+ *
+ * $Id: nfswizard.d 3 2007-08-01 10:50:08Z brendan $
+ *
+ * USAGE: nfswizard.d # hit Ctrl-C to end sample
+ *
+ * COPYRIGHT: Copyright (c) 2005, 2006 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
+ *
+ * 02-Dec-2005 Brendan Gregg Created this.
+ * 20-Apr-2006 " " Last update.
+ */
+
+#pragma D option quiet
+
+dtrace:::BEGIN
+{
+ printf("Tracing... Hit Ctrl-C to end.\n");
+ scriptstart = walltimestamp;
+ timestart = timestamp;
+}
+
+io:nfs::start
+{
+ /* tally file sizes */
+ @file[args[2]->fi_pathname] = sum(args[0]->b_bcount);
+
+ /* time response */
+ start[args[0]->b_addr] = timestamp;
+
+ /* overall stats */
+ @rbytes = sum(args[0]->b_flags & B_READ ? args[0]->b_bcount : 0);
+ @wbytes = sum(args[0]->b_flags & B_READ ? 0 : args[0]->b_bcount);
+ @events = count();
+}
+
+io:nfs::done
+/start[args[0]->b_addr]/
+{
+ /* calculate and save response time stats */
+ this->elapsed = timestamp - start[args[0]->b_addr];
+ @maxtime = max(this->elapsed);
+ @avgtime = avg(this->elapsed);
+ @qnztime = quantize(this->elapsed / 1000);
+}
+
+dtrace:::END
+{
+ /* print header */
+ printf("NFS Client Wizard. %Y -> %Y\n\n", scriptstart, walltimestamp);
+
+ /* print read/write stats */
+ printa("Read: %@d bytes ", @rbytes);
+ normalize(@rbytes, 1000000);
+ printa("(%@d Mb)\n", @rbytes);
+ printa("Write: %@d bytes ", @wbytes);
+ normalize(@wbytes, 1000000);
+ printa("(%@d Mb)\n\n", @wbytes);
+
+ /* print throughput stats */
+ denormalize(@rbytes);
+ normalize(@rbytes, (timestamp - timestart) / 1000000);
+ printa("Read: %@d Kb/sec\n", @rbytes);
+ denormalize(@wbytes);
+ normalize(@wbytes, (timestamp - timestart) / 1000000);
+ printa("Write: %@d Kb/sec\n\n", @wbytes);
+
+ /* print time stats */
+ printa("NFS I/O events: %@d\n", @events);
+ normalize(@avgtime, 1000000);
+ printa("Avg response time: %@d ms\n", @avgtime);
+ normalize(@maxtime, 1000000);
+ printa("Max response time: %@d ms\n\n", @maxtime);
+ printa("Response times (us):%@d\n", @qnztime);
+
+ /* print file stats */
+ printf("Top 25 files accessed (bytes):\n");
+ printf(" %-64s %s\n", "PATHNAME", "BYTES");
+ trunc(@file, 25);
+ printa(" %-64s %@d\n", @file);
+}
diff --git a/Apps/shellsnoop b/Apps/shellsnoop
new file mode 100755
index 000000000000..95f42c046529
--- /dev/null
+++ b/Apps/shellsnoop
@@ -0,0 +1,268 @@
+#!/usr/bin/sh
+#
+# shellsnoop - A program to print read/write details from shells,
+# such as keystrokes and command outputs.
+# Written using DTrace (Solaris 10 3/05).
+#
+# This program sounds somewhat dangerous (snooping keystrokes), but is
+# no more so than /usr/bin/truss, and both need root or dtrace privileges to
+# run. In fact, less dangerous, as we only print visible text (not password
+# text, for example). Having said that, it goes without saying that this
+# program shouldn't be used for breeching privacy of other users.
+#
+# This was written as a tool to demonstrate the capabilities of DTrace.
+#
+# $Id: shellsnoop 19 2007-09-12 07:47:59Z brendan $
+#
+# USAGE: shellsnoop [-hqsv] [-p PID] [-u UID]
+#
+# -q # quiet, only print data
+# -s # include start time, us
+# -v # include start time, string
+# -p PID # process ID to snoop
+# -u UID # user ID to snoop
+# eg,
+# shellsnoop # default output
+# shellsnoop -v # human readable timestamps
+# shellsnoop -p 1892 # snoop this PID only
+# shellsnoop -qp 1892 # watch this PID data only
+#
+# FIELDS:
+# UID User ID
+# PID process ID
+# PPID parent process ID
+# COMM command name
+# DIR direction (R read, W write)
+# TEXT text contained in the read/write
+# TIME timestamp for the command, us
+# STRTIME timestamp for the command, string
+#
+# SEE ALSO: ttywatcher
+#
+# 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]
+#
+# 28-Mar-2004 Brendan Gregg Created this.
+# 21-Jan-2005 " " Wrapped in sh to provide options.
+# 30-Nov-2005 " " Fixed trailing buffer text bug.
+# 30-Nov-2005 " " Fixed sh no keystroke text in quiet bug.
+# 30-Nov-2005 " " Last update.
+#
+
+
+##############################
+# --- Process Arguments ---
+#
+opt_pid=0; opt_uid=0; opt_time=0; opt_timestr=0; opt_quiet=0; opt_debug=0
+filter=0; pid=0; uid=0
+
+while getopts dhp:qsu:v name
+do
+ case $name in
+ d) opt_debug=1 ;;
+ p) opt_pid=1; pid=$OPTARG ;;
+ q) opt_quiet=1 ;;
+ s) opt_time=1 ;;
+ u) opt_uid=1; uid=$OPTARG ;;
+ v) opt_timestr=1 ;;
+ h|?) cat <<-END >&2
+ USAGE: shellsnoop [-hqsv] [-p PID] [-u UID]
+ shellsnoop # default output
+ -q # quiet, only print data
+ -s # include start time, us
+ -v # include start time, string
+ -p PID # process ID to snoop
+ -u UID # user ID to snoop
+ END
+ exit 1
+ esac
+done
+
+if [ $opt_quiet -eq 1 ]; then
+ opt_time=0; opt_timestr=0
+fi
+if [ $opt_pid -eq 1 -o $opt_uid -eq 1 ]; then
+ filter=1
+fi
+
+
+#################################
+# --- Main Program, DTrace ---
+#
+dtrace -n '
+ /*
+ * Command line arguments
+ */
+ inline int OPT_debug = '$opt_debug';
+ inline int OPT_quiet = '$opt_quiet';
+ inline int OPT_pid = '$opt_pid';
+ inline int OPT_uid = '$opt_uid';
+ inline int OPT_time = '$opt_time';
+ inline int OPT_timestr = '$opt_timestr';
+ inline int FILTER = '$filter';
+ inline int PID = '$pid';
+ inline int UID = '$uid';
+
+ #pragma D option quiet
+ #pragma D option switchrate=20hz
+
+ /*
+ * Print header
+ */
+ dtrace:::BEGIN /OPT_time == 1/
+ {
+ printf("%-14s ","TIME");
+ }
+ dtrace:::BEGIN /OPT_timestr == 1/
+ {
+ printf("%-20s ","STRTIME");
+ }
+ dtrace:::BEGIN /OPT_quiet == 0/
+ {
+ printf("%5s %5s %8s %3s %s\n", "PID", "PPID", "CMD", "DIR", "TEXT");
+ }
+
+ /*
+ * Remember this PID is a shell child
+ */
+ syscall::exec:entry, syscall::exece:entry
+ /execname == "sh" || execname == "ksh" || execname == "csh" ||
+ execname == "tcsh" || execname == "zsh" || execname == "bash"/
+ {
+ child[pid] = 1;
+
+ /* debug */
+ this->parent = (char *)curthread->t_procp->p_parent->p_user.u_comm;
+ OPT_debug == 1 ? printf("PID %d CMD %s started. (%s)\n",
+ pid, execname, stringof(this->parent)) : 1;
+ }
+ syscall::exec:entry, syscall::exece:entry
+ /(OPT_pid == 1 && PID != ppid) || (OPT_uid == 1 && UID != uid)/
+ {
+ /* forget if filtered */
+ child[pid] = 0;
+ }
+
+ /*
+ * Print shell keystrokes
+ */
+ syscall::write:entry, syscall::read:entry
+ /(execname == "sh" || execname == "ksh" || execname == "csh" ||
+ execname == "tcsh" || execname == "zsh" || execname == "bash")
+ && (arg0 >= 0 && arg0 <= 2)/
+ {
+ self->buf = arg1;
+ }
+ syscall::write:entry, syscall::read:entry
+ /(OPT_pid == 1 && PID != pid) || (OPT_uid == 1 && UID != uid)/
+ {
+ self->buf = 0;
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && child[pid] == 0 && OPT_time == 1/
+ {
+ printf("%-14d ", timestamp/1000);
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && child[pid] == 0 && OPT_timestr == 1/
+ {
+ printf("%-20Y ", walltimestamp);
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && child[pid] == 0 && OPT_quiet == 0/
+ {
+ this->text = (char *)copyin(self->buf, arg0);
+ this->text[arg0] = '\'\\0\'';
+
+ printf("%5d %5d %8s %3s %s\n", pid, curpsinfo->pr_ppid, execname,
+ probefunc == "read" ? "R" : "W", stringof(this->text));
+ }
+ syscall::write:return
+ /self->buf && child[pid] == 0 && OPT_quiet == 1/
+ {
+ this->text = (char *)copyin(self->buf, arg0);
+ this->text[arg0] = '\'\\0\'';
+ printf("%s", stringof(this->text));
+ }
+ syscall::read:return
+ /self->buf && execname == "sh" && child[pid] == 0 && OPT_quiet == 1/
+ {
+ this->text = (char *)copyin(self->buf, arg0);
+ this->text[arg0] = '\'\\0\'';
+ printf("%s", stringof(this->text));
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && child[pid] == 0/
+ {
+ self->buf = 0;
+ }
+
+ /*
+ * Print command output
+ */
+ syscall::write:entry, syscall::read:entry
+ /child[pid] == 1 && (arg0 == 1 || arg0 == 2)/
+ {
+ self->buf = arg1;
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && OPT_time == 1/
+ {
+ printf("%-14d ", timestamp/1000);
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && OPT_timestr == 1/
+ {
+ printf("%-20Y ", walltimestamp);
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && OPT_quiet == 0/
+ {
+ this->text = (char *)copyin(self->buf, arg0);
+ this->text[arg0] = '\'\\0\'';
+
+ printf("%5d %5d %8s %3s %s", pid, curpsinfo->pr_ppid, execname,
+ probefunc == "read" ? "R" : "W", stringof(this->text));
+
+ /* here we check if a newline is needed */
+ this->length = strlen(this->text);
+ printf("%s", this->text[this->length - 1] == '\'\\n\'' ? "" : "\n");
+ self->buf = 0;
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && OPT_quiet == 1/
+ {
+ this->text = (char *)copyin(self->buf, arg0);
+ this->text[arg0] = '\'\\0\'';
+ printf("%s", stringof(this->text));
+ self->buf = 0;
+ }
+
+ /*
+ * Cleanup
+ */
+ syscall::rexit:entry
+ {
+ child[pid] = 0;
+
+ /* debug */
+ this->parent = (char *)curthread->t_procp->p_parent->p_user.u_comm;
+ OPT_debug == 1 ? printf("PID %d CMD %s exited. (%s)\n",
+ pid, execname, stringof(this->parent)) : 1;
+ }
+'
diff --git a/Apps/weblatency.d b/Apps/weblatency.d
new file mode 100755
index 000000000000..8d96d5cdd88b
--- /dev/null
+++ b/Apps/weblatency.d
@@ -0,0 +1,186 @@
+#!/usr/sbin/dtrace -s
+/*
+ * weblatency.d - website latency statistics.
+ * Written using DTrace (Solaris 10 3/05).
+ *
+ * $Id: weblatency.d 3 2007-08-01 10:50:08Z brendan $
+ *
+ * USAGE: weblatency.d # hit Ctrl-C to end sample
+ *
+ * See the code below for the "BROWSER" variable, which sets the browser
+ * to trace (currently set to "mozilla-bin").
+ *
+ * This is written as an experimental tool, and may not work at all with
+ * your browser.
+ *
+ * FIELDS:
+ * HOST Hostname from URL
+ * NUM Number of GETs
+ * AVGTIME(ms) Average time for response, ms
+ * MAXTIME(ms) Maximum time for response, ms
+ *
+ * NOTE:
+ *
+ * The latency measured here is from the browser sending the GET
+ * request to when the browser begins to recieve the response. It
+ * is an overall response time for the client, and encompasses
+ * connection speed delays, DNS lookups, proxy delays, and web server
+ * response time.
+ *
+ * IDEA: Bryan Cantrill (who wrote an elegant version for Sol 10 update 1)
+ *
+ * COPYRIGHT: Copyright (c) 2005, 2006 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
+ *
+ * ToDo:
+ * Check write fd for socket, not file.
+ *
+ * 30-Nov-2005 Brendan Gregg Created this.
+ * 20-Apr-2006 " " Last update.
+ */
+
+#pragma D option quiet
+
+/* browser's execname */
+inline string BROWSER = "mozilla-bin";
+
+/* maximum expected hostname length + "GET http://" */
+inline int MAX_REQ = 64;
+
+dtrace:::BEGIN
+{
+ printf("Tracing... Hit Ctrl-C to end.\n");
+}
+
+/*
+ * Trace brower request
+ *
+ * This is achieved by matching writes for the browser's execname that
+ * start with "GET", and then timing from the return of the write to
+ * the return of the next read in the same thread. Various stateful flags
+ * are used: self->fd, self->read.
+ *
+ * For performance reasons, I'd like to only process writes that follow a
+ * connect(), however this approach fails to process keepalives.
+ */
+syscall::write:entry
+/execname == BROWSER/
+{
+ self->buf = arg1;
+ self->fd = arg0 + 1;
+ self->nam = "";
+}
+
+syscall::write:return
+/self->fd/
+{
+ this->str = (char *)copyin(self->buf, MAX_REQ);
+ this->str[4] = '\0';
+ self->fd = stringof(this->str) == "GET " ? self->fd : 0;
+}
+
+syscall::write:return
+/self->fd/
+{
+ /* fetch browser request */
+ this->str = (char *)copyin(self->buf, MAX_REQ);
+ this->str[MAX_REQ] = '\0';
+
+ /*
+ * This unrolled loop strips down a URL to it's hostname.
+ * We ought to use strtok(), but it's not available on Sol 10 3/05,
+ * so instead I used dirname(). It's not pretty - it's done so that
+ * this works on all Sol 10 versions.
+ */
+ self->req = stringof(this->str);
+ self->nam = strlen(self->req) > 15 ? self->req : self->nam;
+ self->req = dirname(self->req);
+ self->nam = strlen(self->req) > 15 ? self->req : self->nam;
+ self->req = dirname(self->req);
+ self->nam = strlen(self->req) > 15 ? self->req : self->nam;
+ self->req = dirname(self->req);
+ self->nam = strlen(self->req) > 15 ? self->req : self->nam;
+ self->req = dirname(self->req);
+ self->nam = strlen(self->req) > 15 ? self->req : self->nam;
+ self->req = dirname(self->req);
+ self->nam = strlen(self->req) > 15 ? self->req : self->nam;
+ self->req = dirname(self->req);
+ self->nam = strlen(self->req) > 15 ? self->req : self->nam;
+ self->req = dirname(self->req);
+ self->nam = strlen(self->req) > 15 ? self->req : self->nam;
+ self->req = dirname(self->req);
+ self->nam = strlen(self->req) > 15 ? self->req : self->nam;
+ self->nam = basename(self->nam);
+
+ /* start the timer */
+ start[pid, self->fd - 1] = timestamp;
+ host[pid, self->fd - 1] = self->nam;
+ self->buf = 0;
+ self->fd = 0;
+ self->req = 0;
+ self->nam = 0;
+}
+
+/* this one wasn't a GET */
+syscall::write:return
+/self->buf/
+{
+ self->buf = 0;
+ self->fd = 0;
+}
+
+syscall::read:entry
+/execname == BROWSER && start[pid, arg0]/
+{
+ self->fd = arg0 + 1;
+}
+
+/*
+ * Record host details
+ */
+syscall::read:return
+/self->fd/
+{
+ /* fetch details */
+ self->host = stringof(host[pid, self->fd - 1]);
+ this->start = start[pid, self->fd - 1];
+
+ /* save details */
+ @Avg[self->host] = avg((timestamp - this->start)/1000000);
+ @Max[self->host] = max((timestamp - this->start)/1000000);
+ @Num[self->host] = count();
+
+ /* clear vars */
+ start[pid, self->fd - 1] = 0;
+ host[pid, self->fd - 1] = 0;
+ self->host = 0;
+ self->fd = 0;
+}
+
+/*
+ * Output report
+ */
+dtrace:::END
+{
+ printf("%-32s %11s\n", "HOST", "NUM");
+ printa("%-32s %@11d\n", @Num);
+
+ printf("\n%-32s %11s\n", "HOST", "AVGTIME(ms)");
+ printa("%-32s %@11d\n", @Avg);
+
+ printf("\n%-32s %11s\n", "HOST", "MAXTIME(ms)");
+ printa("%-32s %@11d\n", @Max);
+}