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 class CachePerformanceTest {
52
53
54
55
56 static class Task implements Callable<Integer> {
57 private final JexlEngine jexl;
58 private final BlockingQueue<?> queue;
59
60 Task(final JexlEngine jexl, final BlockingQueue<?> queue) {
61 this.jexl = jexl;
62 this.queue = queue;
63 }
64
65 @Override
66 public Integer call() {
67 int count = 0;
68 Object arg;
69 try {
70 while ((arg = queue.take()) != Task.class) {
71 final Random rnd = new Random((int) arg);
72 for (int l = 0; l < LOOPS; ++l) {
73 for (int c = 0; c < CACHED; ++c) {
74 final int ctl = rnd.nextInt(SCRIPTS);
75 for (int r = 0; r < HIT; ++r) {
76 final JexlScript script = jexl.createScript(Integer.toString(ctl));
77 final Object result = script.execute(null);
78 assertEquals(((Number) result).intValue(), ctl);
79 count += 1;
80 }
81 }
82 }
83 }
84 return count;
85 } catch (final InterruptedException e) {
86 Thread.currentThread().interrupt();
87 throw new RuntimeException(e);
88 }
89 }
90 }
91
92 public static class Timer {
93 long begin;
94 long end;
95
96 String elapse() {
97 final long delta = end - begin;
98 final NumberFormat fmt = new DecimalFormat("#.###");
99 return fmt.format(delta / 1000.d);
100 }
101
102 void start() {
103 begin = System.currentTimeMillis();
104 }
105
106 void stop() {
107 end = System.currentTimeMillis();
108 }
109 }
110
111
112 private static final int LOOPS = 10;
113
114
115 private static final int SCRIPTS = 800;
116
117
118 private static final int CACHED = 500;
119
120
121 private static final int HIT = 5;
122
123
124 private static final int THREADS = 8;
125
126
127 Log LOGGER = LogFactory.getLog(getClass());
128
129
130
131
132
133
134
135 protected void runTest(final String name, final JexlEngine jexl) throws Exception {
136 final ExecutorService exec = Executors.newFixedThreadPool(THREADS);
137 final BlockingQueue<Object> queue = new ArrayBlockingQueue<>(THREADS);
138 final List<Future<Integer>> results = new ArrayList<>(THREADS);
139
140 for (int i = 0; i < CACHED; ++i) {
141 final JexlScript script = jexl.createScript(Integer.toString(i));
142 assertNotNull(script);
143 }
144
145 for (int t = 0; t < THREADS; ++t) {
146 results.add(exec.submit(new Task(jexl, queue)));
147 }
148 final Timer tt = new Timer();
149 tt.start();
150
151 for (int t = 0; t < THREADS; ++t) {
152 queue.put(t);
153 }
154
155 for (int t = 0; t < THREADS; ++t) {
156 queue.put(Task.class);
157 }
158 int total = 0;
159 for (final Future<Integer> result : results) {
160 total += result.get();
161 }
162 exec.shutdown();
163 tt.stop();
164 assertEquals(total, LOOPS * CACHED * THREADS * HIT);
165 LOGGER.info(name + " : " + tt.elapse());
166 }
167
168 @Test
169 void testConcurrent() throws Exception {
170 final JexlBuilder builder = new JexlBuilder().cacheFactory(ConcurrentCache::new).cache(CACHED);
171 final JexlEngine jexl = builder.create();
172 runTest("testConcurrent", jexl);
173 }
174
175 @Test
176 void testSpread() throws Exception {
177 final JexlBuilder builder = new JexlBuilder().cacheFactory(SpreadCache::new).cache(CACHED);
178 final JexlEngine jexl = builder.create();
179 runTest("testSpread", jexl);
180 }
181
182 @Test
183 void testSynchronized() throws Exception {
184 final JexlBuilder builder = new JexlBuilder().cache(CACHED);
185 final JexlEngine jexl = builder.create();
186 runTest("testSynchronized", jexl);
187 }
188 }