1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.performance;
19
20 import java.util.logging.Logger;
21
22 import org.apache.commons.math.random.RandomData;
23 import org.apache.commons.math.random.RandomDataImpl;
24 import org.apache.commons.math.stat.descriptive.SummaryStatistics;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public abstract class ClientThread implements Runnable {
50
51
52
53 private long minDelay;
54
55 private long maxDelay;
56
57 private double sigma;
58
59 private String delayType;
60
61 private long rampPeriod;
62
63 private long peakPeriod;
64
65 private long troughPeriod;
66
67 private final String cycleType;
68
69 private String rampType;
70
71
72 private final long iterations;
73
74
75
76 private long startTime;
77
78 private long periodStart;
79
80 private double lastMean;
81
82 protected static final int RAMPING_UP = 0;
83 protected static final int RAMPING_DOWN = 1;
84 protected static final int PEAK_LOAD = 2;
85 protected static final int TROUGH_LOAD = 3;
86
87 private int cycleState = RAMPING_UP;
88
89 private long numErrors = 0;
90
91 private long numMisses = 0;
92
93
94 protected RandomData randomData = new RandomDataImpl();
95
96 protected Statistics stats;
97
98 protected Logger logger;
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 public ClientThread(long iterations, long minDelay, long maxDelay,
117 double sigma, String delayType, long rampPeriod, long peakPeriod,
118 long troughPeriod, String cycleType,
119 String rampType, Logger logger,
120 Statistics stats) {
121 this.iterations = iterations;
122 this.minDelay = minDelay;
123 this.maxDelay = maxDelay;
124 this.sigma = sigma;
125 this.delayType = delayType;
126 this.peakPeriod = peakPeriod;
127 this.rampPeriod = rampPeriod;
128 this.troughPeriod = troughPeriod;
129 this.cycleType = cycleType;
130 this.rampType = rampType;
131 this.logger = logger;
132 this.stats = stats;
133 }
134
135 public void run() {
136 try {
137 init();
138 } catch (Exception ex) {
139 logger.severe("init failed.");
140 ex.printStackTrace();
141 return;
142 }
143 long start = 0;
144 startTime = System.currentTimeMillis();
145 long lastStart = startTime;
146 periodStart = System.currentTimeMillis();
147 lastMean = (double) maxDelay;
148 SummaryStatistics responseStats = new SummaryStatistics();
149 for (int i = 0; i < iterations; i++) {
150 try {
151 setUp();
152
153
154 long elapsed = System.currentTimeMillis() - lastStart;
155 long nextDelay = nextDelay();
156 if (elapsed > nextDelay) {
157 numMisses++;
158 } else {
159 try {
160 Thread.sleep(nextDelay - elapsed);
161 } catch (InterruptedException ex) {
162 logger.info("Sleep interrupted");
163 }
164 }
165
166
167 start = System.currentTimeMillis();
168 execute();
169 } catch (Exception ex) {
170 ex.printStackTrace();
171 numErrors++;
172 } finally {
173 try {
174 responseStats.addValue(System.currentTimeMillis() - start);
175 lastStart = start;
176 cleanUp();
177 } catch (Exception e) {
178 e.printStackTrace();
179 }
180 }
181 }
182
183 try {
184 finish();
185 } catch (Exception ex) {
186 logger.severe("finalize failed.");
187 ex.printStackTrace();
188 return;
189 }
190
191
192 String process = Thread.currentThread().getName();
193
194
195 stats.addStatistics(responseStats, process, "latency");
196
197
198 logger.info(stats.displayProcessStatistics(process) +
199 "Number of misses: " + numMisses + "\n" +
200 "Number or errors: " + numErrors + "\n");
201 }
202
203
204 protected void init() throws Exception {}
205
206
207 protected void setUp() throws Exception {}
208
209
210 protected void cleanUp() throws Exception {}
211
212
213 protected void finish() throws Exception {}
214
215
216
217
218
219 public abstract void execute() throws Exception;
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309 protected long nextDelay() throws ConfigurationException {
310 double targetDelay = 0;
311 double dMinDelay = (double) minDelay;
312 double dMaxDelay = (double) maxDelay;
313 double delayDifference = dMaxDelay - dMinDelay;
314 long currentTime = System.currentTimeMillis();
315 if (cycleType.equals("none")) {
316 if (rampType.equals("none") ||
317 (currentTime - startTime) > rampPeriod) {
318 targetDelay = dMinDelay;
319 } else if (rampType.equals("linear")) {
320 double prop =
321 (double) (currentTime - startTime) / (double) rampPeriod;
322 targetDelay = dMaxDelay - delayDifference * prop;
323 } else {
324
325
326 double lastProp =
327 (dMaxDelay - lastMean) / delayDifference;
328
329 double prop = randomData.nextUniform(lastProp, 1);
330 targetDelay = dMaxDelay - delayDifference * prop;
331 }
332 } else if (cycleType.equals("oscillating")) {
333
334 adjustState(currentTime);
335 targetDelay = computeCyclicDelay(
336 currentTime, dMinDelay, dMaxDelay);
337 } else {
338 throw new ConfigurationException(
339 "Cycle type not supported: " + cycleType);
340 }
341
342
343 lastMean = targetDelay;
344
345 if (delayType.equals("constant")) {
346 return Math.round(targetDelay);
347 }
348
349
350 if (delayType.equals("gaussian")) {
351 return Math.round(randomData.nextGaussian(targetDelay, sigma));
352 } else {
353 return randomData.nextPoisson(targetDelay);
354 }
355 }
356
357
358
359
360
361
362
363 protected void adjustState(long currentTime) {
364 long timeInPeriod = currentTime - periodStart;
365 if ( ((cycleState == RAMPING_UP || cycleState == RAMPING_DOWN) &&
366 timeInPeriod < rampPeriod) ||
367 (cycleState == PEAK_LOAD && timeInPeriod < peakPeriod) ||
368 (cycleState == TROUGH_LOAD && timeInPeriod < troughPeriod)) {
369 return;
370 }
371 switch (cycleState) {
372 case RAMPING_UP:
373 if (peakPeriod > 0) {
374 cycleState = PEAK_LOAD;
375 } else {
376 cycleState = RAMPING_DOWN;
377 }
378 lastMean = (double) minDelay;
379 periodStart = currentTime;
380 break;
381
382 case RAMPING_DOWN:
383 if (troughPeriod > 0) {
384 cycleState = TROUGH_LOAD;
385 } else {
386 cycleState = RAMPING_UP;
387 }
388 lastMean = (double) maxDelay;
389 periodStart = currentTime;
390 break;
391
392 case PEAK_LOAD:
393 if (rampPeriod > 0) {
394 cycleState = RAMPING_DOWN;
395 lastMean = (double) minDelay;
396 } else {
397 cycleState = TROUGH_LOAD;
398 lastMean = (double) maxDelay;
399 }
400 periodStart = currentTime;
401 break;
402
403 case TROUGH_LOAD:
404 if (rampPeriod > 0) {
405 cycleState = RAMPING_UP;
406 lastMean = (double) maxDelay;
407 } else {
408 cycleState = PEAK_LOAD;
409 lastMean = (double) minDelay;
410 }
411 periodStart = currentTime;
412 break;
413
414 default:
415 throw new IllegalStateException(
416 "Illegal cycle state: " + cycleState);
417 }
418 }
419
420 protected double computeCyclicDelay(
421 long currentTime, double min, double max) {
422
423
424 if (cycleState == PEAK_LOAD) {
425 return min;
426 }
427 if (cycleState == TROUGH_LOAD) {
428 return max;
429 }
430
431
432 if (rampType.equals("none")) {
433 if (cycleState == RAMPING_UP) {
434 return max;
435 } else {
436 return min;
437 }
438 }
439
440
441 double diff = max - min;
442 if (rampType.equals("linear")) {
443 double prop =
444 (double)(currentTime - periodStart) / (double) rampPeriod;
445 if (cycleState == RAMPING_UP) {
446 return max - diff * prop;
447 } else {
448 return min + diff * prop;
449 }
450 } else {
451
452 double lastProp =
453 (max - lastMean) / diff;
454
455 double linearProp =
456 (double)(currentTime - periodStart) / (double) rampPeriod;
457
458
459 if ((cycleState == RAMPING_UP && (lastProp > linearProp)) ||
460 (cycleState == RAMPING_DOWN &&
461 ((1 - lastProp) > linearProp)))
462 lastProp = (cycleState == RAMPING_UP) ? linearProp :
463 (1 - linearProp);
464 double prop = 0;
465 if (cycleState == RAMPING_UP) {
466 prop = randomData.nextUniform(lastProp, 1);
467 } else {
468 prop = randomData.nextUniform(0, lastProp);
469 }
470
471 if (cycleState == RAMPING_UP) {
472 return Math.min(lastMean, max - diff * prop);
473 } else {
474 return Math.max(lastMean, min + diff * prop);
475 }
476 }
477 }
478
479 public long getMinDelay() {
480 return minDelay;
481 }
482
483 public long getMaxDelay() {
484 return maxDelay;
485 }
486
487 public double getSigma() {
488 return sigma;
489 }
490
491 public String getDelayType() {
492 return delayType;
493 }
494
495 public long getRampPeriod() {
496 return rampPeriod;
497 }
498
499 public long getPeakPeriod() {
500 return peakPeriod;
501 }
502
503 public long getTroughPeriod() {
504 return troughPeriod;
505 }
506
507 public String getCycleType() {
508 return cycleType;
509 }
510
511 public String getRampType() {
512 return rampType;
513 }
514
515 public long getIterations() {
516 return iterations;
517 }
518
519 public long getStartTime() {
520 return startTime;
521 }
522
523 public long getPeriodStart() {
524 return periodStart;
525 }
526
527 public double getLastMean() {
528 return lastMean;
529 }
530
531 public int getCycleState() {
532 return cycleState;
533 }
534
535 public long getNumErrors() {
536 return numErrors;
537 }
538
539 public long getNumMisses() {
540 return numMisses;
541 }
542
543 public Statistics getStats() {
544 return stats;
545 }
546
547 public void setStartTime(long startTime) {
548 this.startTime = startTime;
549 }
550
551 public void setPeriodStart(long periodStart) {
552 this.periodStart = periodStart;
553 }
554
555 public void setLastMean(double lastMean) {
556 this.lastMean = lastMean;
557 }
558
559 public void setCycleState(int cycleState) {
560 this.cycleState = cycleState;
561 }
562
563 public void setNumErrors(long numErrors) {
564 this.numErrors = numErrors;
565 }
566
567 public void setNumMisses(long numMisses) {
568 this.numMisses = numMisses;
569 }
570
571 public void setRampType(String rampType) {
572 this.rampType = rampType;
573 }
574
575 public void setMinDelay(long minDelay) {
576 this.minDelay = minDelay;
577 }
578
579 public void setMaxDelay(long maxDelay) {
580 this.maxDelay = maxDelay;
581 }
582
583 public void setSigma(double sigma) {
584 this.sigma = sigma;
585 }
586
587 public void setDelayType(String delayType) {
588 this.delayType = delayType;
589 }
590
591 public void setRampPeriod(long rampPeriod) {
592 this.rampPeriod = rampPeriod;
593 }
594
595 public void setPeakPeriod(long peakPeriod) {
596 this.peakPeriod = peakPeriod;
597 }
598
599 public void setTroughPeriod(long troughPeriod) {
600 this.troughPeriod = troughPeriod;
601 }
602
603 }