diff options
Diffstat (limited to 'cddl/contrib/dtracetoolkit/Apps/weblatency.d')
-rwxr-xr-x | cddl/contrib/dtracetoolkit/Apps/weblatency.d | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/cddl/contrib/dtracetoolkit/Apps/weblatency.d b/cddl/contrib/dtracetoolkit/Apps/weblatency.d new file mode 100755 index 0000000..8d96d5c --- /dev/null +++ b/cddl/contrib/dtracetoolkit/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); +} |