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