1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package net.grinder.statistics;
23
24 import java.io.IOException;
25 import java.io.ObjectInput;
26 import java.io.ObjectOutput;
27 import java.util.Arrays;
28
29 import net.grinder.statistics.StatisticsIndexMap.DoubleIndex;
30 import net.grinder.statistics.StatisticsIndexMap.DoubleSampleIndex;
31 import net.grinder.statistics.StatisticsIndexMap.LongIndex;
32 import net.grinder.statistics.StatisticsIndexMap.LongSampleIndex;
33 import net.grinder.statistics.StatisticsIndexMap.SampleIndex;
34 import net.grinder.util.Serialiser;
35
36
37
38
39
40
41
42
43
44 final class StatisticsSetImplementation implements StatisticsSet {
45
46 private final StatisticsIndexMap m_statisticsIndexMap;
47 private final long[] m_longData;
48 private final double[] m_doubleData;
49
50
51
52 private transient long[] m_transientLongData;
53
54
55 private boolean m_zero = true;
56
57 private boolean m_composite;
58
59
60
61
62
63
64 StatisticsSetImplementation(StatisticsIndexMap statisticsIndexMap) {
65 m_statisticsIndexMap = statisticsIndexMap;
66 m_longData = new long[m_statisticsIndexMap.getNumberOfLongs()];
67 m_doubleData = new double[m_statisticsIndexMap.getNumberOfDoubles()];
68 m_transientLongData =
69 new long[m_statisticsIndexMap.getNumberOfTransientLongs()];
70 }
71
72
73
74
75
76 public synchronized void reset() {
77 if (!m_zero) {
78 Arrays.fill(m_longData, 0);
79 Arrays.fill(m_doubleData, 0);
80 Arrays.fill(m_transientLongData, 0);
81 m_zero = true;
82 m_composite = false;
83 }
84 }
85
86
87
88
89
90
91
92
93
94
95
96 public synchronized StatisticsSet snapshot() {
97 final StatisticsSetImplementation result =
98 new StatisticsSetImplementation(m_statisticsIndexMap);
99
100 if (!m_zero) {
101 synchronized (result) {
102 System.arraycopy(m_longData,
103 0,
104 result.m_longData,
105 0,
106 result.m_longData.length);
107
108 System.arraycopy(m_doubleData,
109 0,
110 result.m_doubleData,
111 0,
112 result.m_doubleData.length);
113
114 System.arraycopy(m_transientLongData,
115 0,
116 result.m_transientLongData,
117 0, result.m_transientLongData.length);
118
119 result.m_zero = false;
120 result.m_composite = m_composite;
121 }
122 }
123
124 return result;
125 }
126
127
128
129
130
131
132
133
134
135
136 public synchronized long getValue(LongIndex index) {
137 if (index.isTransient()) {
138 return m_transientLongData[index.getValue()];
139 }
140
141 return m_longData[index.getValue()];
142 }
143
144
145
146
147
148
149
150
151
152
153 public synchronized double getValue(DoubleIndex index) {
154 return m_doubleData[index.getValue()];
155 }
156
157
158
159
160
161
162
163
164
165
166 public synchronized void setValue(LongIndex index, long value) {
167 if (index.isTransient()) {
168 m_transientLongData[index.getValue()] = value;
169 }
170 else {
171 m_longData[index.getValue()] = value;
172 }
173
174 m_zero &= value == 0;
175 }
176
177
178
179
180
181
182
183
184
185
186 public synchronized void setValue(DoubleIndex index, double value) {
187 m_doubleData[index.getValue()] = value;
188 m_zero &= value == 0;
189 }
190
191
192
193
194
195
196
197
198
199
200 public synchronized void addValue(LongIndex index, long value) {
201 if (!index.isTransient()) {
202 m_longData[index.getValue()] += value;
203 m_zero &= value == 0;
204 }
205 }
206
207
208
209
210
211
212
213
214
215
216 public synchronized void addValue(DoubleIndex index, double value) {
217
218 m_doubleData[index.getValue()] += value;
219 m_zero &= value == 0;
220 }
221
222
223
224
225
226
227
228
229 public synchronized void addSample(LongSampleIndex index, long value) {
230
231 setValue(index.getVarianceIndex(),
232 calculateVariance(getValue(index.getSumIndex()),
233 getValue(index.getCountIndex()),
234 getValue(index.getVarianceIndex()),
235 value));
236
237 m_longData[index.getSumIndex().getValue()] += value;
238 ++m_longData[index.getCountIndex().getValue()];
239 m_zero = false;
240 }
241
242
243
244
245
246
247
248
249 public synchronized void addSample(DoubleSampleIndex index, double value) {
250
251 setValue(index.getVarianceIndex(),
252 calculateVariance(getValue(index.getSumIndex()),
253 getValue(index.getCountIndex()),
254 getValue(index.getVarianceIndex()),
255 value));
256
257 m_doubleData[index.getSumIndex().getValue()] += value;
258 ++m_longData[index.getCountIndex().getValue()];
259 m_zero = false;
260 }
261
262
263
264
265
266
267 public synchronized void reset(LongSampleIndex index) {
268 setValue(index.getSumIndex(), 0);
269 setValue(index.getCountIndex(), 0);
270 setValue(index.getVarianceIndex(), 0);
271 }
272
273
274
275
276
277
278 public synchronized void reset(DoubleSampleIndex index) {
279 setValue(index.getSumIndex(), 0);
280 setValue(index.getCountIndex(), 0);
281 setValue(index.getVarianceIndex(), 0);
282 }
283
284
285
286
287
288
289
290
291
292
293
294
295 private double calculateVariance(double sum,
296 long count,
297 double variance,
298 double newValue) {
299 if (count == 0) {
300 return 0;
301 }
302
303 final long t1 = count + 1;
304 final double t2 = newValue - sum / count;
305
306 return
307 (count * variance) / (count + 1) +
308 (count / (double)(t1 * t1)) * t2 * t2;
309 }
310
311
312
313
314
315
316
317
318
319
320
321
322 private double calculateVariance(double s1, long n1, double v1,
323 double s2, long n2, double v2) {
324 if (n1 == 0) {
325 return v2;
326 }
327 else if (n2 == 0) {
328 return v1;
329 }
330
331 final double s = s1 + s2;
332 final long n = n1 + n2;
333
334 final double term1 = s1 / n1 - s / n;
335 final double term2 = s2 / n2 - s / n;
336
337 return (n1 * (term1 * term1 + v1) + n2 * (term2 * term2 + v2)) / n;
338 }
339
340
341
342
343
344
345
346
347 public long getSum(LongSampleIndex index) {
348 return getValue(index.getSumIndex());
349 }
350
351
352
353
354
355
356
357
358 public double getSum(DoubleSampleIndex index) {
359 return getValue(index.getSumIndex());
360 }
361
362
363
364
365
366
367
368
369 public long getCount(SampleIndex index) {
370 return getValue(index.getCountIndex());
371 }
372
373
374
375
376
377
378
379
380 public double getVariance(SampleIndex index) {
381 return getValue(index.getVarianceIndex());
382 }
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400 public synchronized void add(ImmutableStatisticsSet operand) {
401
402 final StatisticsSetImplementation operandImplementation =
403 (StatisticsSetImplementation)operand;
404
405 final boolean[] isVarianceIndex = new boolean[m_doubleData.length];
406
407 for (LongSampleIndex index : m_statisticsIndexMap.getLongSampleIndicies()) {
408 final LongIndex sumIndex = index.getSumIndex();
409 final LongIndex countIndex = index.getCountIndex();
410 final DoubleIndex varianceIndex = index.getVarianceIndex();
411
412 setValue(varianceIndex,
413 calculateVariance(getValue(sumIndex),
414 getValue(countIndex),
415 getValue(varianceIndex),
416 operand.getValue(sumIndex),
417 operand.getValue(countIndex),
418 operand.getValue(varianceIndex)));
419
420 isVarianceIndex[varianceIndex.getValue()] = true;
421 }
422
423 for (DoubleSampleIndex index :
424 m_statisticsIndexMap.getDoubleSampleIndicies()) {
425
426 final DoubleIndex sumIndex = index.getSumIndex();
427 final LongIndex countIndex = index.getCountIndex();
428 final DoubleIndex varianceIndex = index.getVarianceIndex();
429
430 setValue(varianceIndex,
431 calculateVariance(getValue(sumIndex),
432 getValue(countIndex),
433 getValue(varianceIndex),
434 operand.getValue(sumIndex),
435 operand.getValue(countIndex),
436 operand.getValue(varianceIndex)));
437
438 isVarianceIndex[varianceIndex.getValue()] = true;
439 }
440
441 final long[] longData = operandImplementation.m_longData;
442
443 for (int i = 0; i < longData.length; i++) {
444 m_longData[i] += longData[i];
445 }
446
447 final double[] doubleData = operandImplementation.m_doubleData;
448
449 for (int i = 0; i < doubleData.length; i++) {
450 if (!isVarianceIndex[i]) {
451 m_doubleData[i] += doubleData[i];
452 }
453 }
454
455 m_zero = false;
456
457 if (operand.isComposite()) {
458 setIsComposite();
459 }
460 }
461
462 public synchronized boolean isZero() {
463 return m_zero;
464 }
465
466 public synchronized boolean isComposite() {
467 return m_composite;
468 }
469
470 public synchronized void setIsComposite() {
471 m_composite = true;
472 }
473
474
475
476
477
478
479
480 public synchronized boolean equals(Object o) {
481 if (o == this) {
482 return true;
483 }
484
485 if (o == null || o.getClass() != StatisticsSetImplementation.class) {
486 return false;
487 }
488
489 final StatisticsSetImplementation otherStatistics =
490 (StatisticsSetImplementation)o;
491
492 synchronized (otherStatistics) {
493
494 if (m_composite != otherStatistics.m_composite) {
495 return false;
496 }
497
498 final long[] otherLongData = otherStatistics.m_longData;
499
500 for (int i = 0; i < m_longData.length; i++) {
501 if (m_longData[i] != otherLongData[i]) {
502 return false;
503 }
504 }
505
506 for (int i = 0; i < m_doubleData.length; i++) {
507 if (m_doubleData[i] != otherStatistics.m_doubleData[i]) {
508 return false;
509 }
510 }
511
512 final long[] otherTransientLongData = otherStatistics.m_transientLongData;
513
514 for (int i = 0; i < m_transientLongData.length; i++) {
515 if (m_transientLongData[i] != otherTransientLongData[i]) {
516 return false;
517 }
518 }
519 }
520
521 return true;
522 }
523
524
525
526
527
528
529
530
531
532 public int hashCode() {
533 long result = 0;
534
535 for (int i = 0; i < m_longData.length; i++) {
536 result ^= m_longData[i];
537 }
538
539 for (int i = 0; i < m_doubleData.length; i++) {
540 result ^= Double.doubleToRawLongBits(m_doubleData[i]);
541 }
542
543 for (int i = 0; i < m_transientLongData.length; i++) {
544 result ^= m_transientLongData[i];
545 }
546
547 return (int)(result ^ (result >> 32));
548 }
549
550
551
552
553
554
555
556 public synchronized String toString() {
557 final StringBuilder result = new StringBuilder();
558
559 result.append("StatisticsSet = {{");
560
561 for (int i = 0; i < m_longData.length; i++) {
562 if (i != 0) {
563 result.append(", ");
564 }
565
566 result.append(m_longData[i]);
567 }
568
569 result.append("}, {");
570
571 for (int i = 0; i < m_doubleData.length; i++) {
572 if (i != 0) {
573 result.append(", ");
574 }
575
576 result.append(m_doubleData[i]);
577 }
578
579 result.append("}, {");
580
581 for (int i = 0; i < m_transientLongData.length; i++) {
582 if (i != 0) {
583 result.append(", ");
584 }
585
586 result.append(m_transientLongData[i]);
587 }
588
589 result.append("}, composite = ");
590 result.append(m_composite ? "true" : "false");
591 result.append("}");
592
593 return result.toString();
594 }
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621 synchronized void writeExternal(ObjectOutput out, Serialiser serialiser)
622 throws IOException {
623 for (int i = 0; i < m_longData.length; i++) {
624 serialiser.writeLong(out, m_longData[i]);
625 }
626
627 for (int i = 0; i < m_doubleData.length; i++) {
628 serialiser.writeDouble(out, m_doubleData[i]);
629 }
630
631 out.writeBoolean(m_composite);
632 }
633
634
635
636
637
638
639
640
641
642
643
644
645
646 StatisticsSetImplementation(StatisticsIndexMap statisticsIndexMap,
647 ObjectInput in, Serialiser serialiser)
648 throws IOException {
649 this(statisticsIndexMap);
650
651 for (int i = 0; i < m_longData.length; i++) {
652 m_longData[i] = serialiser.readLong(in);
653 m_zero &= m_longData[i] == 0;
654 }
655
656 for (int i = 0; i < m_doubleData.length; i++) {
657 m_doubleData[i] = serialiser.readDouble(in);
658 m_zero &= m_doubleData[i] == 0;
659 }
660
661 m_composite = in.readBoolean();
662 }
663 }