Rev 1127 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1127 | dev | 1 | package ak.httpbench; |
2 | |||
1128 | dev | 3 | import java.util.List; |
4 | import java.util.ArrayList; |
||
5 | |||
1127 | dev | 6 | import org.apache.commons.logging.Log; |
7 | import org.apache.commons.logging.LogFactory; |
||
8 | |||
9 | import org.apache.commons.httpclient.HttpClient; |
||
10 | import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; |
||
11 | import org.apache.commons.httpclient.methods.GetMethod; |
||
12 | |||
13 | public class HttpBench |
||
14 | { |
||
1128 | dev | 15 | private static Log log = LogFactory.getLog(HttpBench.class); |
16 | |||
1127 | dev | 17 | public static void main(String[] args) |
18 | throws Exception |
||
19 | { |
||
1128 | dev | 20 | HttpBench hb = new HttpBench(); |
21 | |||
22 | if(hb.parseParams(args)) |
||
23 | hb.run(); |
||
1127 | dev | 24 | } |
1128 | dev | 25 | |
26 | // config |
||
27 | private int threadNumber = 10; |
||
28 | private int requestNumber = 50; |
||
29 | private int requestPerConnection = 0; |
||
30 | private int sleepMin = 0; |
||
31 | private int sleepMax = 1000; // 1s |
||
32 | private int timeout = 60000; // 1min |
||
33 | private String firstUrl = null; |
||
34 | private List urls = new ArrayList(); |
||
35 | |||
36 | private int parseInt(String s, String prefix, String errorMsg) |
||
37 | throws Exception |
||
38 | { |
||
39 | try { |
||
40 | return Integer.parseInt(s.substring(prefix.length())); |
||
41 | } |
||
42 | catch(Exception ex) { |
||
43 | log.error(errorMsg); |
||
44 | throw ex; |
||
45 | } |
||
46 | } |
||
47 | |||
48 | private boolean parseParams(String[] args) |
||
49 | throws Exception |
||
50 | { |
||
51 | try { |
||
52 | for(int i = 0; i< args.length; i++) { |
||
53 | String s = args[i]; |
||
54 | if(s.startsWith("thr=")) { |
||
55 | threadNumber = parseInt(s, "thr=", |
||
56 | "Cannot get number of threads from " + s); |
||
57 | } |
||
58 | else if(s.startsWith("req=")) { |
||
59 | requestNumber = parseInt(s, "req=", |
||
60 | "Cannot get number of requests from " + s); |
||
61 | } |
||
62 | else if(s.startsWith("rpc=")) { |
||
63 | requestPerConnection = parseInt(s, "rpc=", |
||
64 | "Cannot get number of requests per connection from " + s); |
||
65 | } |
||
66 | else if(s.startsWith("sleepMin=")) { |
||
67 | sleepMin = parseInt(s, "sleepMin=", |
||
68 | "Cannot get min sleep from " + s); |
||
69 | } |
||
70 | else if(s.startsWith("timeout=")) { |
||
71 | timeout = parseInt(s, "timeout=", |
||
72 | "Cannot get timeout from " + s); |
||
73 | } |
||
74 | else if(s.startsWith("sleepMax=")) { |
||
75 | sleepMax = parseInt(s, "sleepMax=", |
||
76 | "Cannot get max sleep from " + s); |
||
77 | } |
||
78 | else if(s.startsWith("firstUrl=")) { |
||
79 | firstUrl = s.substring("firstUrl=".length()); |
||
80 | if(firstUrl.equals("")) firstUrl = null; |
||
81 | } |
||
82 | else { |
||
83 | urls.add(s); |
||
84 | } |
||
85 | } |
||
86 | |||
87 | if(urls.isEmpty()) { |
||
88 | log.error("Need at least one URL to work"); |
||
89 | return false; |
||
90 | } |
||
91 | |||
92 | return true; |
||
93 | } |
||
94 | catch(Exception ex) { |
||
95 | return false; |
||
96 | } |
||
97 | } |
||
98 | |||
99 | private void run() |
||
100 | throws Exception |
||
101 | { |
||
102 | log.info("start " + threadNumber + "/" + requestNumber + "/" + requestPerConnection |
||
103 | + " " + sleepMin + "/" + sleepMax); |
||
104 | log.info(" firstUrl: " + (firstUrl == null ? "<null>" : firstUrl)); |
||
105 | for(int i = 0; i < urls.size(); i++) |
||
106 | log.info(" url: " + urls.get(i)); |
||
107 | |||
108 | List threads = new ArrayList(); |
||
109 | List workers = new ArrayList(); |
||
110 | String[] urlArray = (String[])urls.toArray(new String[] {}); |
||
111 | |||
112 | for(int i = 0; i < threadNumber; i++) { |
||
113 | log.debug("create thread " + i); |
||
114 | |||
115 | HttpThread ht = new HttpThread(firstUrl, urlArray); |
||
116 | workers.add(ht); |
||
117 | ht.setRequestNumber(requestNumber); |
||
118 | ht.setRequestPerConnection(requestPerConnection); |
||
119 | ht.setSleepMin(sleepMin); |
||
120 | ht.setSleepMax(sleepMax); |
||
121 | ht.setTimeout(timeout); |
||
122 | |||
123 | Thread t = new Thread(ht); |
||
124 | threads.add(t); |
||
125 | t.start(); |
||
126 | } |
||
127 | |||
128 | // wait for all |
||
129 | for(int i = 0; i < threads.size(); i++) { |
||
130 | log.debug("wait for thread " + i); |
||
131 | |||
132 | Thread t = (Thread)threads.get(i); |
||
133 | try { |
||
134 | t.join(); |
||
135 | } |
||
136 | catch(InterruptedException ex) { |
||
137 | } |
||
138 | } |
||
139 | |||
140 | // statistics |
||
141 | long totalTime = 0; |
||
142 | long reqTime = 0; |
||
143 | long minTime = Long.MAX_VALUE; |
||
144 | long maxTime = -1; |
||
145 | int successRequest = 0; |
||
146 | int failRequest = 0; |
||
147 | for(int i = 0; i < workers.size(); i++) { |
||
148 | HttpThread ht = (HttpThread)workers.get(i); |
||
149 | if(ht.getSuccess()) { |
||
150 | totalTime += ht.getRunTime(); |
||
151 | |||
152 | List results = ht.getResults(); |
||
153 | for(int j = 0; j < results.size(); j++) { |
||
154 | RequestResult r = (RequestResult)results.get(j); |
||
155 | totalTime -= r.sleepBefore; |
||
156 | if(r.success) { |
||
157 | successRequest++; |
||
158 | |||
159 | long t = r.stopTime - r.startTime; |
||
160 | reqTime += t; |
||
161 | if(minTime > t) minTime = t; |
||
162 | if(maxTime < t) maxTime = t; |
||
163 | } |
||
164 | else { |
||
165 | failRequest++; |
||
166 | } |
||
167 | } |
||
168 | } |
||
169 | } |
||
170 | |||
171 | log.info("done " + totalTime + "ms / " + successRequest + " = " |
||
172 | + (totalTime / successRequest) + "ms " |
||
173 | + minTime + "/" + (reqTime / successRequest) + "/" + maxTime |
||
174 | + " ms, " + failRequest + " failed"); |
||
175 | } |
||
1127 | dev | 176 | } |
177 | |||
1128 | dev | 178 | class RequestResult |
1127 | dev | 179 | { |
1128 | dev | 180 | public boolean success = false; |
181 | public String url; |
||
182 | public long sleepBefore; |
||
183 | public long startTime; |
||
184 | public long stopTime; |
||
185 | public int code; |
||
186 | public Exception exception; |
||
187 | } |
||
188 | |||
189 | class HttpThread implements Runnable |
||
190 | { |
||
1127 | dev | 191 | private static int threadCount = 0; |
192 | private static Log log = LogFactory.getLog(HttpThread.class); |
||
193 | |||
194 | private int id; |
||
195 | private String firstUrl; // is used one time only, may be null |
||
196 | private String[] urls; |
||
197 | private int requestNumber = 1; |
||
198 | private int requestPerConnection = 0; // 0 == all |
||
199 | private int sleepMin = 0; |
||
200 | private int sleepMax = 0; |
||
1128 | dev | 201 | private int timeout = 0; |
1127 | dev | 202 | |
1128 | dev | 203 | private boolean success; |
204 | private long runTime; |
||
205 | private List results; |
||
206 | |||
1127 | dev | 207 | public HttpThread(String firstUrl, String[] urls) |
208 | { |
||
209 | id = threadCount++; |
||
210 | this.firstUrl = firstUrl; |
||
211 | this.urls = urls; |
||
212 | } |
||
213 | |||
214 | public int getId() |
||
215 | { |
||
216 | return id; |
||
217 | } |
||
218 | |||
219 | public int getRequestNumber() |
||
220 | { |
||
221 | return requestNumber; |
||
222 | } |
||
223 | |||
224 | public void setRequestNumber(int requestNumber) |
||
225 | { |
||
226 | this.requestNumber = requestNumber; |
||
227 | } |
||
228 | |||
229 | public int getRequestPerConnection() |
||
230 | { |
||
231 | return requestPerConnection; |
||
232 | } |
||
233 | |||
234 | public void setRequestPerConnection(int requestPerConnection) |
||
235 | { |
||
236 | this.requestPerConnection = requestPerConnection; |
||
237 | } |
||
238 | |||
239 | public void setSleepMin(int sleepMin) |
||
240 | { |
||
241 | this.sleepMin = sleepMin; |
||
242 | } |
||
243 | |||
244 | public int getSleepMax() |
||
245 | { |
||
246 | return sleepMax; |
||
247 | } |
||
248 | |||
249 | public void setSleepMax(int sleepMax) |
||
250 | { |
||
251 | this.sleepMax = sleepMax; |
||
252 | } |
||
253 | |||
1128 | dev | 254 | public int getTimeout() |
255 | { |
||
256 | return timeout; |
||
257 | } |
||
258 | |||
259 | public void setTimeout(int timeout) |
||
260 | { |
||
261 | this.timeout = timeout; |
||
262 | } |
||
263 | |||
264 | public boolean getSuccess() |
||
265 | { |
||
266 | return success; |
||
267 | } |
||
268 | |||
269 | public long getRunTime() |
||
270 | { |
||
271 | return runTime; |
||
272 | } |
||
273 | |||
274 | public List getResults() |
||
275 | { |
||
276 | return results; |
||
277 | } |
||
278 | |||
1127 | dev | 279 | public void run() |
280 | { |
||
1128 | dev | 281 | long sumSleep = 0; |
1127 | dev | 282 | log.info(Integer.toString(id) + ": start"); |
283 | |||
284 | try { |
||
285 | HttpClient client = new HttpClient(); |
||
286 | |||
1128 | dev | 287 | results = new ArrayList(); |
1127 | dev | 288 | for(int i = 0; i < requestNumber; i++) { |
1128 | dev | 289 | results.add(new RequestResult()); |
290 | } |
||
291 | |||
292 | long startTime = System.currentTimeMillis(); |
||
293 | for(int i = 0; i < requestNumber; i++) { |
||
294 | RequestResult result = (RequestResult)results.get(i); |
||
295 | |||
296 | if(sleepMax > 0) { |
||
297 | long sleep = (long)(Math.random() * (sleepMax - sleepMin)) + sleepMin; |
||
298 | sumSleep += sleep; |
||
299 | result.sleepBefore = sleep; |
||
300 | log.trace(Integer.toString(id) + ": sleep for " + sleep + "ms"); |
||
301 | Thread.sleep(sleep); |
||
302 | } |
||
303 | |||
1127 | dev | 304 | if(i == 0 && firstUrl != null) |
1128 | dev | 305 | result.url = firstUrl; |
1127 | dev | 306 | else |
1128 | dev | 307 | result.url = urls[(firstUrl == null ? i : i-1) % urls.length]; |
1127 | dev | 308 | |
1128 | dev | 309 | GetMethod get = new GetMethod(result.url); |
310 | get.getParams().setSoTimeout(timeout); |
||
1127 | dev | 311 | |
312 | try { |
||
1128 | dev | 313 | result.startTime = System.currentTimeMillis(); |
314 | result.code = client.executeMethod(get); |
||
315 | result.stopTime = System.currentTimeMillis(); |
||
316 | result.success = true; |
||
317 | |||
1127 | dev | 318 | if(log.isTraceEnabled()) { |
319 | String response = get.getResponseBodyAsString(); |
||
1128 | dev | 320 | log.trace(Integer.toString(id) + ": got " + result |
321 | + " in " + (result.stopTime - result.startTime) |
||
322 | + "ms \n'" + response.substring(0, 100) + "'"); |
||
1127 | dev | 323 | } |
324 | else if(log.isDebugEnabled()) { |
||
1128 | dev | 325 | log.debug(Integer.toString(id) + ": got " + result |
326 | + " in " + (result.stopTime - result.startTime) + "ms"); |
||
1127 | dev | 327 | } |
328 | } |
||
1128 | dev | 329 | catch(Exception ex) { |
330 | result.stopTime = System.currentTimeMillis(); |
||
331 | result.exception = ex; |
||
332 | } |
||
1127 | dev | 333 | finally { |
334 | get.releaseConnection(); |
||
335 | } |
||
336 | |||
337 | if(requestPerConnection > 0 && (i+1) % requestPerConnection == 0 |
||
338 | && i < requestNumber-1) |
||
339 | { |
||
340 | log.debug(Integer.toString(id) |
||
341 | + ": request per connection limit reached at " + i); |
||
342 | client.getHttpConnectionManager().closeIdleConnections(0); |
||
343 | } |
||
344 | } |
||
345 | |||
346 | client.getHttpConnectionManager().closeIdleConnections(0); |
||
1128 | dev | 347 | success = true; |
348 | runTime = System.currentTimeMillis() - startTime; |
||
1127 | dev | 349 | } |
350 | catch(Exception ex) { |
||
1128 | dev | 351 | success = false; |
1127 | dev | 352 | log.warn(Integer.toString(id), ex); |
353 | } |
||
354 | |||
1128 | dev | 355 | log.info(Integer.toString(id) + ": done" + (success ? " " + runTime |
356 | + "/" + sumSleep + "/" + (runTime - sumSleep) + " ms": " with error")); |
||
1127 | dev | 357 | } |
358 | } |
||
359 |