Skip to content

Commit

Permalink
chore: Return NaN instead of throwing an exception on harder level ch…
Browse files Browse the repository at this point in the history
…ange
  • Loading branch information
Christopher-Chianelli committed Jan 15, 2025
1 parent 46ede2b commit 4cbb5aa
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ private void inheritGracePeriod(@NonNull AdaptiveTerminationConfig parent) {

@Override
public void visitReferencedClasses(@NonNull Consumer<Class<?>> classVisitor) {

// intentionally empty - no classes to visit
}

/** Check whether any gracePeriod... is non-null. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import org.jspecify.annotations.Nullable;

final class AdaptiveScoreRingBuffer<Score_ extends Score<Score_>> {
private final static int DEFAULT_CAPACITY = 4096;
private static final int DEFAULT_CAPACITY = 4096;

int readIndex;
int writeIndex;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,29 +37,18 @@ public double getMinimumImprovementRatio() {
}

/**
* An exception that is thrown to signal a hard score improvement.
* This is done since:
* <p/>
* <ul>
* <li/>Hard score improvements are significantly rarer than soft score improvements.
* <li/>Allows us to directly return a double in a method instead of using a
* carrier type/needing to box it so we can use null as a special value.
* <li/>Avoid branching in code on the hot path.
* </ul>
* <p/>
* This exception does not fill the stack trace to improve performance;
* it is a signal that should always be caught
* and handled appropriately.
* Returns the improvement in the softest level between the prior
* and current best scores as a double, or {@link Double#NaN} if
* there is a difference in any of their other levels.
*
* @param start the prior best score
* @param end the current best score
* @return the softest level difference between end and start, or
* {@link Double#NaN} if a harder level changed
* @param <Score_> The score type
*/
private static final class HardLevelImprovedSignal extends Exception {
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}

private static <Score_ extends Score<Score_>> double softImprovement(@NonNull Score_ start,
@NonNull Score_ end) throws HardLevelImprovedSignal {
private static <Score_ extends Score<Score_>> double softImprovementOrNaNForHarderChange(@NonNull Score_ start,
@NonNull Score_ end) {
if (start.equals(end)) {
// optimization: since most of the time the score the same,
// we can use equals to avoid creating double arrays in the
Expand All @@ -70,7 +59,7 @@ private static <Score_ extends Score<Score_>> double softImprovement(@NonNull Sc
var softestLevel = scoreDiffs.length - 1;
for (int i = 0; i < softestLevel; i++) {
if (scoreDiffs[i] != 0.0) {
throw new HardLevelImprovedSignal();
return Double.NaN;
}
}
return scoreDiffs[softestLevel];
Expand All @@ -96,28 +85,31 @@ private void resetGracePeriod(long currentTime, Score_ startingScore) {
}

public boolean isTerminated(long currentTime, Score_ endScore) {
try {
if (isGracePeriodActive) {
// first score in scoresByTime = first score in grace period window
var endpointDiff = softImprovement(scoresByTime.peekFirst(), endScore);
var timeElapsedNanos = currentTime - gracePeriodStartTimeNanos;
if (timeElapsedNanos >= gracePeriodNanos) {
// grace period over, record the reference diff
isGracePeriodActive = false;
gracePeriodSoftestImprovementDouble = endpointDiff;
return endpointDiff == 0.0;
}
if (isGracePeriodActive) {
// first score in scoresByTime = first score in grace period window
var endpointDiff = softImprovementOrNaNForHarderChange(scoresByTime.peekFirst(), endScore);
if (Double.isNaN(endpointDiff)) {
resetGracePeriod(currentTime, endScore);
return false;
}
var timeElapsedNanos = currentTime - gracePeriodStartTimeNanos;
if (timeElapsedNanos >= gracePeriodNanos) {
// grace period over, record the reference diff
isGracePeriodActive = false;
gracePeriodSoftestImprovementDouble = endpointDiff;
return endpointDiff == 0.0;
}
return false;
}

var startScore = scoresByTime.pollLatestScoreBeforeTimeAndClearPrior(currentTime - gracePeriodNanos);
var scoreDiff = softImprovement(startScore, endScore);

return scoreDiff / gracePeriodSoftestImprovementDouble < minimumImprovementRatio;
} catch (HardLevelImprovedSignal signal) {
var startScore = scoresByTime.pollLatestScoreBeforeTimeAndClearPrior(currentTime - gracePeriodNanos);
var scoreDiff = softImprovementOrNaNForHarderChange(startScore, endScore);
if (Double.isNaN(scoreDiff)) {
resetGracePeriod(currentTime, endScore);
return false;
}

return scoreDiff / gracePeriodSoftestImprovementDouble < minimumImprovementRatio;
}

@Override
Expand Down Expand Up @@ -149,12 +141,12 @@ public Termination<Solution_> createChildThreadTermination(SolverScope<Solution_

@Override
public void phaseStarted(AbstractPhaseScope<Solution_> phaseScope) {

// intentionally empty - no work to do
}

@Override
public void stepStarted(AbstractStepScope<Solution_> stepScope) {

// intentionally empty - no work to do
}

@Override
Expand All @@ -164,7 +156,7 @@ public void stepEnded(AbstractStepScope<Solution_> stepScope) {

@Override
public void phaseEnded(AbstractPhaseScope<Solution_> phaseScope) {

// intentionally empty - no work to do
}

@Override
Expand Down

0 comments on commit 4cbb5aa

Please sign in to comment.