1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.pool2.performance;
19
20 import java.time.Duration;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.concurrent.Callable;
24 import java.util.concurrent.ExecutionException;
25 import java.util.concurrent.ExecutorService;
26 import java.util.concurrent.Executors;
27 import java.util.concurrent.Future;
28
29 import org.apache.commons.pool2.impl.GenericObjectPool;
30
31
32
33
34 public class PerformanceTest {
35
36 class PerfTask implements Callable<TaskStats> {
37 final TaskStats taskStats = new TaskStats();
38 long borrowTimeNanos;
39 long returnTimeNanos;
40
41 @Override
42 public TaskStats call() {
43 runOnce();
44 for (int i = 0; i < nrIterations; i++) {
45 runOnce();
46 taskStats.totalBorrowNanos += borrowTimeNanos;
47 taskStats.totalReturnNanos += returnTimeNanos;
48 taskStats.nrSamples++;
49 if (logLevel >= 2) {
50 final String name = "thread" + Thread.currentThread().getName();
51 System.out.println("result " + taskStats.nrSamples + '\t' +
52 name + '\t' + "borrow time: " + Duration.ofNanos(borrowTimeNanos) + '\t' +
53 "return time: " + Duration.ofNanos(returnTimeNanos) + '\t' + "waiting: " +
54 taskStats.waiting + '\t' + "complete: " +
55 taskStats.complete);
56 }
57 }
58 return taskStats;
59 }
60
61 public void runOnce() {
62 try {
63 taskStats.waiting++;
64 if (logLevel >= 5) {
65 final String name = "thread" + Thread.currentThread().getName();
66 System.out.println(name +
67 " waiting: " + taskStats.waiting +
68 " complete: " + taskStats.complete);
69 }
70 final long bbeginNanos = System.nanoTime();
71 final Integer o = pool.borrowObject();
72 final long bendNanos = System.nanoTime();
73 taskStats.waiting--;
74
75 if (logLevel >= 3) {
76 final String name = "thread" + Thread.currentThread().getName();
77 System.out.println(name +
78 " waiting: " + taskStats.waiting +
79 " complete: " + taskStats.complete);
80 }
81
82 final long rbeginNanos = System.nanoTime();
83 pool.returnObject(o);
84 final long rendNanos = System.nanoTime();
85 Thread.yield();
86 taskStats.complete++;
87 borrowTimeNanos = bendNanos - bbeginNanos;
88 returnTimeNanos = rendNanos - rbeginNanos;
89 } catch (final Exception e) {
90 e.printStackTrace();
91 }
92 }
93 }
94 private static class TaskStats {
95 public int waiting;
96 public int complete;
97 public long totalBorrowNanos;
98 public long totalReturnNanos;
99 public int nrSamples;
100 }
101
102 public static void main(final String[] args) {
103 final PerformanceTest test = new PerformanceTest();
104 test.setLogLevel(0);
105 System.out.println("Increase threads");
106 test.run(1, 50, 5, 5);
107 test.run(1, 100, 5, 5);
108 test.run(1, 200, 5, 5);
109 test.run(1, 400, 5, 5);
110
111 System.out.println("Increase threads & poolSize");
112 test.run(1, 50, 5, 5);
113 test.run(1, 100, 10, 10);
114 test.run(1, 200, 20, 20);
115 test.run(1, 400, 40, 40);
116
117 System.out.println("Increase maxIdle");
118 test.run(1, 400, 40, 5);
119 test.run(1, 400, 40, 40);
120
121
122
123
124 }
125
126 private int logLevel;
127
128 private int nrIterations = 5;
129
130 private GenericObjectPool<Integer> pool;
131
132 private void run(final int iterations, final int nrThreads, final int maxTotal, final int maxIdle) {
133 this.nrIterations = iterations;
134
135 final SleepingObjectFactory factory = new SleepingObjectFactory();
136 if (logLevel >= 4) { factory.setDebug(true); }
137 pool = new GenericObjectPool<>(factory);
138 pool.setMaxTotal(maxTotal);
139 pool.setMaxIdle(maxIdle);
140 pool.setTestOnBorrow(true);
141
142 final ExecutorService threadPool = Executors.newFixedThreadPool(nrThreads);
143
144 final List<Callable<TaskStats>> tasks = new ArrayList<>();
145 for (int i = 0; i < nrThreads; i++) {
146 tasks.add(new PerfTask());
147 Thread.yield();
148 }
149
150 if (logLevel >= 1) {
151 System.out.println("created");
152 }
153 Thread.yield();
154 List<Future<TaskStats>> futures = null;
155 try {
156 futures = threadPool.invokeAll(tasks);
157 } catch (final InterruptedException e) {
158 e.printStackTrace();
159 }
160
161 if (logLevel >= 1) { System.out.println("started"); }
162 Thread.yield();
163
164 if (logLevel >= 1) { System.out.println("go"); }
165 Thread.yield();
166
167 if (logLevel >= 1) { System.out.println("finish"); }
168
169 final TaskStats aggregate = new TaskStats();
170 if (futures != null) {
171 for (final Future<TaskStats> future : futures) {
172 TaskStats taskStats = null;
173 try {
174 taskStats = future.get();
175 } catch (final InterruptedException | ExecutionException e) {
176 e.printStackTrace();
177 }
178 if (taskStats != null) {
179 aggregate.complete += taskStats.complete;
180 aggregate.nrSamples += taskStats.nrSamples;
181 aggregate.totalBorrowNanos += taskStats.totalBorrowNanos;
182 aggregate.totalReturnNanos += taskStats.totalReturnNanos;
183 aggregate.waiting += taskStats.waiting;
184 }
185 }
186 }
187
188 final Duration totalBorrowDuration = Duration.ofNanos(aggregate.totalBorrowNanos);
189 final Duration totalReturnDuration = Duration.ofNanos(aggregate.totalReturnNanos);
190 System.out.println("-----------------------------------------");
191 System.out.println("nrIterations: " + iterations);
192 System.out.println("nrThreads: " + nrThreads);
193 System.out.println("maxTotal: " + maxTotal);
194 System.out.println("maxIdle: " + maxIdle);
195 System.out.println("nrSamples: " + aggregate.nrSamples);
196 System.out.println("totalBorrowTime: " + totalBorrowDuration);
197 System.out.println("totalReturnTime: " + totalReturnDuration);
198 System.out.println("avg BorrowTime: " + totalBorrowDuration.dividedBy(aggregate.nrSamples));
199 System.out.println("avg ReturnTime: " + totalReturnDuration.dividedBy(aggregate.nrSamples));
200
201 threadPool.shutdown();
202 }
203
204 public void setLogLevel(final int i) {
205 logLevel = i;
206 }
207 }