Mercurial > hg > graal-compiler
comparison graal/com.oracle.max.base/src/com/sun/max/profile/ValueMetrics.java @ 3733:e233f5660da4
Added Java files from Maxine project.
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Sat, 17 Dec 2011 19:59:18 +0100 |
parents | |
children | bc8527f3071c |
comparison
equal
deleted
inserted
replaced
3732:3e2e8b8abdaf | 3733:e233f5660da4 |
---|---|
1 /* | |
2 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 */ | |
23 package com.sun.max.profile; | |
24 | |
25 import java.util.*; | |
26 import java.util.Arrays; | |
27 | |
28 import com.sun.max.*; | |
29 import com.sun.max.profile.Metrics.*; | |
30 import com.sun.max.program.*; | |
31 | |
32 /** | |
33 * This class is a container for a number of inner classes that support recording | |
34 * metrics about the distribution (i.e. frequency) of values. For example, | |
35 * these utilities can be used to gather the distribution of compilation times, | |
36 * object sizes, heap allocations, etc. Several different distribution implementations | |
37 * are available, with different time and space tradeoffs and different approximations, | |
38 * ranging from exact distributions to only distributions within a limited range. | |
39 */ | |
40 public class ValueMetrics { | |
41 | |
42 public static final Approximation EXACT = new Approximation(); | |
43 public static final Approximation TRACE = new IntegerTraceApproximation(1024); | |
44 | |
45 public static class Approximation { | |
46 } | |
47 | |
48 public static class FixedApproximation extends Approximation { | |
49 protected final Object[] values; | |
50 public FixedApproximation(Object... values) { | |
51 this.values = values.clone(); | |
52 } | |
53 } | |
54 | |
55 public static class IntegerRangeApproximation extends Approximation { | |
56 protected final int lowValue; | |
57 protected final int highValue; | |
58 public IntegerRangeApproximation(int low, int high) { | |
59 lowValue = low; | |
60 highValue = high; | |
61 } | |
62 } | |
63 | |
64 public static class IntegerTraceApproximation extends Approximation { | |
65 protected final int bufferSize; | |
66 public IntegerTraceApproximation(int bufferSize) { | |
67 this.bufferSize = bufferSize; | |
68 } | |
69 } | |
70 | |
71 /** | |
72 * This class and its descendants allow recording of a distribution of integer values. | |
73 * Various implementations implement different approximations with different time and | |
74 * space tradeoffs. Because this class and its descendants record distributions only | |
75 * for integers, it can be more efficient than using boxed (e.g. {@code java.lang.Integer}) values. | |
76 * | |
77 */ | |
78 public abstract static class IntegerDistribution extends Distribution<Integer> { | |
79 | |
80 public abstract void record(int value); | |
81 } | |
82 | |
83 public static class FixedRangeIntegerDistribution extends IntegerDistribution { | |
84 protected final int lowValue; | |
85 protected final int[] counts; | |
86 protected int missed; | |
87 | |
88 public FixedRangeIntegerDistribution(int low, int high) { | |
89 lowValue = low; | |
90 counts = new int[high - low]; | |
91 } | |
92 | |
93 @Override | |
94 public void record(int value) { | |
95 total++; | |
96 final int index = value - lowValue; | |
97 if (index >= 0 && index < counts.length) { | |
98 counts[index]++; | |
99 } else { | |
100 missed++; | |
101 } | |
102 } | |
103 | |
104 @Override | |
105 public int getCount(Integer value) { | |
106 final int index = value - lowValue; | |
107 if (index >= 0 && index < counts.length) { | |
108 return counts[index]; | |
109 } | |
110 return missed > 0 ? -1 : 0; | |
111 } | |
112 | |
113 @Override | |
114 public Map<Integer, Integer> asMap() { | |
115 final Map<Integer, Integer> map = new HashMap<Integer, Integer>(); | |
116 for (int i = 0; i != counts.length; ++i) { | |
117 map.put(lowValue + i, counts[i]); | |
118 } | |
119 return map; | |
120 } | |
121 | |
122 @Override | |
123 public void reset() { | |
124 super.reset(); | |
125 missed = 0; | |
126 Arrays.fill(counts, 0); | |
127 } | |
128 } | |
129 | |
130 public static class FixedSetIntegerDistribution extends IntegerDistribution { | |
131 | |
132 private final int[] set; | |
133 private final int[] count; | |
134 protected int missed; | |
135 | |
136 public FixedSetIntegerDistribution(int[] set) { | |
137 // TODO: sort() and binarySearch for large sets. | |
138 this.set = set.clone(); | |
139 count = new int[set.length]; | |
140 } | |
141 | |
142 @Override | |
143 public void record(int value) { | |
144 total++; | |
145 for (int i = 0; i < set.length; i++) { | |
146 if (set[i] == value) { | |
147 count[i]++; | |
148 return; | |
149 } | |
150 } | |
151 missed++; | |
152 } | |
153 | |
154 @Override | |
155 public int getCount(Integer value) { | |
156 final int val = value; | |
157 for (int i = 0; i < set.length; i++) { | |
158 if (set[i] == val) { | |
159 return count[i]; | |
160 } | |
161 } | |
162 return missed > 0 ? -1 : 0; | |
163 } | |
164 | |
165 @Override | |
166 public Map<Integer, Integer> asMap() { | |
167 final Map<Integer, Integer> map = new HashMap<Integer, Integer>(); | |
168 for (int i = 0; i != count.length; ++i) { | |
169 map.put(set[i], count[i]); | |
170 } | |
171 return map; | |
172 } | |
173 | |
174 @Override | |
175 public void reset() { | |
176 super.reset(); | |
177 missed = 0; | |
178 Arrays.fill(set, 0); | |
179 Arrays.fill(count, 0); | |
180 } | |
181 } | |
182 | |
183 /** | |
184 * The trace integer distribution class collects an exact distribution of integer | |
185 * values by internally recording every integer value in order in a fixed size buffer. | |
186 * When the buffer fills up, its contents are sorted and then reduced into a | |
187 * sorted list of value/count pairs. This results in an exact distribution | |
188 * with a tunable size/performance tradeoff, since a larger buffer means | |
189 * fewer reduction steps. | |
190 * | |
191 * This implementation is <b>not thread safe</b>. It may lose updates and potentially | |
192 * generate exceptions if used in a multi-threaded scenario. To make updates | |
193 * to this distribution thread safe, {@linkplain ValueMetrics#threadSafe(IntegerDistribution) wrap} | |
194 * it with a {@link ThreadsafeIntegerDistribution}. | |
195 * | |
196 */ | |
197 public static class TraceIntegerDistribution extends IntegerDistribution { | |
198 private final int[] buffer; | |
199 private int cursor; | |
200 | |
201 private int[] values; | |
202 private int[] counts; | |
203 | |
204 public TraceIntegerDistribution(int bufferSize) { | |
205 assert bufferSize > 0; | |
206 buffer = new int[bufferSize]; | |
207 } | |
208 | |
209 @Override | |
210 public void record(int value) { | |
211 total++; | |
212 buffer[cursor++] = value; | |
213 if (cursor == buffer.length) { | |
214 reduce(); | |
215 } | |
216 } | |
217 | |
218 @Override | |
219 public int getCount(Integer value) { | |
220 reduce(); | |
221 final int index = Arrays.binarySearch(values, value); | |
222 if (index < 0) { | |
223 return 0; | |
224 } | |
225 return counts[index]; | |
226 } | |
227 | |
228 @Override | |
229 public Map<Integer, Integer> asMap() { | |
230 reduce(); | |
231 // TODO: another map implementation might be better. | |
232 final Map<Integer, Integer> map = new HashMap<Integer, Integer>(); | |
233 if (values != null) { | |
234 for (int i = 0; i < values.length; i++) { | |
235 map.put(values[i], counts[i]); | |
236 } | |
237 } | |
238 return map; | |
239 } | |
240 | |
241 @Override | |
242 public void reset() { | |
243 super.reset(); | |
244 cursor = 0; | |
245 Arrays.fill(buffer, 0); | |
246 Arrays.fill(values, 0); | |
247 Arrays.fill(counts, 0); | |
248 } | |
249 | |
250 private void reduce() { | |
251 if (cursor == 0) { | |
252 // no recorded values to reduce | |
253 return; | |
254 } | |
255 // compression needed. | |
256 Arrays.sort(buffer, 0, cursor); | |
257 if (values != null) { | |
258 // there are already some entries. need to merge counts | |
259 removeExistingValues(); | |
260 if (cursor > 0) { | |
261 final int[] ovalues = values; | |
262 final int[] ocounts = counts; | |
263 reduceBuffer(buffer); | |
264 mergeValues(ovalues, ocounts, values, counts); | |
265 } | |
266 } else { | |
267 // there currently aren't any entry arrays. reduce the buffer to generate the first ones. | |
268 reduceBuffer(buffer); | |
269 } | |
270 cursor = 0; | |
271 } | |
272 | |
273 private void removeExistingValues() { | |
274 // increment counts for values that already occur in the entry arrays | |
275 // and leave leftover values in the buffer | |
276 int valuesPos = 0; | |
277 final int ocursor = cursor; | |
278 cursor = 0; | |
279 for (int i = 0; i < ocursor; i++) { | |
280 final int nvalue = buffer[i]; | |
281 while (valuesPos < values.length && values[valuesPos] < nvalue) { | |
282 valuesPos++; | |
283 } | |
284 if (valuesPos < values.length && values[valuesPos] == nvalue) { | |
285 counts[valuesPos]++; | |
286 } else { | |
287 // retain the new values in the buffer | |
288 buffer[cursor++] = nvalue; | |
289 } | |
290 } | |
291 } | |
292 | |
293 private void mergeValues(int[] avalues, int[] acounts, int[] bvalues, int[] bcounts) { | |
294 final int[] nvalues = new int[avalues.length + values.length]; | |
295 final int[] ncounts = new int[acounts.length + counts.length]; | |
296 | |
297 int a = 0; | |
298 int b = 0; | |
299 int n = 0; | |
300 while (n < nvalues.length) { | |
301 while (a < avalues.length && (b == bvalues.length || avalues[a] < bvalues[b])) { | |
302 nvalues[n] = avalues[a]; | |
303 ncounts[n] = acounts[a]; | |
304 n++; | |
305 a++; | |
306 } | |
307 while (b < bvalues.length && (a == avalues.length || bvalues[b] < avalues[a])) { | |
308 nvalues[n] = bvalues[b]; | |
309 ncounts[n] = bcounts[b]; | |
310 n++; | |
311 b++; | |
312 } | |
313 } | |
314 assert n == nvalues.length && a == avalues.length && b == bvalues.length; | |
315 values = nvalues; | |
316 counts = ncounts; | |
317 } | |
318 | |
319 private void reduceBuffer(int[] buf) { | |
320 // count the unique values | |
321 int last1 = buf[0]; | |
322 int unique = 1; | |
323 for (int i1 = 1; i1 < cursor; i1++) { | |
324 if (buffer[i1] != last1) { | |
325 unique++; | |
326 last1 = buffer[i1]; | |
327 } | |
328 } | |
329 // create the values arrays and populate them | |
330 values = new int[unique]; | |
331 counts = new int[unique]; | |
332 int last = buffer[0]; | |
333 int count = 1; | |
334 int pos = 0; | |
335 for (int i = 1; i < cursor; i++) { | |
336 if (buffer[i] != last) { | |
337 values[pos] = last; | |
338 counts[pos] = count; | |
339 pos++; | |
340 count = 1; | |
341 last = buffer[i]; | |
342 } else { | |
343 count++; | |
344 } | |
345 } | |
346 assert pos == values.length - 1; | |
347 values[pos] = last; | |
348 counts[pos] = count; | |
349 } | |
350 } | |
351 | |
352 public static class HashedIntegerDistribution extends IntegerDistribution { | |
353 private Map<Integer, Distribution> map; | |
354 | |
355 private Map<Integer, Distribution> map() { | |
356 if (map == null) { | |
357 map = new HashMap<Integer, Distribution>(); | |
358 } | |
359 return map; | |
360 } | |
361 | |
362 @Override | |
363 public void record(int value) { | |
364 total++; | |
365 final Integer integer = value; | |
366 Distribution distribution = map().get(integer); | |
367 if (distribution == null) { | |
368 distribution = new Distribution(); | |
369 map().put(integer, distribution); | |
370 } | |
371 distribution.total++; | |
372 } | |
373 @Override | |
374 public int getCount(Integer value) { | |
375 final Distribution distribution = map().get(value); | |
376 if (distribution != null) { | |
377 return distribution.total; | |
378 } | |
379 return 0; | |
380 } | |
381 | |
382 @Override | |
383 public Map<Integer, Integer> asMap() { | |
384 final Map<Integer, Integer> result = new HashMap<Integer, Integer>(); | |
385 for (Map.Entry<Integer, Distribution> entry : map().entrySet()) { | |
386 result.put(entry.getKey(), entry.getValue().total); | |
387 } | |
388 return result; | |
389 } | |
390 | |
391 @Override | |
392 public void reset() { | |
393 super.reset(); | |
394 map = null; | |
395 } | |
396 } | |
397 | |
398 /** | |
399 * This class and its descendants support profiling of individual objects. Reference | |
400 * equality is used here exclusively. Various implementations with different size and space | |
401 * tradeoffs offer various levels of accuracy. | |
402 * | |
403 */ | |
404 public abstract static class ObjectDistribution<T> extends Distribution<T> { | |
405 public abstract void record(T value); | |
406 } | |
407 | |
408 public static class HashedObjectDistribution<T> extends ObjectDistribution<T> { | |
409 private Map<T, Distribution> map; | |
410 private Map<T, Distribution> map() { | |
411 if (map == null) { | |
412 map = new IdentityHashMap<T, Distribution>(); | |
413 } | |
414 return map; | |
415 } | |
416 | |
417 public HashedObjectDistribution() { | |
418 } | |
419 | |
420 @Override | |
421 public void record(T value) { | |
422 total++; | |
423 Distribution distribution = map().get(value); | |
424 if (distribution == null) { | |
425 distribution = new Distribution(); | |
426 map().put(value, distribution); | |
427 } | |
428 distribution.total++; | |
429 } | |
430 @Override | |
431 public int getCount(T value) { | |
432 final Distribution distribution = map().get(value); | |
433 if (distribution != null) { | |
434 return distribution.total; | |
435 } | |
436 return 0; | |
437 } | |
438 | |
439 @Override | |
440 public Map<T, Integer> asMap() { | |
441 final Map<T, Integer> result = new IdentityHashMap<T, Integer>(); | |
442 for (Map.Entry<T, Distribution> entry : map().entrySet()) { | |
443 result.put(entry.getKey(), entry.getValue().total); | |
444 } | |
445 return result; | |
446 } | |
447 | |
448 @Override | |
449 public void reset() { | |
450 super.reset(); | |
451 map = null; | |
452 } | |
453 } | |
454 | |
455 public static class FixedSetObjectDistribution<T> extends ObjectDistribution<T> { | |
456 | |
457 private final T[] set; | |
458 private final int[] count; | |
459 private int missed; | |
460 | |
461 public FixedSetObjectDistribution(T[] set) { | |
462 this.set = set.clone(); | |
463 count = new int[set.length]; | |
464 } | |
465 | |
466 @Override | |
467 public void record(T value) { | |
468 total++; | |
469 for (int i = 0; i < set.length; i++) { | |
470 if (set[i] == value) { | |
471 count[i]++; | |
472 return; | |
473 } | |
474 } | |
475 missed++; | |
476 } | |
477 @Override | |
478 public int getCount(T value) { | |
479 for (int i = 0; i < set.length; i++) { | |
480 if (set[i] == value) { | |
481 return count[i]; | |
482 } | |
483 } | |
484 return missed > 0 ? -1 : 0; | |
485 } | |
486 | |
487 @Override | |
488 public Map<T, Integer> asMap() { | |
489 final Map<T, Integer> map = new IdentityHashMap<T, Integer>(); | |
490 for (int i = 0; i != count.length; ++i) { | |
491 map.put(set[i], count[i]); | |
492 } | |
493 return map; | |
494 } | |
495 | |
496 @Override | |
497 public void reset() { | |
498 super.reset(); | |
499 missed = 0; | |
500 Arrays.fill(set, 0); | |
501 Arrays.fill(count, 0); | |
502 } | |
503 } | |
504 | |
505 /** | |
506 * This method creates a new distribution for the occurrence of integer values. | |
507 * | |
508 * @param name the name of the metric; if non-null, then a global metric of the specified | |
509 * name will be returned {@see GlobalMetrics} | |
510 * @param approx the approximation level that is requested. Different approximation levels | |
511 * have different time and space tradeoffs versus accuracy. | |
512 * @return a new integer distribution object that can be used to record occurrences of integers | |
513 */ | |
514 public static IntegerDistribution newIntegerDistribution(String name, Approximation approx) { | |
515 if (name != null) { | |
516 final IntegerDistribution prev = GlobalMetrics.getMetric(name, IntegerDistribution.class); | |
517 if (prev != null) { | |
518 return prev; | |
519 } | |
520 return GlobalMetrics.setMetric(name, IntegerDistribution.class, createIntegerDistribution(approx)); | |
521 } | |
522 return createIntegerDistribution(approx); | |
523 } | |
524 | |
525 private static IntegerDistribution createIntegerDistribution(Approximation approx) throws ProgramError { | |
526 if (approx instanceof FixedApproximation) { | |
527 final FixedApproximation fixedApprox = (FixedApproximation) approx; | |
528 final int[] values = new int[fixedApprox.values.length]; | |
529 for (int i = 0; i < values.length; i++) { | |
530 values[i] = (Integer) fixedApprox.values[i]; | |
531 } | |
532 return new FixedSetIntegerDistribution(values); | |
533 } | |
534 if (approx instanceof IntegerRangeApproximation) { | |
535 final IntegerRangeApproximation fixedApprox = (IntegerRangeApproximation) approx; | |
536 return new FixedRangeIntegerDistribution(fixedApprox.lowValue, fixedApprox.highValue); | |
537 } | |
538 if (approx == EXACT) { | |
539 return new HashedIntegerDistribution(); | |
540 } | |
541 if (approx instanceof IntegerTraceApproximation) { | |
542 final IntegerTraceApproximation traceApprox = (IntegerTraceApproximation) approx; | |
543 return new TraceIntegerDistribution(traceApprox.bufferSize); | |
544 } | |
545 return new HashedIntegerDistribution(); | |
546 } | |
547 | |
548 /** | |
549 * This is a utility method to create an integer distribution over a range of specified integers. | |
550 * | |
551 * @param name the name of the metric | |
552 * @param low the lowest value to be recorded in the range (inclusive) | |
553 * @param high the highest value to be recorded (inclusive) | |
554 * @return a new integer distribution object that will record exact profiles for the integers in the | |
555 * specified range | |
556 */ | |
557 public static IntegerDistribution newIntegerDistribution(String name, int low, int high) { | |
558 return newIntegerDistribution(name, new IntegerRangeApproximation(low, high)); | |
559 } | |
560 | |
561 /** | |
562 * This utility method creates a new integer distribution with the {@link #EXACT} approximation. | |
563 * Note that the implementation of this integer distribution may consume excessive time and/or | |
564 * space for unstructured distributions. | |
565 * | |
566 * @param name the name of the metric; if non-null, then a shared, global metric of the specified name will be returned | |
567 * @return a new integer distribution that records an exact profile | |
568 */ | |
569 public static IntegerDistribution newIntegerDistribution(String name) { | |
570 return newIntegerDistribution(name, EXACT); | |
571 } | |
572 | |
573 /** | |
574 * This utility method creates an integer distribution that records only the specified set of | |
575 * values, with all other values being not recorded. | |
576 * | |
577 * @param name the name of the metric; if non-null, then a shared, global metric of the specified name will be returned | |
578 * @param values the set of integer values to be recored | |
579 * @return a new integer distribution recorder | |
580 */ | |
581 public static IntegerDistribution newIntegerDistribution(String name, int[] values) { | |
582 final Object[] vals = new Object[values.length]; | |
583 for (int i = 0; i < vals.length; i++) { | |
584 vals[i] = values[i]; | |
585 } | |
586 return newIntegerDistribution(name, new FixedApproximation(vals)); | |
587 } | |
588 | |
589 /** | |
590 * This method creates a new distribution capable of recording individual objects. | |
591 * | |
592 * @param <T> the type of objects being profiled | |
593 * @param name the name of the metric; if non-null, then a shared, global metric of the specified name will be | |
594 * returned | |
595 * @param approx the approximation for the distribution | |
596 * @return a new distribution capable of profiling the occurrence of objects | |
597 */ | |
598 public static <T> ObjectDistribution<T> newObjectDistribution(String name, Approximation approx) { | |
599 if (name != null) { | |
600 final ObjectDistribution<T> prev = Utils.cast(GlobalMetrics.getMetric(name, ObjectDistribution.class)); | |
601 if (prev != null) { | |
602 return prev; | |
603 } | |
604 return Utils.cast(GlobalMetrics.setMetric(name, ObjectDistribution.class, createObjectDistribution(approx))); | |
605 } | |
606 return createObjectDistribution(approx); | |
607 } | |
608 | |
609 private static <T> ObjectDistribution<T> createObjectDistribution(Approximation approx) { | |
610 if (approx instanceof FixedApproximation) { | |
611 final FixedApproximation fixedApprox = (FixedApproximation) approx; | |
612 final T[] values = Utils.cast(fixedApprox.values); | |
613 return new FixedSetObjectDistribution<T>(values); | |
614 } | |
615 if (approx == EXACT) { | |
616 return new HashedObjectDistribution<T>(); | |
617 } | |
618 // default is to use the hashed object distribution | |
619 return new HashedObjectDistribution<T>(); | |
620 } | |
621 | |
622 /** | |
623 * This is a utility method to create a new object distribution that only records occurrences of | |
624 * objects in the specified set. | |
625 * | |
626 * @param <T> the type of the objects being profiled | |
627 * @param name the name of the metric | |
628 * @param set the set of objects for which to record exact profiling information | |
629 * @return a new distribution capable of producing an exact profile of the occurence of the specified objects | |
630 */ | |
631 public static <T> ObjectDistribution<T> newObjectDistribution(String name, T... set) { | |
632 return newObjectDistribution(name, new FixedApproximation(set)); | |
633 } | |
634 | |
635 /** | |
636 * This is utility method to create a new object distribution with an exact profile. | |
637 * | |
638 * @param <T> the type of the objects being profiled | |
639 * @param name the name of metric | |
640 * @return a new distribution capable of producing an exact profile of the occurrences of all of the specified | |
641 * objects. | |
642 */ | |
643 public static <T> ObjectDistribution<T> newObjectDistribution(String name) { | |
644 return newObjectDistribution(name, EXACT); | |
645 } | |
646 | |
647 public static class ThreadsafeIntegerDistribution extends IntegerDistribution { | |
648 | |
649 private final IntegerDistribution distribution; | |
650 | |
651 public ThreadsafeIntegerDistribution(IntegerDistribution distribution) { | |
652 this.distribution = distribution; | |
653 } | |
654 @Override | |
655 public void record(int value) { | |
656 synchronized (distribution) { | |
657 distribution.record(value); | |
658 } | |
659 } | |
660 @Override | |
661 public int getCount(Integer value) { | |
662 synchronized (distribution) { | |
663 return distribution.getCount(value); | |
664 } | |
665 } | |
666 | |
667 @Override | |
668 public Map<Integer, Integer> asMap() { | |
669 synchronized (distribution) { | |
670 return distribution.asMap(); | |
671 } | |
672 } | |
673 @Override | |
674 public void reset() { | |
675 super.reset(); | |
676 distribution.reset(); | |
677 } | |
678 | |
679 } | |
680 | |
681 private static class ThreadsafeObjectDistribution<T> extends ObjectDistribution<T> { | |
682 | |
683 private final ObjectDistribution<T> distribution; | |
684 | |
685 ThreadsafeObjectDistribution(ObjectDistribution<T> distribution) { | |
686 this.distribution = distribution; | |
687 } | |
688 @Override | |
689 public void record(T value) { | |
690 synchronized (distribution) { | |
691 distribution.record(value); | |
692 } | |
693 } | |
694 @Override | |
695 public int getCount(T value) { | |
696 synchronized (distribution) { | |
697 return distribution.getCount(value); | |
698 } | |
699 } | |
700 | |
701 @Override | |
702 public Map<T, Integer> asMap() { | |
703 synchronized (distribution) { | |
704 return distribution.asMap(); | |
705 } | |
706 } | |
707 } | |
708 | |
709 /** | |
710 * This method creates a wrapper around the specified integer distribution that ensures | |
711 * access to the distribution is synchronized. | |
712 * | |
713 * @param distribution the distribution to wrap in a synchronization | |
714 * @return a synchronized view of the distribution | |
715 */ | |
716 public static IntegerDistribution threadSafe(IntegerDistribution distribution) { | |
717 return new ThreadsafeIntegerDistribution(distribution); | |
718 } | |
719 | |
720 /** | |
721 * This method creates a wrapper around the specified integer distribution that ensures | |
722 * access to the distribution is synchronized. | |
723 * | |
724 * @param distribution the distribution to wrap in a synchronization | |
725 * @return a synchronized view of the distribution | |
726 */ | |
727 public static <T> ObjectDistribution<T> threadSafe(ObjectDistribution<T> distribution) { | |
728 return new ThreadsafeObjectDistribution<T>(distribution); | |
729 } | |
730 } |