View Javadoc
1   /*
2    * Copyright (C) 2014 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.util.concurrent;
18  
19  import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
20  import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService;
21  
22  import com.google.caliper.AfterExperiment;
23  import com.google.caliper.BeforeExperiment;
24  import com.google.caliper.Benchmark;
25  import com.google.caliper.Param;
26  import com.google.caliper.api.Footprint;
27  import com.google.caliper.api.VmOptions;
28  
29  import java.util.HashSet;
30  import java.util.Set;
31  import java.util.concurrent.Executor;
32  import java.util.concurrent.atomic.AtomicInteger;
33  
34  /**
35   * A benchmark comparing the {@link MoreExecutors#newDirectExecutorService()} to
36   * {@link MoreExecutors#directExecutor}.
37   */
38  @VmOptions({"-Xms12g", "-Xmx12g", "-d64"})
39  public class MoreExecutorsDirectExecutorBenchmark {
40    enum Impl {
41      EXECUTOR_SERVICE {
42        @Override Executor executor() {
43          return newDirectExecutorService();
44        }
45      },
46      EXECUTOR {
47        @Override Executor executor() {
48          return directExecutor();
49        }
50      };
51      abstract Executor executor();
52    }
53  
54    @Param Impl impl;
55    Executor executor;
56  
57    static final class CountingRunnable implements Runnable {
58      AtomicInteger integer = new AtomicInteger();
59      @Override public void run() {
60        integer.incrementAndGet();
61      }
62    }
63    
64    CountingRunnable countingRunnable = new CountingRunnable();
65  
66    Set<Thread> threads = new HashSet<Thread>();
67    
68    @BeforeExperiment void before() {
69      executor = impl.executor();
70      for (int i = 0; i < 4; i++) {
71        Thread thread = new Thread() {
72          @Override public void run() {
73            CountingRunnable localRunnable = new CountingRunnable();
74            while (!isInterrupted()) {
75              executor.execute(localRunnable);
76            }
77            countingRunnable.integer.addAndGet(localRunnable.integer.get());
78          }
79        };
80        threads.add(thread);
81      }
82    }
83  
84    @AfterExperiment void after() {
85      for (Thread thread : threads) {
86        thread.interrupt();  // try to get them to exit
87      }
88      threads.clear();
89    }
90    
91    @Footprint Object measureSize() {
92      return executor;
93    }
94    
95    @Benchmark int timeUncontendedExecute(int reps) {
96      final Executor executor = this.executor;
97      final CountingRunnable countingRunnable = this.countingRunnable;
98      for (int i = 0; i < reps; i++) {
99        executor.execute(countingRunnable);
100     }
101     return countingRunnable.integer.get();
102   }
103   
104   @Benchmark int timeContendedExecute(int reps) {
105     final Executor executor = this.executor;
106     for (Thread thread : threads) {
107       if (!thread.isAlive()) {
108         thread.start();
109       }
110     }
111     final CountingRunnable countingRunnable = this.countingRunnable;
112     for (int i = 0; i < reps; i++) {
113       executor.execute(countingRunnable);
114     }
115     return countingRunnable.integer.get();
116   }
117 }