View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
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   * Multi-thread performance test
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(); // warmup
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 //      System.out.println("Show creation/destruction of objects");
122 //      test.setLogLevel(4);
123 //      test.run(1, 400, 40,  5);
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 }