• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 Google Inc.
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.caliper.runner;
18 
19 import static com.google.caliper.runner.CommonInstrumentOptions.GC_BEFORE_EACH_OPTION;
20 import static com.google.common.base.Throwables.propagateIfInstanceOf;
21 
22 import com.google.caliper.api.SkipThisScenarioException;
23 import com.google.caliper.bridge.AbstractLogMessageVisitor;
24 import com.google.caliper.bridge.StopMeasurementLogMessage;
25 import com.google.caliper.model.ArbitraryMeasurement;
26 import com.google.caliper.model.Measurement;
27 import com.google.caliper.platform.Platform;
28 import com.google.caliper.platform.SupportedPlatform;
29 import com.google.caliper.util.Util;
30 import com.google.caliper.worker.ArbitraryMeasurementWorker;
31 import com.google.caliper.worker.Worker;
32 import com.google.common.base.Optional;
33 import com.google.common.collect.ImmutableList;
34 import com.google.common.collect.ImmutableMap;
35 import com.google.common.collect.ImmutableSet;
36 import com.google.common.collect.Iterables;
37 
38 import java.lang.reflect.InvocationTargetException;
39 import java.lang.reflect.Method;
40 
41 /**
42  * Instrument for taking an arbitrary measurement. When using this instrument, the benchmark code
43  * itself returns the value. See {@link ArbitraryMeasurement}.
44  */
45 @SupportedPlatform(Platform.Type.JVM)
46 public final class ArbitraryMeasurementInstrument extends Instrument {
isBenchmarkMethod(Method method)47   @Override public boolean isBenchmarkMethod(Method method) {
48     return method.isAnnotationPresent(ArbitraryMeasurement.class);
49   }
50 
51   @Override
createInstrumentation(Method benchmarkMethod)52   public Instrumentation createInstrumentation(Method benchmarkMethod)
53       throws InvalidBenchmarkException {
54     if (benchmarkMethod.getParameterTypes().length != 0) {
55       throw new InvalidBenchmarkException(
56           "Arbitrary measurement methods should take no parameters: " + benchmarkMethod.getName());
57     }
58 
59     if (benchmarkMethod.getReturnType() != double.class) {
60       throw new InvalidBenchmarkException(
61           "Arbitrary measurement methods must have a return type of double: "
62               + benchmarkMethod.getName());
63     }
64 
65     // Static technically doesn't hurt anything, but it's just the completely wrong idea
66     if (Util.isStatic(benchmarkMethod)) {
67       throw new InvalidBenchmarkException(
68           "Arbitrary measurement methods must not be static: " + benchmarkMethod.getName());
69     }
70 
71     if (!Util.isPublic(benchmarkMethod)) {
72       throw new InvalidBenchmarkException(
73           "Arbitrary measurement methods must be public: " + benchmarkMethod.getName());
74     }
75 
76     return new ArbitraryMeasurementInstrumentation(benchmarkMethod);
77   }
78 
schedulingPolicy()79   @Override public TrialSchedulingPolicy schedulingPolicy() {
80     // We could allow it here but in general it would depend on the particular measurement so it
81     // should probably be configured by the user.  For now we just disable it.
82     return TrialSchedulingPolicy.SERIAL;
83   }
84 
85   private final class ArbitraryMeasurementInstrumentation extends Instrumentation {
ArbitraryMeasurementInstrumentation(Method benchmarkMethod)86     protected ArbitraryMeasurementInstrumentation(Method benchmarkMethod) {
87       super(benchmarkMethod);
88     }
89 
90     @Override
dryRun(Object benchmark)91     public void dryRun(Object benchmark) throws InvalidBenchmarkException {
92       try {
93         benchmarkMethod.invoke(benchmark);
94       } catch (IllegalAccessException impossible) {
95         throw new AssertionError(impossible);
96       } catch (InvocationTargetException e) {
97         Throwable userException = e.getCause();
98         propagateIfInstanceOf(userException, SkipThisScenarioException.class);
99         throw new UserCodeException(userException);
100       }
101     }
102 
103     @Override
workerClass()104     public Class<? extends Worker> workerClass() {
105       return ArbitraryMeasurementWorker.class;
106     }
107 
workerOptions()108     @Override public ImmutableMap<String, String> workerOptions() {
109       return ImmutableMap.of(GC_BEFORE_EACH_OPTION, options.get(GC_BEFORE_EACH_OPTION));
110     }
111 
112     @Override
getMeasurementCollectingVisitor()113     MeasurementCollectingVisitor getMeasurementCollectingVisitor() {
114       return new SingleMeasurementCollectingVisitor();
115     }
116   }
117 
118   @Override
instrumentOptions()119   public ImmutableSet<String> instrumentOptions() {
120     return ImmutableSet.of(GC_BEFORE_EACH_OPTION);
121   }
122 
123   private static final class SingleMeasurementCollectingVisitor extends AbstractLogMessageVisitor
124       implements MeasurementCollectingVisitor {
125     Optional<Measurement> measurement = Optional.absent();
126 
127     @Override
isDoneCollecting()128     public boolean isDoneCollecting() {
129       return measurement.isPresent();
130     }
131 
132     @Override
isWarmupComplete()133     public boolean isWarmupComplete() {
134       return true;
135     }
136 
137     @Override
getMeasurements()138     public ImmutableList<Measurement> getMeasurements() {
139       return ImmutableList.copyOf(measurement.asSet());
140     }
141 
142     @Override
visit(StopMeasurementLogMessage logMessage)143     public void visit(StopMeasurementLogMessage logMessage) {
144       this.measurement = Optional.of(Iterables.getOnlyElement(logMessage.measurements()));
145     }
146 
147     @Override
getMessages()148     public ImmutableList<String> getMessages() {
149       return ImmutableList.of();
150     }
151   }
152 }
153