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