aboutsummaryrefslogtreecommitdiff
path: root/Apps/weblatency.d
diff options
context:
space:
mode:
Diffstat (limited to 'Apps/weblatency.d')
-rwxr-xr-xApps/weblatency.d186
1 files changed, 186 insertions, 0 deletions
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);
+}