1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl3;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertNotNull;
21
22 import java.text.DecimalFormat;
23 import java.text.NumberFormat;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Random;
27 import java.util.concurrent.ArrayBlockingQueue;
28 import java.util.concurrent.BlockingQueue;
29 import java.util.concurrent.Callable;
30 import java.util.concurrent.ExecutorService;
31 import java.util.concurrent.Executors;
32 import java.util.concurrent.Future;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.junit.jupiter.api.Test;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 public class CachePerformanceTest {
52
53
54
55 static class Task implements Callable<Integer> {
56 private final JexlEngine jexl;
57 private final BlockingQueue<?> queue;
58
59 Task(final JexlEngine jexl, final BlockingQueue<?> queue) {
60 this.jexl = jexl;
61 this.queue = queue;
62 }
63
64 @Override
65 public Integer call() {
66 int count = 0;
67 Object arg;
68 try {
69 while ((arg = queue.take()) != Task.class) {
70 final Random rnd = new Random((int) arg);
71 for (int l = 0; l < LOOPS; ++l) {
72 for (int c = 0; c < CACHED; ++c) {
73 final int ctl = rnd.nextInt(SCRIPTS);
74 for (int r = 0; r < HIT; ++r) {
75 final JexlScript script = jexl.createScript(Integer.toString(ctl));
76 final Object result = script.execute(null);
77 assert ((Number) result).intValue() == ctl;
78 count += 1;
79 }
80 }
81 }
82 }
83 return count;
84 } catch (final InterruptedException e) {
85 throw new RuntimeException(e);
86 }
87 }
88 }
89
90 public static class Timer {
91 long begin;
92 long end;
93
94 String elapse() {
95 final long delta = end - begin;
96 final NumberFormat fmt = new DecimalFormat("#.###");
97 return fmt.format(delta / 1000.d);
98 }
99
100 void start() {
101 begin = System.currentTimeMillis();
102 }
103
104 void stop() {
105 end = System.currentTimeMillis();
106 }
107 }
108
109
110 private static final int LOOPS = 10;
111
112 private static final int SCRIPTS = 800;
113
114 private static final int CACHED = 500;
115
116 private static final int HIT = 5;
117
118
119 private static final int THREADS = 8;
120
121
122 Log LOGGER = LogFactory.getLog(getClass());
123
124
125
126
127
128
129
130 protected void runTest(final String name, final JexlEngine jexl) throws Exception {
131 final ExecutorService exec = Executors.newFixedThreadPool(THREADS);
132 final BlockingQueue<Object> queue = new ArrayBlockingQueue<>(THREADS);
133 final List<Future<Integer>> results = new ArrayList<>(THREADS);
134
135 for (int i = 0; i < CACHED; ++i) {
136 final JexlScript script = jexl.createScript(Integer.toString(i));
137 assertNotNull(script);
138 }
139
140 for (int t = 0; t < THREADS; ++t) {
141 results.add(exec.submit(new Task(jexl, queue)));
142 }
143 final Timer tt = new Timer();
144 tt.start();
145
146 for (int t = 0; t < THREADS; ++t) {
147 queue.put(t);
148 }
149
150 for (int t = 0; t < THREADS; ++t) {
151 queue.put(Task.class);
152 }
153 int total = 0;
154 for (final Future<Integer> result : results) {
155 total += result.get();
156 }
157 exec.shutdown();
158 tt.stop();
159 assertEquals(total, LOOPS * CACHED * THREADS * HIT);
160 LOGGER.info(name + " : " + tt.elapse());
161 }
162
163 @Test
164 public void testConcurrent() throws Exception {
165 final JexlBuilder builder = new JexlBuilder().cacheFactory(ConcurrentCache::new).cache(CACHED);
166 final JexlEngine jexl = builder.create();
167 runTest("testConcurrent", jexl);
168 }
169
170 @Test
171 public void testSpread() throws Exception {
172 final JexlBuilder builder = new JexlBuilder().cacheFactory(SpreadCache::new).cache(CACHED);
173 final JexlEngine jexl = builder.create();
174 runTest("testSpread", jexl);
175 }
176
177 @Test
178 public void testSynchronized() throws Exception {
179 final JexlBuilder builder = new JexlBuilder().cache(CACHED);
180 final JexlEngine jexl = builder.create();
181 runTest("testSynchronized", jexl);
182 }
183 }