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 
21 import com.google.caliper.BeforeExperiment;
22 import com.google.caliper.Param;
23 import com.google.caliper.api.Footprint;
24 import com.google.caliper.api.SkipThisScenarioException;
25 import com.google.common.util.concurrent.AbstractFutureBenchmarks.Facade;
26 import com.google.common.util.concurrent.AbstractFutureBenchmarks.Impl;
27 import java.util.HashSet;
28 import java.util.Set;
29 import java.util.concurrent.Executor;
30 
31 /** Measures the size of AbstractFuture implementations. */
32 public class AbstractFutureFootprintBenchmark {
33 
34   enum State {
35     NOT_DONE,
36     FINISHED,
37     CANCELLED,
38     FAILED
39   }
40 
41   @Param State state;
42   @Param Impl impl;
43 
44   @Param({"0", "1", "5", "10"})
45   int numListeners;
46 
47   @Param({"0", "1", "5", "10"})
48   int numThreads;
49 
50   private final Set<Thread> blockedThreads = new HashSet<>();
51 
52   @BeforeExperiment
setUp()53   void setUp() throws Exception {
54     if (state != State.NOT_DONE && (numListeners != 0 || numThreads != 0)) {
55       throw new SkipThisScenarioException();
56     }
57   }
58 
59   // This exclusion doesn't exclude the TOMBSTONE objects we set. So 'done' NEW futures will look
60   // larger than they are.
61   @SuppressWarnings("FutureReturnValueIgnored")
62   @Footprint(exclude = {Runnable.class, Executor.class, Thread.class, Exception.class})
measureSize()63   public Object measureSize() {
64     for (Thread thread : blockedThreads) {
65       thread.interrupt();
66     }
67     blockedThreads.clear();
68     final Facade<Object> f = impl.newFacade();
69     for (int i = 0; i < numThreads; i++) {
70       Thread thread =
71           new Thread() {
72             @Override
73             public void run() {
74               try {
75                 f.get();
76               } catch (Throwable expected) {
77               }
78             }
79           };
80       thread.start();
81       blockedThreads.add(thread);
82     }
83     for (int i = 0; i < numListeners; i++) {
84       f.addListener(Runnables.doNothing(), directExecutor());
85     }
86     for (Thread thread : blockedThreads) {
87       AbstractFutureBenchmarks.awaitWaiting(thread);
88     }
89     switch (state) {
90       case NOT_DONE:
91         break;
92       case FINISHED:
93         f.set(null);
94         break;
95       case CANCELLED:
96         f.cancel(false);
97         break;
98       case FAILED:
99         f.setException(new Exception());
100         break;
101       default:
102         throw new AssertionError();
103     }
104     return f;
105   }
106 }
107