1e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin/*
2e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * Copyright (C) 2011 Google Inc.
3e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin *
4e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License");
5e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * you may not use this file except in compliance with the License.
6e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * You may obtain a copy of the License at
7e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin *
8e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0
9e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin *
10e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * Unless required by applicable law or agreed to in writing, software
11e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS,
12e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * See the License for the specific language governing permissions and
14e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * limitations under the License.
15e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin */
16e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
17e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinpackage com.google.caliper.runner;
18e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
19e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport static com.google.caliper.runner.CommonInstrumentOptions.GC_BEFORE_EACH_OPTION;
20e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport static com.google.common.base.Throwables.propagateIfInstanceOf;
21e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
22e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.caliper.api.SkipThisScenarioException;
23e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.caliper.bridge.AbstractLogMessageVisitor;
24e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.caliper.bridge.StopMeasurementLogMessage;
25e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.caliper.model.ArbitraryMeasurement;
26e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.caliper.model.Measurement;
27e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.caliper.platform.Platform;
28e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.caliper.platform.SupportedPlatform;
29e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.caliper.util.Util;
30e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.caliper.worker.ArbitraryMeasurementWorker;
31e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.caliper.worker.Worker;
32e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.common.base.Optional;
33e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.common.collect.ImmutableList;
34e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.common.collect.ImmutableMap;
35e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.common.collect.ImmutableSet;
36e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport com.google.common.collect.Iterables;
37e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
38e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport java.lang.reflect.InvocationTargetException;
39e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinimport java.lang.reflect.Method;
40e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
41e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin/**
42e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * Instrument for taking an arbitrary measurement. When using this instrument, the benchmark code
43e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin * itself returns the value. See {@link ArbitraryMeasurement}.
44e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin */
45e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin@SupportedPlatform(Platform.Type.JVM)
46e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffinpublic final class ArbitraryMeasurementInstrument extends Instrument {
47e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  @Override public boolean isBenchmarkMethod(Method method) {
48e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    return method.isAnnotationPresent(ArbitraryMeasurement.class);
49e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  }
50e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
51e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  @Override
52e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  public Instrumentation createInstrumentation(Method benchmarkMethod)
53e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      throws InvalidBenchmarkException {
54e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    if (benchmarkMethod.getParameterTypes().length != 0) {
55e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      throw new InvalidBenchmarkException(
56e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin          "Arbitrary measurement methods should take no parameters: " + benchmarkMethod.getName());
57e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
58e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
59e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    if (benchmarkMethod.getReturnType() != double.class) {
60e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      throw new InvalidBenchmarkException(
61e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin          "Arbitrary measurement methods must have a return type of double: "
62e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin              + benchmarkMethod.getName());
63e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
64e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
65e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    // Static technically doesn't hurt anything, but it's just the completely wrong idea
66e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    if (Util.isStatic(benchmarkMethod)) {
67e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      throw new InvalidBenchmarkException(
68e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin          "Arbitrary measurement methods must not be static: " + benchmarkMethod.getName());
69e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
70e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
71e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    if (!Util.isPublic(benchmarkMethod)) {
72e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      throw new InvalidBenchmarkException(
73e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin          "Arbitrary measurement methods must be public: " + benchmarkMethod.getName());
74e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
75e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
76e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    return new ArbitraryMeasurementInstrumentation(benchmarkMethod);
77e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  }
78e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
79e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  @Override public TrialSchedulingPolicy schedulingPolicy() {
80e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    // We could allow it here but in general it would depend on the particular measurement so it
81e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    // should probably be configured by the user.  For now we just disable it.
82e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    return TrialSchedulingPolicy.SERIAL;
83e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  }
84e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
85e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  private final class ArbitraryMeasurementInstrumentation extends Instrumentation {
86e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    protected ArbitraryMeasurementInstrumentation(Method benchmarkMethod) {
87e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      super(benchmarkMethod);
88e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
89e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
90e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    @Override
91e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    public void dryRun(Object benchmark) throws InvalidBenchmarkException {
92e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      try {
93e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin        benchmarkMethod.invoke(benchmark);
94e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      } catch (IllegalAccessException impossible) {
95e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin        throw new AssertionError(impossible);
96e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      } catch (InvocationTargetException e) {
97e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin        Throwable userException = e.getCause();
98e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin        propagateIfInstanceOf(userException, SkipThisScenarioException.class);
99e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin        throw new UserCodeException(userException);
100e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      }
101e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
102e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
103e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    @Override
104e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    public Class<? extends Worker> workerClass() {
105e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      return ArbitraryMeasurementWorker.class;
106e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
107e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
108e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    @Override public ImmutableMap<String, String> workerOptions() {
109e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      return ImmutableMap.of(GC_BEFORE_EACH_OPTION, options.get(GC_BEFORE_EACH_OPTION));
110e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
111e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
112e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    @Override
113e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    MeasurementCollectingVisitor getMeasurementCollectingVisitor() {
114e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      return new SingleMeasurementCollectingVisitor();
115e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
116e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  }
117e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
118e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  @Override
119e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  public ImmutableSet<String> instrumentOptions() {
120e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    return ImmutableSet.of(GC_BEFORE_EACH_OPTION);
121e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  }
122e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
123e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  private static final class SingleMeasurementCollectingVisitor extends AbstractLogMessageVisitor
124e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      implements MeasurementCollectingVisitor {
125e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    Optional<Measurement> measurement = Optional.absent();
126e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
127e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    @Override
128e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    public boolean isDoneCollecting() {
129e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      return measurement.isPresent();
130e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
131e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
132e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    @Override
133e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    public boolean isWarmupComplete() {
134e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      return true;
135e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
136e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
137e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    @Override
138e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    public ImmutableList<Measurement> getMeasurements() {
139e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      return ImmutableList.copyOf(measurement.asSet());
140e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
141e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
142e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    @Override
143e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    public void visit(StopMeasurementLogMessage logMessage) {
144e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      this.measurement = Optional.of(Iterables.getOnlyElement(logMessage.measurements()));
145e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
146e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin
147e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    @Override
148e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    public ImmutableList<String> getMessages() {
149e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin      return ImmutableList.of();
150e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin    }
151e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin  }
152e236301e5fc778bffe1748ed80d7936e6c807012Paul Duffin}
153