/* Copyright 2012 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.arbeitspferde.groningen.config;
import org.arbeitspferde.groningen.exceptions.InvalidConfigurationException;
import org.arbeitspferde.groningen.experimentdb.jvmflags.JvmFlag;
import org.arbeitspferde.groningen.proto.GroningenConfigProto.ProgramConfiguration;
import java.util.List;
/**
* Map a protobuf JvmSearchSpace to a GenericSearchSpaceBundle.
*/
public class ProtoBufSearchSpaceBundle extends GenericSearchSpaceBundle {
/**
* Map each of the command line arguments from the setting in the protobuf to the enum, throwing
* exceptions if the user requests that all fields must be present (all translates to including at
* least one of the gc modes).
*
* @param protoSpace the protocol buffer {@link ProgramConfiguration.JvmSearchSpace} from which we
* should create this {@link SearchSpaceBundle}
* @param requireAll true iff the user wants an exception to be thrown for fields that are not
* specified. If false and a field is not specified, the default range will be pulled from
* {@link JvmFlag}.
* @throws InvalidConfigurationException a value or range was either not within the expected
* bounds or the complete set was requested but not specified in the protobuf.
*/
public ProtoBufSearchSpaceBundle(final ProgramConfiguration.JvmSearchSpace protoSpace,
final boolean requireAll) throws InvalidConfigurationException {
// initial param check - the rest of the CommandLineArgs will be checked
// their entry is instantiated
if (protoSpace.getGcModeCount() == 0 && requireAll) {
throw new InvalidConfigurationException("no gc mode specified");
}
/*
* Run through all the different enums
*
* This is kind of a lot of boiler plate code with unnecessary calls to the get methods for
* fields that were not defined in the protobuf. It perhaps could be condensed via annotations
* or reflection. The latter was avoided in favor of compile time verification of method names.
* The former was avoided due to lack of experience by the implementor, but from my amount of
* understanding, an annotation based method would still require use of reflection.
*
* TODO(team): if requireAll is true, we make the user pin values that are not going to be
* included in the final command line. It would be good if we can require only the values that
* in 'mutually inclusive' sets so users don't have to pin values that have no bearing. But
* that's annoying and time consuming for mach 1, and the workaround is not too large a burden.
*/
makeInt64RangeEntry(JvmFlag.ADAPTIVE_SIZE_DECREMENT_SCALE_FACTOR,
protoSpace.hasAdaptiveSizeDecrementScaleFactor(),
protoSpace.getAdaptiveSizeDecrementScaleFactor(), requireAll);
makeInt64RangeEntry(JvmFlag.CMS_EXP_AVG_FACTOR, protoSpace.hasCmsExpAvgFactor(),
protoSpace.getCmsExpAvgFactor(), requireAll);
makeInt64RangeEntry(JvmFlag.CMS_INCREMENTAL_DUTY_CYCLE,
protoSpace.hasCmsIncrementalDutyCycle(), protoSpace.getCmsIncrementalDutyCycle(),
requireAll);
makeInt64RangeEntry(JvmFlag.CMS_INCREMENTAL_DUTY_CYCLE_MIN,
protoSpace.hasCmsIncrementalDutyCycleMin(), protoSpace.getCmsIncrementalDutyCycleMin(),
requireAll);
makeInt64RangeEntry(JvmFlag.CMS_INCREMENTAL_OFFSET, protoSpace.hasCmsIncrementalOffset(),
protoSpace.getCmsIncrementalOffset(), requireAll);
makeInt64RangeEntry(JvmFlag.CMS_INCREMENTAL_SAFETY_FACTOR,
protoSpace.hasCmsIncrementalSafetyFactor(), protoSpace.getCmsIncrementalSafetyFactor(),
requireAll);
makeInt64RangeEntry(JvmFlag.CMS_INITIATING_OCCUPANCY_FRACTION,
protoSpace.hasCmsInitiatingOccupancyFraction(),
protoSpace.getCmsInitiatingOccupancyFraction(), requireAll);
makeInt64RangeEntry(JvmFlag.GC_TIME_RATIO, protoSpace.hasGcTimeRatio(),
protoSpace.getGcTimeRatio(), requireAll);
makeInt64RangeEntry(JvmFlag.MAX_GC_PAUSE_MILLIS, protoSpace.hasMaxGcPauseMillis(),
protoSpace.getMaxGcPauseMillis(), requireAll);
makeInt64RangeEntry(JvmFlag.MAX_HEAP_FREE_RATIO, protoSpace.hasMaxHeapFreeRatio(),
protoSpace.getMaxHeapFreeRatio(), requireAll);
makeInt64RangeEntry(JvmFlag.MIN_HEAP_FREE_RATIO, protoSpace.hasMinHeapFreeRatio(),
protoSpace.getMinHeapFreeRatio(), requireAll);
makeInt64RangeEntry(JvmFlag.NEW_RATIO, protoSpace.hasNewRatio(), protoSpace.getNewRatio(),
requireAll);
makeInt64RangeEntry(JvmFlag.NEW_SIZE, protoSpace.hasNewSize(), protoSpace.getNewSize(),
requireAll);
makeInt64RangeEntry(JvmFlag.MAX_NEW_SIZE, protoSpace.hasMaxNewSize(),
protoSpace.getMaxNewSize(), requireAll);
makeInt64RangeEntry(JvmFlag.PARALLEL_GC_THREADS, protoSpace.hasParallelGcThreads(),
protoSpace.getParallelGcThreads(), requireAll);
makeInt64RangeEntry(JvmFlag.SURVIVOR_RATIO, protoSpace.hasSurvivorRatio(),
protoSpace.getSurvivorRatio(), requireAll);
makeInt64RangeEntry(JvmFlag.TENURED_GENERATION_SIZE_INCREMENT,
protoSpace.hasTenuredGenerationSizeIncrement(),
protoSpace.getTenuredGenerationSizeIncrement(), requireAll);
makeInt64RangeEntry(JvmFlag.HEAP_SIZE, protoSpace.hasHeapSize(), protoSpace.getHeapSize(),
requireAll);
makeInt64RangeEntry(JvmFlag.YOUNG_GENERATION_SIZE_INCREMENT,
protoSpace.hasYoungGenerationSizeIncrement(), protoSpace.getYoungGenerationSizeIncrement(),
requireAll);
makeBoolEntry(JvmFlag.CMS_INCREMENTAL_MODE, protoSpace.hasCmsIncrementalMode(),
protoSpace.getCmsIncrementalMode(), requireAll);
makeBoolEntry(JvmFlag.CMS_INCREMENTAL_PACING, protoSpace.hasCmsIncrementalPacing(),
protoSpace.getCmsIncrementalPacing(), requireAll);
makeBoolEntry(JvmFlag.USE_CMS_INITIATING_OCCUPANCY_ONLY,
protoSpace.hasUseCmsInitiatingOccupancyOnly(),
protoSpace.getUseCmsInitiatingOccupancyOnly(), requireAll);
makeInt64RangeEntry(JvmFlag.SOFT_REF_LRU_POLICY_MS_PER_MB,
protoSpace.hasSoftRefLruPolicyMsPerMb(), protoSpace.getSoftRefLruPolicyMsPerMb(),
requireAll);
/*
* Finally deal with GC Mode
*
* We have a repeated list here so that we can select multiple gc modes over which to search.
* However, squashing these down to boolean values seems wrong.
*
* TODO(team): Really, we want to return a set of the available gc modes but need to
* understand implications on hypothesizer and the GA in general to see if that makes sense.
* Not for mach1.
*/
if (protoSpace.getGcModeCount() == 0) {
// use the 'full' (it is boolean) search step to look over each gcmode
for (JvmFlag gcModeArg : JvmFlag.getGcModeArguments()) {
makeBoolEntry(gcModeArg, false, false, false);
}
} else {
/*
* this list is puny so we can do contains() searches on it even if we have a dumb user who
* puts lots of duplicates in their config....
*
* Essentially, we say we have a value to pin to - true if it is present, false otherwise.
*/
List<ProgramConfiguration.JvmSearchSpace.GcMode> gcModes = protoSpace.getGcModeList();
for (ProgramConfiguration.JvmSearchSpace.GcMode mode :
ProgramConfiguration.JvmSearchSpace.GcMode.values()) {
makeBoolEntry(JvmFlag.getGcModeArgument(mode), true, gcModes.contains(mode), false);
}
}
}
/**
* Small method to do verification on an Int64Range and make a
* SearchSpaceEntry for it
*
* @param arg the {@link JvmFlag} with which this range/{@link SearchSpaceBundle.SearchSpaceEntry}
* shall be equated
* @param has true iff the protobuf contained a value for this
* @param range user described range
* @param required if the field was not included, should an exception be thrown
* @throws InvalidConfigurationException the range was inconsistent or missing when required
*/
protected void makeInt64RangeEntry(final JvmFlag arg,
final boolean has,
final ProgramConfiguration.JvmSearchSpace.Int64Range range,
final boolean required) throws InvalidConfigurationException {
GenericSearchSpaceEntry entry = null;
if (has) {
// validation has been pushed to this function, so validate everything
if (range.hasValue() && (range.hasFloor() || range.hasCeiling())) {
throw new InvalidConfigurationException("had value and range setting for " + arg.name());
} else if (range.hasValue()) {
if (range.getValue() < arg.getMinimum() || range.getValue() > arg.getMaximum()) {
StringBuilder sb = new StringBuilder();
sb.append("value outside default range of ").append(arg.getMinimum()).append(":")
.append(arg.getMaximum()).append(" for ").append(arg.name());
throw new InvalidConfigurationException(sb.toString());
}
entry = new GenericSearchSpaceEntry(arg, range.getValue(), range.getValue(), 0L);
} else if (range.hasFloor() && range.hasCeiling()) {
if (range.getFloor() < arg.getMinimum() || range.getCeiling() > arg.getMaximum()) {
StringBuilder sb = new StringBuilder();
sb.append("specified range ").append(range.getFloor()).append(":")
.append(range.getCeiling()).append(" has endpoint outside default range of ")
.append(arg.getMinimum()).append(":").append(arg.getMaximum()).append(" for ")
.append(arg.name());
throw new InvalidConfigurationException(sb.toString());
}
// TODO(team): add default step size to JvmFlag and clean up hardcoded
// value
entry =
new GenericSearchSpaceEntry(arg, range.getFloor(), range.getCeiling(),
range.hasStepSize() ? range.getStepSize() : 1L);
} else {
throw new InvalidConfigurationException("incomplete range specified for " + arg.name());
}
} else if (required) {
throw new InvalidConfigurationException("missing required Int64Range " + arg.name());
} else {
// TODO(team): add default step size to JvmFlag and clean up hardcoded
// value
entry = new GenericSearchSpaceEntry(arg, arg.getMinimum(), arg.getMaximum(),
arg.getStepSize());
}
// finally the entry is ready to be stored
entries[arg.ordinal()] = entry;
}
/**
* Small method to do verification on an Int64Range and make a SearchSpaceEntry for it.
*
* @param arg the {@link JvmFlag} with which this
* range/{@link SearchSpaceBundle.SearchSpaceEntry} shall be equated.
* @param has true iff the protobuf contained a value for this
* @param truthVal which truth value the user selected if present
* @param required if the field was not included, should an exception be thrown
* @throws InvalidConfigurationException the range was inconsistent or missing when required
*/
protected void makeBoolEntry(final JvmFlag arg,
final boolean has,
final boolean truthVal,
final boolean required) throws InvalidConfigurationException {
GenericSearchSpaceEntry entry = null;
if (has) {
long val = (truthVal) ? 1L : 0L;
entry = new GenericSearchSpaceEntry(arg, val, val, 0L);
} else if (required) {
throw new InvalidConfigurationException("missing required boolean " + arg.name());
} else {
// TODO(team): pull from JvmFlag when its back in
entry = new GenericSearchSpaceEntry(arg, 0L, 1L, 1L);
}
// finally the entry is ready to be stored
entries[arg.ordinal()] = entry;
}
}