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 17package com.google.common.util.concurrent; 18 19import static com.google.common.util.concurrent.MoreExecutors.directExecutor; 20import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService; 21 22import com.google.caliper.AfterExperiment; 23import com.google.caliper.BeforeExperiment; 24import com.google.caliper.Benchmark; 25import com.google.caliper.Param; 26import com.google.caliper.api.Footprint; 27import com.google.caliper.api.VmOptions; 28 29import java.util.HashSet; 30import java.util.Set; 31import java.util.concurrent.Executor; 32import 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"}) 39public 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} 118