Last active
May 18, 2021 20:09
-
-
Save Groostav/95cca95fd6f719664eadc1558d65f1c2 to your computer and use it in GitHub Desktop.
Ancient java code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.empowerops.visualizer; | |
import com.empowerops.common.*; | |
import com.empowerops.common.eventbus.EventBus; | |
import com.empowerops.common.ui.FXController; | |
import com.empowerops.common.ui.FXMLLoader; | |
import com.empowerops.dal.OptimizationMetadata; | |
import com.empowerops.dal.OptimizationModel; | |
import com.empowerops.jargon.OptimizerService; | |
import com.empowerops.jargon.events.NewExpensivePointFoundEvent; | |
import com.empowerops.jargon.events.SimulationFinishedEvent; | |
import com.empowerops.jargon.events.SimulationStartedEvent; | |
import com.empowerops.jargon.events.UserSelectedPreviousRunForDisplayEvent; | |
import com.empowerops.jargon.model.*; | |
import com.empowerops.linqalike.Factories; | |
import com.empowerops.linqalike.LinqingMap; | |
import com.empowerops.linqalike.Queryable; | |
import com.empowerops.linqalike.QueryableMap; | |
import com.google.common.annotations.VisibleForTesting; | |
import com.google.common.eventbus.Subscribe; | |
import com.google.inject.Inject; | |
import com.google.inject.assistedinject.Assisted; | |
import javafx.fxml.FXML; | |
import javafx.scene.control.ScrollPane; | |
import javafx.scene.layout.Region; | |
import javafx.scene.layout.VBox; | |
import javax.annotation.Nullable; | |
import java.text.DecimalFormat; | |
import java.time.Duration; | |
import java.time.Instant; | |
import java.util.Optional; | |
import java.util.UUID; | |
import java.util.concurrent.ScheduledExecutorService; | |
import java.util.concurrent.ScheduledFuture; | |
import java.util.concurrent.TimeUnit; | |
import java.util.concurrent.atomic.AtomicBoolean; | |
import java.util.logging.Level; | |
import java.util.logging.Logger; | |
import static com.empowerops.common.BootstrappingUtilities.getEnvInt; | |
import static com.empowerops.visualizer.OptimizationResultLineItem.*; | |
/** | |
* Created by Josh on 1/7/2015. | |
*/ | |
public class RuntimeStatisticsController implements FXController, VisualizationController { | |
private static final Logger log = Logger.getLogger(RuntimeStatisticsController.class.getCanonicalName()); | |
private final EventBus eventBus; | |
private final ModelUpdaterService updaterService; | |
private final LinqingMap<OptimizationResultLineItem, ResultItemController> itemControllerByType = new LinqingMap<>(); | |
private final DecimalFormat exponentFormatter = new DecimalFormat("0.000E0#"); | |
private final DecimalFormat simpleFormatter = new DecimalFormat("0.000"); | |
private OptimizationStopWatch stopwatch; | |
@FXML VBox elements; | |
@FXML ScrollPane view; | |
private @UpdateServiced OptimizationMat matrix; | |
private @UpdateServiced GraphModel graphModel; | |
public interface Factory { | |
RuntimeStatisticsController create(OptimizationMat optimizationMat, @Nullable OptimizationMetadata metadata); | |
} | |
@Inject | |
public RuntimeStatisticsController(EventBus eventBus, | |
FXMLLoader loader, | |
ResultItemController.Factory factory, | |
ModelUpdaterService updaterService, | |
GraphModel graphModel, | |
OptimizationStopWatch.Factory optimizationProgressFactory, | |
@Assisted OptimizationMat optimizationMat, | |
@Assisted @Nullable OptimizationMetadata metadata | |
) { | |
this.eventBus = eventBus; | |
this.updaterService = updaterService; | |
this.matrix = optimizationMat; | |
this.graphModel = graphModel; | |
for (OptimizationResultLineItem type : OptimizationResultLineItem.values()) { | |
ResultItemController controller = factory.create(type); | |
itemControllerByType.put(type, controller); | |
} | |
stopwatch = optimizationProgressFactory.create(itemControllerByType, graphModel.ofType(ProxyNode.class), metadata); | |
updaterService.registerForModelPush(this); | |
eventBus.register(this); | |
loader.load(this); | |
} | |
@Override | |
public void initialize() { | |
elements.getChildren().clear(); | |
initializeViewByControllers(); | |
setDisplayingValue(); | |
// because this constructor is called in response to an optimization started, | |
// we're simply going to start the task from here. | |
stopwatch.start(); | |
} | |
private void initializeViewByControllers() { | |
Queryable<OptimizationResultLineItem> itemsToDisplay = Factories.from(OptimizationResultLineItem.values()); | |
if (! matrix.isSingleObjective()) { | |
itemsToDisplay = itemsToDisplay.except(OptimizationResultLineItem.OptimumValue); | |
} | |
if (! graphModel.ofType(ExternalToolProxyNode.class).any()) { | |
itemsToDisplay = itemsToDisplay.except(OptimizationResultLineItem.SimulationTimeRemaining); | |
} | |
for (OptimizationResultLineItem displayItem : itemsToDisplay) { | |
ResultItemController controller = itemControllerByType.get(displayItem); | |
controller.getView().prefWidthProperty().bind(view.widthProperty()); | |
elements.getChildren().add(controller.getView()); | |
} | |
} | |
private void setDisplayingValue() { | |
try { | |
ResultItemController itemController2 = itemControllerByType.getValueFor(NumberOfFunctionEvaluations); | |
itemController2.setText(String.valueOf(matrix.size())); | |
if (matrix.isSingleObjective() && matrix.any()) { | |
ResultItemController itemController3 = itemControllerByType.getValueFor(OptimumValue); | |
Optional<Double> bestFeasiblePointFValue = matrix.getBestFeasiblePointFValue(); | |
Double newOptimumValue = bestFeasiblePointFValue.orElseGet(() -> matrix.getBestPointFValue()); | |
itemController3.setText(getTextForOptimumValue(newOptimumValue, bestFeasiblePointFValue.isPresent())); | |
itemController3.setToolTip("" + newOptimumValue); | |
} | |
} | |
catch (Exception e) { | |
log.log(Level.WARNING, "Problem in rendering results", e); | |
} | |
} | |
private String getTextForOptimumValue(double newOptimumValue, boolean isFeasible) { | |
String relativeFormattedString; | |
if(newOptimumValue <= -1000.0 || newOptimumValue >= +1000.0){ | |
relativeFormattedString = exponentFormatter.format(newOptimumValue); | |
} | |
else{ | |
relativeFormattedString = simpleFormatter.format(newOptimumValue); | |
} | |
if (! isFeasible) { | |
relativeFormattedString = relativeFormattedString + " (infeasible)"; | |
} | |
return relativeFormattedString; | |
} | |
@Subscribe | |
public void refreshResultPanelOnModelChanged(UserSelectedPreviousRunForDisplayEvent event) { | |
setDisplayingValue(); | |
} | |
@Override | |
public void refreshVisualizationsOn(NewExpensivePointFoundEvent event) { | |
setDisplayingValue(); | |
} | |
@Override | |
public Region getView() { | |
return view; | |
} | |
@Override | |
public void dispose() { | |
try { | |
updaterService.unregisterFromModelPush(this); | |
eventBus.unregister(this); | |
stopwatch.dispose(); | |
} | |
catch (Exception exception) { | |
log.log(Level.WARNING, "encountered error on disposal", exception); | |
} | |
} | |
/** | |
* Created by Josh on 1/14/2015. | |
*/ | |
public static class OptimizationStopWatch implements Disposable { | |
private static final Class<OptimizationStopWatch> clazz = OptimizationStopWatch.class; | |
private static final Logger log = Logger.getLogger(clazz.getCanonicalName()); | |
//47 is a prime number close to 50. | |
// - using a prime gives the timer the appearance of tracking values | |
// all the way down to the thousandth of a second (1ms) | |
// - 50 ms is slow to a computer but fast to a human, | |
// thus it makes a good value for a period from both a usability view and a performance view. | |
private static final int PollPeriodMillis = getEnvInt(clazz, "PollPeriodMillis").orElse(47); | |
private final ScheduledExecutorService blockableUpdaterThread; | |
private final EventBus eventBus; | |
private final QueryableMap<OptimizationResultLineItem, ResultItemController> itemControllerByType; | |
private final OptimizerService optimizerService; | |
private final ModelUpdaterService updaterService; | |
private final @Nullable OptimizationMetadata metadata; | |
private ScheduledFuture<?> runningTask; | |
private @UpdateServiced GraphModel graphModel; | |
private Optional<UUID> runningAppId = Optional.empty(); | |
private Optional<Instant> appStartTime = Optional.empty(); | |
public interface Factory { | |
OptimizationStopWatch create(QueryableMap<OptimizationResultLineItem, ResultItemController> itemControllerByType, | |
Queryable<ProxyNode> proxyNodes, | |
@Assisted("metadata") @Nullable OptimizationMetadata metadata); | |
} | |
private final Queryable<ProxyNode> proxyNodes; | |
private final AtomicBoolean wasDisposed = new AtomicBoolean(false); | |
@Inject | |
public OptimizationStopWatch(ThreadFactory threadFactory, | |
ModelUpdaterService updaterService, | |
OptimizerService optimizerService, | |
EventBus eventBus, | |
GraphModel graphModel, | |
@Assisted QueryableMap<OptimizationResultLineItem, ResultItemController> itemControllerByType, | |
@Assisted Queryable<ProxyNode> proxyNodes, | |
@Assisted("metadata") @Nullable OptimizationMetadata metadata | |
) { | |
this.updaterService = updaterService; | |
this.optimizerService = optimizerService; | |
this.eventBus = eventBus; | |
this.itemControllerByType = itemControllerByType; | |
this.proxyNodes = proxyNodes; | |
this.graphModel = graphModel; | |
this.metadata = metadata; | |
blockableUpdaterThread = threadFactory.createScheduledExecutor(this, Sequential.INSTANCE); | |
eventBus.register(this); | |
updaterService.registerForModelPush(this); | |
} | |
@Override | |
public void dispose() { | |
if (! wasDisposed.getAndSet(true)) { | |
updaterService.unregisterFromModelPush(this); | |
if(runningTask != null) runningTask.cancel(false); | |
eventBus.unregister(this); | |
} | |
} | |
public void start() { | |
if(metadata == OptimizationMetadata.Companion.getNullInstance()) return; | |
runningTask = blockableUpdaterThread.scheduleWithFixedDelay( | |
this::updatedDisplayedTimeValues, 0L, | |
PollPeriodMillis, TimeUnit.MILLISECONDS | |
); | |
} | |
// TODO: theres a volatile issue on `model` and a thread-confinement issue on setText here. | |
// TODO: replace with coroutines. | |
@VisibleForTesting void updatedDisplayedTimeValues() { | |
//take a snap-shot of the values to avoid the clocks creeping forward while we update the view. | |
Duration currentRunTime; | |
Duration simulationTime; | |
Duration oasisOverheadTime; | |
Duration sessionTime; | |
if (optimizerService.isMidExecution()) { | |
currentRunTime = optimizerService.getCurrentRunTime(); | |
simulationTime = optimizerService.getSimulationTime(); | |
oasisOverheadTime = optimizerService.getOasisOverheadTime(); | |
sessionTime = optimizerService.getSessionTime(); | |
} | |
else if (metadata != null){ | |
currentRunTime = metadata.getRunTime(); | |
simulationTime = metadata.getSimulationTime(); | |
oasisOverheadTime = metadata.getOasisOverheadTime(); | |
sessionTime = metadata.getSessionTime(); | |
} | |
else { | |
throw new IllegalStateException("not running and no metadata provided"); | |
} | |
setDisplayingTimeWithFormat(CurrentRunTime, currentRunTime); | |
setDisplayingTimeWithFormat(SimulationExecution, simulationTime); | |
setDisplayingTimeWithFormat(AlgorithmOverhead, oasisOverheadTime); | |
setDisplayingTimeWithFormat(SessionTime, sessionTime); | |
if (! proxyNodes.any() || ! optimizerService.isRunning()) { | |
return; | |
} | |
Duration duration = calculateTimeRemainingBeforeTimeoutOnCurrentSimulation(); | |
ResultItemController itemController = itemControllerByType.getValueFor(SimulationTimeRemaining); | |
String formattedTime = formatDuration(duration); | |
itemController.setText(formattedTime); | |
} | |
@Subscribe | |
public synchronized void noteRunningToolOn(SimulationStartedEvent event) { | |
this.runningAppId = Optional.of(event.getNodeId()); | |
this.appStartTime = Optional.of(event.getTimeOfExecStart()); | |
} | |
@Subscribe | |
public synchronized void noteRunningToolOn(SimulationFinishedEvent event) { | |
this.runningAppId = Optional.empty(); | |
this.appStartTime = Optional.empty(); | |
} | |
private void setDisplayingTimeWithFormat(OptimizationResultLineItem resultLineItem, Duration duration) { | |
String formattedTime = formatDuration(duration); | |
itemControllerByType.getValueFor(resultLineItem).setText(formattedTime); | |
} | |
private Duration calculateTimeRemainingBeforeTimeoutOnCurrentSimulation() { | |
if (graphModel.ofType(ExternalToolProxyNode.class).isEmpty()) { | |
return Duration.ZERO; | |
} | |
if (! runningAppId.isPresent()) { | |
return Duration.ZERO; | |
} | |
Optional<ExternalToolProxyNode> node = graphModel | |
.ofType(ExternalToolProxyNode.class) | |
.singleOrDefault(etNode -> etNode.getID().equals(runningAppId.get())); | |
if (! node.isPresent()) { | |
log.warning( | |
"tried generating running time on an ETPN id=" + runningAppId.get() + ", " + | |
"but that tool doesnt exist on this graph?" | |
); | |
return Heartbeat.FOREVER; | |
} | |
FormattedDuration timeout = node.get().getToolTemplate().getTimeout(); | |
if (timeout.asDuration() == Durations.Forever) { | |
return Durations.Forever; | |
} | |
Duration elapsedOnApp = Duration.between(appStartTime.get(), Instant.now()); | |
Duration remaining = timeout.asDuration().minus(elapsedOnApp); | |
return remaining.isNegative() ? Duration.ZERO : remaining; | |
} | |
/** | |
* This is equivalent to | |
* long hours = seconds / SECONDS_PER_HOUR; | |
* int minutes = (int) ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE); | |
* int secs = (int) (seconds % SECONDS_PER_MINUTE); | |
*/ | |
public static String formatDuration(Duration duration) { | |
duration = duration.compareTo(Durations.Forever) >= 0 ? Duration.ZERO : duration; | |
long hours = duration.toHours(); | |
long minutes = duration.minusHours(duration.toHours()).toMinutes(); | |
long seconds = duration.minusMinutes(duration.toMinutes()).getSeconds(); | |
long millis = duration.minusSeconds(duration.getSeconds()).toMillis(); | |
String positive = String.format( | |
"%d:%02d:%02d.%03d", | |
hours, | |
minutes, | |
seconds, | |
millis | |
); | |
return duration.isNegative() ? "-" + positive : positive; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment