package org.arbeitspferde.groningen;
import com.google.common.collect.Lists;
import com.google.protobuf.InvalidProtocolBufferException;
import org.arbeitspferde.groningen.common.EvaluatedSubject;
import org.arbeitspferde.groningen.config.GroningenConfig;
import org.arbeitspferde.groningen.config.ProtoBufConfig;
import org.arbeitspferde.groningen.exceptions.InvalidConfigurationException;
import org.arbeitspferde.groningen.experimentdb.CommandLine;
import org.arbeitspferde.groningen.experimentdb.ExperimentDb;
import org.arbeitspferde.groningen.experimentdb.SubjectStateBridge;
import org.arbeitspferde.groningen.experimentdb.jvmflags.JvmFlag;
import org.arbeitspferde.groningen.experimentdb.jvmflags.JvmFlagSet;
import org.arbeitspferde.groningen.proto.ExperimentDbProtos;
import org.arbeitspferde.groningen.proto.GroningenConfigProto.ProgramConfiguration;
import org.arbeitspferde.groningen.utility.PinnedClock;
import org.joda.time.Instant;
import java.util.List;
/**
* PipelineHistoryState encapsulates pipeline state after each iteration (unlike PipelineState
* it includes evaluated experiment results).
*
* PipelineHistoryState is intended for HistoryDatastore. Please note that although
* HistoryDatastore's functionality resembles event evaluation system (see EventLoggerService),
* it's different from the latter. Unlike EventLoggerService, HistoryDatastore (and consequently,
* PipelineHistoryState is multiple-pipelines-aware).
*
* Also, although PipelineHistoryState resembles PipelineState, they're kept separate, because
* their respective datastores, HistoryDatastore and Datastore, were designed to be totally
* independent of each other.
*/
public class PipelineHistoryState {
private final PipelineId pipelineId;
private final GroningenConfig config;
private final Instant endTimestamp;
private final EvaluatedSubject[] evaluatedSubjects;
private final long experimentId;
public PipelineHistoryState(PipelineId pipelineId, GroningenConfig config, Instant endTimestamp,
EvaluatedSubject[] evluatedSubjects, long experimentId) {
this.pipelineId = pipelineId;
this.config = config;
this.endTimestamp = endTimestamp;
this.evaluatedSubjects = evluatedSubjects;
this.experimentId = experimentId;
}
public PipelineHistoryState(byte[] bytes) {
ExperimentDbProtos.PipelineHistoryState stateProto;
try {
stateProto = ExperimentDbProtos.PipelineHistoryState.parseFrom(bytes);
} catch (InvalidProtocolBufferException e) {
throw new RuntimeException(e);
}
pipelineId = new PipelineId(stateProto.getId().getId());
try {
config = new ProtoBufConfig(stateProto.getConfiguration());
} catch (InvalidConfigurationException e) {
throw new RuntimeException(e);
}
endTimestamp = new Instant(stateProto.getEndTimestamp());
experimentId = stateProto.getExperimentId();
// TODO(mbushkov): we don't need it here. Refactor to create SubjectStateBridge without it.
ExperimentDb experimentDb = new ExperimentDb();
List<EvaluatedSubject> evaluatedSubjectsList = Lists.newArrayList();
for (ExperimentDbProtos.EvaluatedSubject esProto : stateProto.getEvaluatedSubjectsList()) {
SubjectStateBridge bridge = experimentDb.makeSubject(esProto.getSubject().getId());
final JvmFlagSet.Builder builder = JvmFlagSet.builder();
final ExperimentDbProtos.CommandLine cl = esProto.getSubject().getCommandLine();
for (final ExperimentDbProtos.CommandLineArgument arg : cl.getArgumentList()) {
final int value = Integer.parseInt(arg.getValue());
final JvmFlag argument = JvmFlag.valueOf(arg.getName());
switch (argument) {
case ADAPTIVE_SIZE_DECREMENT_SCALE_FACTOR:
builder.withValue(JvmFlag.ADAPTIVE_SIZE_DECREMENT_SCALE_FACTOR, value);
break;
case CMS_EXP_AVG_FACTOR:
builder.withValue(JvmFlag.CMS_EXP_AVG_FACTOR, value);
break;
case CMS_INCREMENTAL_DUTY_CYCLE:
builder.withValue(JvmFlag.CMS_INCREMENTAL_DUTY_CYCLE, value);
break;
case CMS_INCREMENTAL_DUTY_CYCLE_MIN:
builder.withValue(JvmFlag.CMS_INCREMENTAL_DUTY_CYCLE_MIN, value);
break;
case CMS_INCREMENTAL_OFFSET:
builder.withValue(JvmFlag.CMS_INCREMENTAL_OFFSET, value);
break;
case CMS_INCREMENTAL_SAFETY_FACTOR:
builder.withValue(JvmFlag.CMS_INCREMENTAL_SAFETY_FACTOR, value);
break;
case CMS_INITIATING_OCCUPANCY_FRACTION:
builder.withValue(JvmFlag.CMS_INITIATING_OCCUPANCY_FRACTION, value);
break;
case GC_TIME_RATIO:
builder.withValue(JvmFlag.GC_TIME_RATIO, value);
break;
case HEAP_SIZE:
builder.withValue(JvmFlag.HEAP_SIZE, value);
break;
case MAX_GC_PAUSE_MILLIS:
builder.withValue(JvmFlag.MAX_GC_PAUSE_MILLIS, value);
break;
case MAX_HEAP_FREE_RATIO:
builder.withValue(JvmFlag.MAX_HEAP_FREE_RATIO, value);
break;
case MIN_HEAP_FREE_RATIO:
builder.withValue(JvmFlag.MIN_HEAP_FREE_RATIO, value);
break;
case NEW_RATIO:
builder.withValue(JvmFlag.NEW_RATIO, value);
break;
case NEW_SIZE:
builder.withValue(JvmFlag.NEW_SIZE, value);
break;
case MAX_NEW_SIZE:
builder.withValue(JvmFlag.MAX_NEW_SIZE, value);
break;
case PARALLEL_GC_THREADS:
builder.withValue(JvmFlag.PARALLEL_GC_THREADS, value);
break;
case SOFT_REF_LRU_POLICY_MS_PER_MB:
builder.withValue(JvmFlag.SOFT_REF_LRU_POLICY_MS_PER_MB, value);
break;
case SURVIVOR_RATIO:
builder.withValue(JvmFlag.SURVIVOR_RATIO, value);
break;
case TENURED_GENERATION_SIZE_INCREMENT:
builder.withValue(JvmFlag.TENURED_GENERATION_SIZE_INCREMENT, value);
break;
case YOUNG_GENERATION_SIZE_INCREMENT:
builder.withValue(JvmFlag.YOUNG_GENERATION_SIZE_INCREMENT, value);
break;
case USE_CONC_MARK_SWEEP_GC:
builder.withValue(JvmFlag.USE_CONC_MARK_SWEEP_GC, value);
break;
case USE_PARALLEL_GC:
builder.withValue(JvmFlag.USE_PARALLEL_GC, value);
break;
case USE_PARALLEL_OLD_GC:
builder.withValue(JvmFlag.USE_PARALLEL_OLD_GC, value);
break;
case USE_SERIAL_GC:
builder.withValue(JvmFlag.USE_SERIAL_GC, value);
break;
case CMS_INCREMENTAL_MODE:
builder.withValue(JvmFlag.CMS_INCREMENTAL_MODE, value);
break;
case CMS_INCREMENTAL_PACING:
builder.withValue(JvmFlag.CMS_INCREMENTAL_PACING, value);
break;
case USE_CMS_INITIATING_OCCUPANCY_ONLY:
builder.withValue(JvmFlag.USE_CMS_INITIATING_OCCUPANCY_ONLY, value);
break;
}
}
final JvmFlagSet jvmFlagSet = builder.build();
bridge.storeCommandLine(jvmFlagSet);
EvaluatedSubject evaluatedSubject = new EvaluatedSubject(
new PinnedClock(esProto.getEndTimestamp()),
bridge,
esProto.getFitness(),
stateProto.getExperimentId());
evaluatedSubject.setClusterName(esProto.getSubject().getClusterName());
evaluatedSubject.setSubjectGroupIndex((int) esProto.getSubject().getSubjectGroupIndex());
evaluatedSubject.setSubjectGroupName(esProto.getSubject().getSubjectGroupName());
evaluatedSubject.setUserName(esProto.getSubject().getUserName());
evaluatedSubject.setDefault(esProto.getSubject().getIsDefault());
evaluatedSubjectsList.add(evaluatedSubject);
}
evaluatedSubjects = evaluatedSubjectsList.toArray(new EvaluatedSubject[] {});
}
public byte[] toBytes() {
ExperimentDbProtos.PipelineId.Builder idProtoBuilder =
ExperimentDbProtos.PipelineId.newBuilder();
idProtoBuilder.setId(pipelineId.id());
ExperimentDbProtos.PipelineId idProto = idProtoBuilder.build();
ProgramConfiguration configurationProto = config.getProtoConfig();
List<ExperimentDbProtos.EvaluatedSubject> evaluatesSubjectsProtos = Lists.newArrayList();
for (EvaluatedSubject es : evaluatedSubjects) {
ExperimentDbProtos.EvaluatedSubject.Builder espBuilder =
ExperimentDbProtos.EvaluatedSubject.newBuilder();
// Build Subject proto
ExperimentDbProtos.Subject.Builder spBuilder = ExperimentDbProtos.Subject.newBuilder();
spBuilder.setClusterName(es.getClusterName());
spBuilder.setSubjectGroupIndex(es.getSubjectGroupIndex());
spBuilder.setSubjectGroupName(es.getSubjectGroupName());
spBuilder.setUserName(es.getUserName());
spBuilder.setIsDefault(es.isDefault());
spBuilder.setId(es.getBridge().getIdOfObject());
// Copy the command line
final JvmFlag[] arguments = JvmFlag.values();
final CommandLine commandLine = es.getBridge().getCommandLine();
final ExperimentDbProtos.CommandLine.Builder commandLineBuilder =
ExperimentDbProtos.CommandLine.newBuilder();
for (final JvmFlag argument : arguments) {
final long value = commandLine.getValue(argument);
final ExperimentDbProtos.CommandLineArgument.Builder argumentBuilder =
ExperimentDbProtos.CommandLineArgument.newBuilder();
argumentBuilder.setName(argument.name());
argumentBuilder.setValue(String.valueOf(value));
commandLineBuilder.addArgument(argumentBuilder);
}
spBuilder.setCommandLine(commandLineBuilder);
espBuilder.setSubject(spBuilder.build());
espBuilder.setEndTimestamp(es.getTimeStamp().getMillis());
espBuilder.setFitness(es.getFitness());
evaluatesSubjectsProtos.add(espBuilder.build());
}
ExperimentDbProtos.PipelineHistoryState.Builder stateProtoBuilder =
ExperimentDbProtos.PipelineHistoryState.newBuilder();
stateProtoBuilder.setId(idProto);
stateProtoBuilder.setConfiguration(configurationProto);
stateProtoBuilder.addAllEvaluatedSubjects(evaluatesSubjectsProtos);
stateProtoBuilder.setEndTimestamp(endTimestamp.getMillis());
stateProtoBuilder.setExperimentId(experimentId);
return stateProtoBuilder.build().toByteArray();
}
public PipelineId pipelineId() {
return pipelineId;
}
public GroningenConfig config() {
return config;
}
public Instant endTimestamp() {
return endTimestamp;
}
public EvaluatedSubject[] evaluatedSubjects() {
return evaluatedSubjects;
}
}