weblatency.d revision 1.1 1 1.1 christos #!/usr/sbin/dtrace -s
2 1.1 christos /*
3 1.1 christos * weblatency.d - website latency statistics.
4 1.1 christos * Written using DTrace (Solaris 10 3/05).
5 1.1 christos *
6 1.1 christos * $Id: weblatency.d,v 1.1 2015/09/30 22:01:06 christos Exp $
7 1.1 christos *
8 1.1 christos * USAGE: weblatency.d # hit Ctrl-C to end sample
9 1.1 christos *
10 1.1 christos * See the code below for the "BROWSER" variable, which sets the browser
11 1.1 christos * to trace (currently set to "mozilla-bin").
12 1.1 christos *
13 1.1 christos * This is written as an experimental tool, and may not work at all with
14 1.1 christos * your browser.
15 1.1 christos *
16 1.1 christos * FIELDS:
17 1.1 christos * HOST Hostname from URL
18 1.1 christos * NUM Number of GETs
19 1.1 christos * AVGTIME(ms) Average time for response, ms
20 1.1 christos * MAXTIME(ms) Maximum time for response, ms
21 1.1 christos *
22 1.1 christos * NOTE:
23 1.1 christos *
24 1.1 christos * The latency measured here is from the browser sending the GET
25 1.1 christos * request to when the browser begins to recieve the response. It
26 1.1 christos * is an overall response time for the client, and encompasses
27 1.1 christos * connection speed delays, DNS lookups, proxy delays, and web server
28 1.1 christos * response time.
29 1.1 christos *
30 1.1 christos * IDEA: Bryan Cantrill (who wrote an elegant version for Sol 10 update 1)
31 1.1 christos *
32 1.1 christos * COPYRIGHT: Copyright (c) 2005, 2006 Brendan Gregg.
33 1.1 christos *
34 1.1 christos * CDDL HEADER START
35 1.1 christos *
36 1.1 christos * The contents of this file are subject to the terms of the
37 1.1 christos * Common Development and Distribution License, Version 1.0 only
38 1.1 christos * (the "License"). You may not use this file except in compliance
39 1.1 christos * with the License.
40 1.1 christos *
41 1.1 christos * You can obtain a copy of the license at Docs/cddl1.txt
42 1.1 christos * or http://www.opensolaris.org/os/licensing.
43 1.1 christos * See the License for the specific language governing permissions
44 1.1 christos * and limitations under the License.
45 1.1 christos *
46 1.1 christos * CDDL HEADER END
47 1.1 christos *
48 1.1 christos * ToDo:
49 1.1 christos * Check write fd for socket, not file.
50 1.1 christos *
51 1.1 christos * 30-Nov-2005 Brendan Gregg Created this.
52 1.1 christos * 20-Apr-2006 " " Last update.
53 1.1 christos */
54 1.1 christos
55 1.1 christos #pragma D option quiet
56 1.1 christos
57 1.1 christos /* browser's execname */
58 1.1 christos inline string BROWSER = "mozilla-bin";
59 1.1 christos
60 1.1 christos /* maximum expected hostname length + "GET http://" */
61 1.1 christos inline int MAX_REQ = 64;
62 1.1 christos
63 1.1 christos dtrace:::BEGIN
64 1.1 christos {
65 1.1 christos printf("Tracing... Hit Ctrl-C to end.\n");
66 1.1 christos }
67 1.1 christos
68 1.1 christos /*
69 1.1 christos * Trace brower request
70 1.1 christos *
71 1.1 christos * This is achieved by matching writes for the browser's execname that
72 1.1 christos * start with "GET", and then timing from the return of the write to
73 1.1 christos * the return of the next read in the same thread. Various stateful flags
74 1.1 christos * are used: self->fd, self->read.
75 1.1 christos *
76 1.1 christos * For performance reasons, I'd like to only process writes that follow a
77 1.1 christos * connect(), however this approach fails to process keepalives.
78 1.1 christos */
79 1.1 christos syscall::write:entry
80 1.1 christos /execname == BROWSER/
81 1.1 christos {
82 1.1 christos self->buf = arg1;
83 1.1 christos self->fd = arg0 + 1;
84 1.1 christos self->nam = "";
85 1.1 christos }
86 1.1 christos
87 1.1 christos syscall::write:return
88 1.1 christos /self->fd/
89 1.1 christos {
90 1.1 christos this->str = (char *)copyin(self->buf, MAX_REQ);
91 1.1 christos this->str[4] = '\0';
92 1.1 christos self->fd = stringof(this->str) == "GET " ? self->fd : 0;
93 1.1 christos }
94 1.1 christos
95 1.1 christos syscall::write:return
96 1.1 christos /self->fd/
97 1.1 christos {
98 1.1 christos /* fetch browser request */
99 1.1 christos this->str = (char *)copyin(self->buf, MAX_REQ);
100 1.1 christos this->str[MAX_REQ] = '\0';
101 1.1 christos
102 1.1 christos /*
103 1.1 christos * This unrolled loop strips down a URL to it's hostname.
104 1.1 christos * We ought to use strtok(), but it's not available on Sol 10 3/05,
105 1.1 christos * so instead I used dirname(). It's not pretty - it's done so that
106 1.1 christos * this works on all Sol 10 versions.
107 1.1 christos */
108 1.1 christos self->req = stringof(this->str);
109 1.1 christos self->nam = strlen(self->req) > 15 ? self->req : self->nam;
110 1.1 christos self->req = dirname(self->req);
111 1.1 christos self->nam = strlen(self->req) > 15 ? self->req : self->nam;
112 1.1 christos self->req = dirname(self->req);
113 1.1 christos self->nam = strlen(self->req) > 15 ? self->req : self->nam;
114 1.1 christos self->req = dirname(self->req);
115 1.1 christos self->nam = strlen(self->req) > 15 ? self->req : self->nam;
116 1.1 christos self->req = dirname(self->req);
117 1.1 christos self->nam = strlen(self->req) > 15 ? self->req : self->nam;
118 1.1 christos self->req = dirname(self->req);
119 1.1 christos self->nam = strlen(self->req) > 15 ? self->req : self->nam;
120 1.1 christos self->req = dirname(self->req);
121 1.1 christos self->nam = strlen(self->req) > 15 ? self->req : self->nam;
122 1.1 christos self->req = dirname(self->req);
123 1.1 christos self->nam = strlen(self->req) > 15 ? self->req : self->nam;
124 1.1 christos self->req = dirname(self->req);
125 1.1 christos self->nam = strlen(self->req) > 15 ? self->req : self->nam;
126 1.1 christos self->nam = basename(self->nam);
127 1.1 christos
128 1.1 christos /* start the timer */
129 1.1 christos start[pid, self->fd - 1] = timestamp;
130 1.1 christos host[pid, self->fd - 1] = self->nam;
131 1.1 christos self->buf = 0;
132 1.1 christos self->fd = 0;
133 1.1 christos self->req = 0;
134 1.1 christos self->nam = 0;
135 1.1 christos }
136 1.1 christos
137 1.1 christos /* this one wasn't a GET */
138 1.1 christos syscall::write:return
139 1.1 christos /self->buf/
140 1.1 christos {
141 1.1 christos self->buf = 0;
142 1.1 christos self->fd = 0;
143 1.1 christos }
144 1.1 christos
145 1.1 christos syscall::read:entry
146 1.1 christos /execname == BROWSER && start[pid, arg0]/
147 1.1 christos {
148 1.1 christos self->fd = arg0 + 1;
149 1.1 christos }
150 1.1 christos
151 1.1 christos /*
152 1.1 christos * Record host details
153 1.1 christos */
154 1.1 christos syscall::read:return
155 1.1 christos /self->fd/
156 1.1 christos {
157 1.1 christos /* fetch details */
158 1.1 christos self->host = stringof(host[pid, self->fd - 1]);
159 1.1 christos this->start = start[pid, self->fd - 1];
160 1.1 christos
161 1.1 christos /* save details */
162 1.1 christos @Avg[self->host] = avg((timestamp - this->start)/1000000);
163 1.1 christos @Max[self->host] = max((timestamp - this->start)/1000000);
164 1.1 christos @Num[self->host] = count();
165 1.1 christos
166 1.1 christos /* clear vars */
167 1.1 christos start[pid, self->fd - 1] = 0;
168 1.1 christos host[pid, self->fd - 1] = 0;
169 1.1 christos self->host = 0;
170 1.1 christos self->fd = 0;
171 1.1 christos }
172 1.1 christos
173 1.1 christos /*
174 1.1 christos * Output report
175 1.1 christos */
176 1.1 christos dtrace:::END
177 1.1 christos {
178 1.1 christos printf("%-32s %11s\n", "HOST", "NUM");
179 1.1 christos printa("%-32s %@11d\n", @Num);
180 1.1 christos
181 1.1 christos printf("\n%-32s %11s\n", "HOST", "AVGTIME(ms)");
182 1.1 christos printa("%-32s %@11d\n", @Avg);
183 1.1 christos
184 1.1 christos printf("\n%-32s %11s\n", "HOST", "MAXTIME(ms)");
185 1.1 christos printa("%-32s %@11d\n", @Max);
186 1.1 christos }
187