1 package net.sf.ehcache;
2
3 import java.util.UUID;
4 import java.util.concurrent.Callable;
5 import java.util.concurrent.ExecutorService;
6 import java.util.concurrent.Executors;
7 import java.util.concurrent.Future;
8
9 import org.junit.Assert;
10 import org.junit.Ignore;
11
12 import org.junit.Test;
13
14 import java.util.logging.Logger;
15
16 /***
17 * @author cdennis
18 */
19 @Ignore
20 public class ChrisCachePerformanceTest {
21
22 private static final Logger LOG = Logger.getLogger(ChrisCachePerformanceTest.class.getName());
23
24
25
26
27
28 @Test
29 public void testSingleThreadedPut() {
30 Cache testCache = new Cache(UUID.randomUUID().toString(), 100000, false, true, 0, 0);
31 CacheManager.getInstance().addCache(testCache);
32
33 Double time = testPut("Single-Threaded Put Test", testCache, 20);
34
35 LOG.info("Single-Threaded Put Test, Average Time " + time + "ms/put");
36
37 CacheManager.getInstance().removeCache(testCache.getName());
38 }
39
40 @Test
41 public void testMultiThreadedPut() throws Exception {
42 testMultiThreadedPut(Math.max(2, Runtime.getRuntime().availableProcessors()));
43 }
44
45 @Test
46 public void testOverThreadedPut() throws Exception {
47 testMultiThreadedPut(4 * Math.max(2, Runtime.getRuntime().availableProcessors()));
48 }
49
50 private void testMultiThreadedPut(final int cpuCount) throws Exception {
51 final Cache testCache = new Cache(UUID.randomUUID().toString(), 100000, false, true, 0, 0);
52 CacheManager.getInstance().addCache(testCache);
53
54 Future<Double>[] futures = new Future[cpuCount];
55 ExecutorService[] executors = new ExecutorService[cpuCount];
56
57 for (int i = 0; i < cpuCount; i++) {
58 final int cpu = i;
59 executors[i] = Executors.newSingleThreadExecutor();
60 futures[i] = executors[i].submit(new Callable<Double>() {
61 public Double call() {
62 return testPut("Multi-Threaded Put Test [" + cpuCount + " Threads], Partition " + cpu, testCache, 20, cpu, cpuCount);
63 }
64 });
65 }
66
67 double total = 0;
68 for (Future<Double> f : futures) {
69 total += f.get().doubleValue();
70 }
71
72 LOG.info("Multi-Threaded Put Test, Average Time For " + cpuCount + " Threads " + (total / cpuCount) + "ms/put");
73
74 for (ExecutorService e : executors) {
75 e.shutdown();
76 }
77
78 CacheManager.getInstance().removeCache(testCache.getName());
79 }
80
81 @Test
82 public void testSingleThreadedPutAtThreshold() {
83 final Cache testCache = new Cache(UUID.randomUUID().toString(), 100000, false, true, 0, 0);
84 CacheManager.getInstance().addCache(testCache);
85
86 testPut("Warming Cache For Single-Threaded Threshold Put Test", testCache, 1);
87
88 Double time = testThresholdPut("Single-Threaded Threshold Put Test", testCache, 20);
89
90 LOG.info("Single-Threaded Threshold Put Test, Average Time " + time + "ms/put");
91
92 CacheManager.getInstance().removeCache(testCache.getName());
93 }
94
95 @Test
96 public void testMultiThreadedPutAtThreshold() throws Exception {
97 testMultiThreadedPutAtThreshold(Math.max(2, Runtime.getRuntime().availableProcessors()));
98 }
99
100 @Test
101 public void testOverThreadedPutAtThreshold() throws Exception {
102 testMultiThreadedPutAtThreshold(4 * Math.max(2, Runtime.getRuntime().availableProcessors()));
103 }
104
105 private void testMultiThreadedPutAtThreshold(final int cpuCount) throws Exception {
106 final Cache testCache = new Cache(UUID.randomUUID().toString(), 100000, false, true, 0, 0);
107 CacheManager.getInstance().addCache(testCache);
108
109 testPut("Warming Cache For Multi-Threaded Threshold Put Test", testCache, 1);
110
111 Future<Double>[] futures = new Future[cpuCount];
112 ExecutorService[] executors = new ExecutorService[cpuCount];
113
114 for (int i = 0; i < cpuCount; i++) {
115 final int cpu = i;
116 executors[i] = Executors.newSingleThreadExecutor();
117 futures[i] = executors[i].submit(new Callable<Double>() {
118 public Double call() {
119 return testThresholdPut("Multi-Threaded Threshold Put Test, Partition " + cpu, testCache, 20, cpu, cpuCount);
120 }
121 });
122 }
123
124 double total = 0;
125 for (Future<Double> f : futures) {
126 total += f.get().doubleValue();
127 }
128
129 LOG.info("Multi-Threaded Threshold Put Test, Average Time For " + cpuCount + " Threads " + (total / cpuCount) + "ms/put");
130
131 for (ExecutorService e : executors) {
132 e.shutdown();
133 }
134
135 CacheManager.getInstance().removeCache(testCache.getName());
136 }
137
138 @Test
139 public void testSingleThreadedGet() {
140 final Cache testCache = new Cache(UUID.randomUUID().toString(), 100000, false, true, 0, 0);
141 CacheManager.getInstance().addCache(testCache);
142
143 testPut("Warming Cache For Single-Threaded Get Test", testCache, 1);
144
145 Double time = testGet("Single-Threaded Get Test", testCache, 20);
146
147 LOG.info("Single-Threaded Get Test, Average Time " + time + "ms/get");
148
149 CacheManager.getInstance().removeCache(testCache.getName());
150 }
151
152 @Test
153 public void testMultiThreadedGet() throws Exception {
154 testMultiThreadedGet(Math.max(2, Runtime.getRuntime().availableProcessors()));
155 }
156
157 @Test
158 public void testOverThreadedGet() throws Exception {
159 testMultiThreadedGet(4 * Math.max(2, Runtime.getRuntime().availableProcessors()));
160 }
161
162 private void testMultiThreadedGet(final int cpuCount) throws Exception {
163 final Cache testCache = new Cache(UUID.randomUUID().toString(), 100000, false, true, 0, 0);
164 CacheManager.getInstance().addCache(testCache);
165
166 testPut("Warming Cache For Multi-Threaded Get Test", testCache, 1);
167
168 Future<Double>[] futures = new Future[cpuCount];
169 ExecutorService[] executors = new ExecutorService[cpuCount];
170
171 for (int i = 0; i < cpuCount; i++) {
172 final int cpu = i;
173 executors[i] = Executors.newSingleThreadExecutor();
174 futures[i] = executors[i].submit(new Callable<Double>() {
175 public Double call() {
176 return testGet("Multi-Threaded Get Test, Partition " + cpu, testCache, 20, cpu, cpuCount);
177 }
178 });
179 }
180
181 double total = 0;
182 for (Future<Double> f : futures) {
183 total += f.get().doubleValue();
184 }
185
186 LOG.info("Multi-Threaded Get Test, Average Time For " + cpuCount + " Threads " + (total / cpuCount) + "ms/get");
187
188 for (ExecutorService e : executors) {
189 e.shutdown();
190 }
191
192 CacheManager.getInstance().removeCache(testCache.getName());
193
194 }
195
196
197 private static Double testPut(String test, Cache cache, int cycles) {
198 return testPut(test, cache, cycles, 0, 1);
199 }
200
201 private static Double testPut(String test, Cache cache, int cycles, int index, int partitions) {
202 int max = cache.getCacheConfiguration().getMaxElementsInMemory();
203
204 int begin = (max / partitions) * index;
205 int finish = (max / partitions) * (index + 1);
206
207 long totalPuts = 0;
208 long totalTime = 0;
209 for (int c = 0; c < cycles; c++) {
210 cache.removeAll();
211 System.gc();
212
213 long start = System.currentTimeMillis();
214 for (int i = begin; i < finish; i++) {
215 cache.put(new Element(Integer.valueOf(i), new Object()));
216 }
217 long end = System.currentTimeMillis();
218
219 totalPuts += (finish - begin);
220 totalTime += (end - start);
221 LOG.fine(test + ": Test Cycle " + (c + 1) + ": " + (finish - begin) + " puts took " + (end - start) + "ms ["
222 + (((double) (end - start)) / (finish - begin)) + "ms/put]\n"
223 + "\t\tRunning Average: " + totalPuts + " puts took " + totalTime + "ms [" + (((double) totalTime) / totalPuts) + "ms/put]");
224
225 }
226
227 return Double.valueOf(((double) totalTime) / totalPuts);
228 }
229
230 private static Double testThresholdPut(String test, Cache cache, int cycles) {
231 return testThresholdPut(test, cache, cycles, 0, 1);
232 }
233
234 private static Double testThresholdPut(String test, Cache cache, int cycles, int index, int partitions) {
235 int max = cache.getCacheConfiguration().getMaxElementsInMemory();
236
237 long totalPuts = 0;
238 long totalTime = 0;
239 for (int c = 0; c < cycles; c++) {
240 System.gc();
241
242 int begin = ((c + 1) * max) + (max / partitions) * index;
243 int finish = ((c + 1) * max) + (max / partitions) * (index + 1);
244
245 long start = System.currentTimeMillis();
246 for (int i = begin; i < finish; i++) {
247 cache.put(new Element(Integer.valueOf(i), new Object()));
248 }
249 long end = System.currentTimeMillis();
250
251 totalPuts += (finish - begin);
252 totalTime += (end - start);
253 LOG.fine(test + ": Test Cycle " + (c + 1) + ": " + (finish - begin) + " puts took " + (end - start) + "ms ["
254 + (((double) (end - start)) / (finish - begin)) + "ms/put]\n"
255 + "\t\tRunning Average: " + totalPuts + " puts took " + totalTime + "ms [" + (((double) totalTime) / totalPuts) + "ms/put]");
256
257 }
258
259 return Double.valueOf(((double) totalTime) / totalPuts);
260 }
261
262 private static Double testGet(String test, Cache cache, int cycles) {
263 return testGet(test, cache, cycles, 0, 1);
264 }
265
266 private static Double testGet(String test, Cache cache, int cycles, int index, int partitions) {
267 int max = cache.getCacheConfiguration().getMaxElementsInMemory();
268
269 int begin = (max / partitions) * index;
270 int finish = (max / partitions) * (index + 1);
271
272 long totalGets = 0;
273 long totalTime = 0;
274 for (int c = 0; c < cycles; c++) {
275 long start = System.currentTimeMillis();
276 for (int i = begin; i < finish; i++) {
277 Assert.assertNotNull("Element @ " + i, cache.get(Integer.valueOf(i)));
278 }
279 long end = System.currentTimeMillis();
280
281 totalGets += (finish - begin);
282 totalTime += (end - start);
283 LOG.fine(test + ": Test Cycle " + (c + 1) + ": " + (finish - begin) + " gets took " + (end - start) + "ms ["
284 + (((double) (end - start)) / (finish - begin)) + "ms/get]\n"
285 + "\t\tRunning Average: " + totalGets + " gets took " + totalTime + "ms [" + (((double) totalTime) / totalGets) + "ms/get]");
286 }
287
288 return Double.valueOf(((double) totalTime) / totalGets);
289 }
290 }