Skip to content

Commit 0174966

Browse files
committed
[PEx] Add first version of RL-based choice selection
1 parent ad40c1c commit 0174966

File tree

17 files changed

+560
-13
lines changed

17 files changed

+560
-13
lines changed

Src/PRuntimes/PExplicitRuntime/src/main/java/pexplicit/PExplicit.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public static void main(String[] args) {
3232

3333
// parse the commandline arguments to create the configuration
3434
PExplicitGlobal.setConfig(PExplicitOptions.ParseCommandlineArgs(args));
35+
PExplicitGlobal.setChoiceSelector();
3536
PExplicitLogger.Initialize(PExplicitGlobal.getConfig().getVerbosity());
3637
ComputeHash.Initialize();
3738

Src/PRuntimes/PExplicitRuntime/src/main/java/pexplicit/commandline/PExplicitConfig.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import pexplicit.runtime.machine.buffer.BufferSemantics;
66
import pexplicit.runtime.scheduler.explicit.StateCachingMode;
77
import pexplicit.runtime.scheduler.explicit.StatefulBacktrackingMode;
8+
import pexplicit.runtime.scheduler.explicit.choiceselector.ChoiceSelectorMode;
89
import pexplicit.runtime.scheduler.explicit.strategy.SearchStrategyMode;
910

1011
/**
@@ -62,6 +63,9 @@ public class PExplicitConfig {
6263
// search strategy mode
6364
@Setter
6465
SearchStrategyMode searchStrategyMode = SearchStrategyMode.Random;
66+
// choice selector mode
67+
@Setter
68+
ChoiceSelectorMode choiceSelectorMode = ChoiceSelectorMode.Random;
6569
// max number of schedules per search task
6670
@Setter
6771
int maxSchedulesPerTask = 500;

Src/PRuntimes/PExplicitRuntime/src/main/java/pexplicit/commandline/PExplicitOptions.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.apache.commons.cli.*;
44
import pexplicit.runtime.scheduler.explicit.StateCachingMode;
55
import pexplicit.runtime.scheduler.explicit.StatefulBacktrackingMode;
6+
import pexplicit.runtime.scheduler.explicit.choiceselector.ChoiceSelectorMode;
67
import pexplicit.runtime.scheduler.explicit.strategy.SearchStrategyMode;
78

89
import java.io.PrintWriter;
@@ -214,6 +215,17 @@ public class PExplicitOptions {
214215
.build();
215216
addHiddenOption(maxChildrenPerTask);
216217

218+
// choice selection mode
219+
Option choiceSelect =
220+
Option.builder("cs")
221+
.longOpt("choice-selection")
222+
.desc("Choice selection mode: random, ql (default: random)")
223+
.numberOfArgs(1)
224+
.hasArg()
225+
.argName("Mode (string)")
226+
.build();
227+
addOption(choiceSelect);
228+
217229
/*
218230
* Help menu options
219231
*/
@@ -420,6 +432,21 @@ public static PExplicitConfig ParseCommandlineArgs(String[] args) {
420432
option, String.format("Expected an integer value, got %s", option.getValue()));
421433
}
422434
break;
435+
case "cs":
436+
case "choice-selection":
437+
switch (option.getValue()) {
438+
case "random":
439+
config.setChoiceSelectorMode(ChoiceSelectorMode.Random);
440+
break;
441+
case "ql":
442+
config.setChoiceSelectorMode(ChoiceSelectorMode.QL);
443+
break;
444+
default:
445+
optionError(
446+
option,
447+
String.format("Unrecognized choice selection mode, got %s", option.getValue()));
448+
}
449+
break;
423450
case "h":
424451
case "help":
425452
formatter.printHelp(

Src/PRuntimes/PExplicitRuntime/src/main/java/pexplicit/runtime/PExplicitGlobal.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import pexplicit.runtime.machine.PMachine;
77
import pexplicit.runtime.machine.PMachineId;
88
import pexplicit.runtime.scheduler.Scheduler;
9+
import pexplicit.runtime.scheduler.explicit.choiceselector.ChoiceSelector;
10+
import pexplicit.runtime.scheduler.explicit.choiceselector.ChoiceSelectorQL;
11+
import pexplicit.runtime.scheduler.explicit.choiceselector.ChoiceSelectorRandom;
912
import pexplicit.runtime.scheduler.explicit.strategy.SearchStrategyMode;
1013

1114
import java.util.*;
@@ -57,6 +60,11 @@ public class PExplicitGlobal {
5760
@Getter
5861
@Setter
5962
private static String result = "error";
63+
/**
64+
* Choice orchestrator
65+
*/
66+
@Getter
67+
private static ChoiceSelector choiceSelector = null;
6068

6169
/**
6270
* Get a machine of a given type and index if exists, else return null.
@@ -92,4 +100,20 @@ public static void addGlobalMachine(PMachine machine, int machineCount) {
92100
machineSet.add(machine);
93101
assert (machineListByType.get(machine.getClass()).get(machineCount) == machine);
94102
}
103+
104+
/**
105+
* Set choice orchestrator
106+
*/
107+
public static void setChoiceSelector() {
108+
switch (config.getChoiceSelectorMode()) {
109+
case Random:
110+
choiceSelector = new ChoiceSelectorRandom();
111+
break;
112+
case QL:
113+
choiceSelector = new ChoiceSelectorQL();
114+
break;
115+
default:
116+
throw new RuntimeException("Unrecognized choice orchestrator: " + config.getChoiceSelectorMode());
117+
}
118+
}
95119
}

Src/PRuntimes/PExplicitRuntime/src/main/java/pexplicit/runtime/STATUS.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public enum STATUS {
1111
INTERRUPTED("interrupted"), // interrupted by user
1212
ERROR("error"); // unexpected error encountered
1313

14-
private String name;
14+
private final String name;
1515

1616
/**
1717
* Constructor

Src/PRuntimes/PExplicitRuntime/src/main/java/pexplicit/runtime/logger/PExplicitLogger.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ public static void logEndOfRun(ExplicitSearchScheduler scheduler, long timeSpent
9494
if (scheduler != null) {
9595
log.info("... Scheduling statistics:");
9696
if (PExplicitGlobal.getConfig().getStateCachingMode() != StateCachingMode.None) {
97-
log.info(String.format("..... Explored %d distinct states", SearchStatistics.totalDistinctStates));
97+
log.info(String.format("..... Explored %d distinct states over %d timelines",
98+
SearchStatistics.totalDistinctStates, scheduler.getTimelines().size()));
9899
}
99100
log.info(String.format("..... Explored %d distinct schedules", SearchStatistics.iteration));
100101
log.info(String.format("..... Finished %d search tasks (%d pending)",

Src/PRuntimes/PExplicitRuntime/src/main/java/pexplicit/runtime/machine/PMachine.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package pexplicit.runtime.machine;
22

33
import lombok.Getter;
4+
import org.apache.commons.lang3.tuple.ImmutablePair;
45
import pexplicit.runtime.PExplicitGlobal;
56
import pexplicit.runtime.logger.PExplicitLogger;
67
import pexplicit.runtime.machine.buffer.DeferQueue;
@@ -51,6 +52,9 @@ public abstract class PMachine implements Serializable, Comparable<PMachine> {
5152
private boolean started = false;
5253
@Getter
5354
private boolean halted = false;
55+
private Set<PEvent> observedEvents;
56+
@Getter
57+
private Set<ImmutablePair<PEvent, PEvent>> happensBeforePairs;
5458
private PContinuation blockedBy = null;
5559
@Getter
5660
private State blockedStateExit;
@@ -95,6 +99,9 @@ public void handleEvent(PMachine target, PValue<?> payload) {
9599
// initialize send buffer
96100
this.sendBuffer = new SenderQueue(this);
97101
this.deferQueue = new DeferQueue(this);
102+
// initialize happens-before
103+
this.observedEvents = new HashSet<>();
104+
this.happensBeforePairs = new HashSet<>();
98105
}
99106

100107
public void start(PValue<?> payload) {
@@ -128,6 +135,9 @@ public void reset() {
128135
this.started = false;
129136
this.halted = false;
130137

138+
this.observedEvents.clear();
139+
this.happensBeforePairs.clear();
140+
131141
this.blockedBy = null;
132142
this.blockedStateExit = null;
133143
this.blockedNewStateEntry = null;
@@ -168,6 +178,9 @@ public List<String> getLocalVarNames() {
168178
result.add("_started");
169179
result.add("_halted");
170180

181+
result.add("_observedEvents");
182+
result.add("_happensBefore");
183+
171184
result.add("_blockedBy");
172185
result.add("_blockedStateExit");
173186
result.add("_blockedNewStateEntry");
@@ -205,6 +218,9 @@ public List<Object> getLocalVarValues() {
205218
result.add(started);
206219
result.add(halted);
207220

221+
result.add(observedEvents);
222+
result.add(happensBeforePairs);
223+
208224
result.add(blockedBy);
209225
result.add(blockedStateExit);
210226
result.add(blockedNewStateEntry);
@@ -246,6 +262,9 @@ public List<Object> copyLocalVarValues() {
246262
result.add(started);
247263
result.add(halted);
248264

265+
result.add(new HashSet<>(observedEvents));
266+
result.add(new HashSet<>(happensBeforePairs));
267+
249268
result.add(blockedBy);
250269
result.add(blockedStateExit);
251270
result.add(blockedNewStateEntry);
@@ -288,6 +307,9 @@ protected int setLocalVarValues(List<Object> values) {
288307
started = (boolean) values.get(idx++);
289308
halted = (boolean) values.get(idx++);
290309

310+
observedEvents = (Set<PEvent>) values.get(idx++);
311+
happensBeforePairs = (Set<ImmutablePair<PEvent, PEvent>>) values.get(idx++);
312+
291313
blockedBy = (PContinuation) values.get(idx++);
292314
blockedStateExit = (State) values.get(idx++);
293315
blockedNewStateEntry = (State) values.get(idx++);
@@ -502,9 +524,9 @@ void processEvent(PMessage message) {
502524
* @param message Message to process
503525
*/
504526
void runEvent(PMessage message) {
527+
PEvent event = message.getEvent();
505528
if (isBlocked()) {
506529
PContinuation currBlockedBy = this.blockedBy;
507-
PEvent event = message.getEvent();
508530
clearBlocked();
509531

510532
// make sure event is handled (or is halt event)
@@ -521,6 +543,7 @@ void runEvent(PMessage message) {
521543
event, this, this.currentState));
522544
}
523545
} else {
546+
addObservedEvent(event);
524547
currentState.handleEvent(message, this);
525548
}
526549
}
@@ -624,6 +647,13 @@ public void enterNewState(State newState, PValue<?> payload) {
624647
newState.entry(this, payload);
625648
}
626649

650+
private void addObservedEvent(PEvent newEvent) {
651+
for (PEvent happenedBeforeEvent : observedEvents) {
652+
happensBeforePairs.add(new ImmutablePair<>(happenedBeforeEvent, newEvent));
653+
}
654+
observedEvents.add(newEvent);
655+
}
656+
627657
@Override
628658
public int compareTo(PMachine rhs) {
629659
if (rhs == null) {

Src/PRuntimes/PExplicitRuntime/src/main/java/pexplicit/runtime/scheduler/Scheduler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ public void checkLiveness(boolean terminated) {
360360
if (terminated) {
361361
for (PMachine monitor : PExplicitGlobal.getModel().getMonitors()) {
362362
if (monitor.getCurrentState().isHotState()) {
363-
Assert.liveness(String.format("Monitor %s detected liveness bug in hot state %s at the end of program execution", monitor, monitor.getCurrentState()));
363+
Assert.liveness(String.format("Monitor %s detected liveness bug in hot state %s at the end of program execution", monitor, monitor.getCurrentState()));
364364
}
365365
}
366366
}

Src/PRuntimes/PExplicitRuntime/src/main/java/pexplicit/runtime/scheduler/explicit/ExplicitSearchScheduler.java

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import pexplicit.runtime.scheduler.Scheduler;
1515
import pexplicit.runtime.scheduler.choice.ScheduleChoice;
1616
import pexplicit.runtime.scheduler.choice.SearchUnit;
17+
import pexplicit.runtime.scheduler.explicit.choiceselector.ChoiceSelectorMode;
18+
import pexplicit.runtime.scheduler.explicit.choiceselector.ChoiceSelectorQL;
1719
import pexplicit.runtime.scheduler.explicit.strategy.*;
1820
import pexplicit.utils.exceptions.PExplicitRuntimeException;
1921
import pexplicit.utils.misc.Assert;
@@ -35,6 +37,11 @@ public class ExplicitSearchScheduler extends Scheduler {
3537
* Map from state hash to iteration when first visited
3638
*/
3739
private final transient Map<Object, Integer> stateCache = new HashMap<>();
40+
/**
41+
* Set of timelines
42+
*/
43+
@Getter
44+
private final transient Set<Integer> timelines = new HashSet<>();
3845
/**
3946
* Search strategy orchestrator
4047
*/
@@ -191,6 +198,16 @@ protected void runStep() throws TimeoutException {
191198
return;
192199
}
193200

201+
// update timeline
202+
Integer timelineHash = stepState.getTimelineHash();
203+
if (!timelines.contains(timelineHash)) {
204+
// stepState.printTimeline(timelineHash, timelines.size());
205+
timelines.add(timelineHash);
206+
}
207+
if (PExplicitGlobal.getConfig().getChoiceSelectorMode() == ChoiceSelectorMode.QL) {
208+
PExplicitGlobal.getChoiceSelector().startStep(this);
209+
}
210+
194211
if (PExplicitGlobal.getConfig().getStatefulBacktrackingMode() != StatefulBacktrackingMode.None
195212
&& stepNumber != 0) {
196213
schedule.setStepBeginState(stepState.copyState());
@@ -330,12 +347,13 @@ public PMachine getNextScheduleChoice() {
330347
}
331348
}
332349

333-
// pick the first choice
334-
result = PExplicitGlobal.getGlobalMachine(choices.get(0));
350+
// pick a choice
351+
int selected = PExplicitGlobal.getChoiceSelector().selectChoice(choices);
352+
result = PExplicitGlobal.getGlobalMachine(choices.get(selected));
335353
PExplicitLogger.logCurrentScheduleChoice(result, stepNumber, choiceNumber);
336354

337-
// remove the first choice from unexplored choices
338-
choices.remove(0);
355+
// remove the selected choice from unexplored choices
356+
choices.remove(selected);
339357

340358
// add choice to schedule
341359
schedule.setScheduleChoice(stepNumber, choiceNumber, result.getPid());
@@ -393,12 +411,13 @@ public PValue<?> getNextDataChoice(List<PValue<?>> input_choices) {
393411
}
394412
}
395413

396-
// pick the first choice
397-
result = choices.get(0);
414+
// pick a choice
415+
int selected = PExplicitGlobal.getChoiceSelector().selectChoice(choices);
416+
result = choices.get(selected);
398417
PExplicitLogger.logCurrentDataChoice(result, stepNumber, choiceNumber);
399418

400-
// remove the first choice from unexplored choices
401-
choices.remove(0);
419+
// remove the selected choice from unexplored choices
420+
choices.remove(selected);
402421

403422
// add choice to schedule
404423
schedule.setDataChoice(stepNumber, choiceNumber, result);
@@ -600,6 +619,7 @@ public void recordStats() {
600619

601620
// print basic statistics
602621
StatWriter.log("#-schedules", String.format("%d", SearchStatistics.iteration));
622+
StatWriter.log("#-timelines", String.format("%d", timelines.size()));
603623
if (PExplicitGlobal.getConfig().getStateCachingMode() != StateCachingMode.None) {
604624
StatWriter.log("#-states", String.format("%d", SearchStatistics.totalStates));
605625
StatWriter.log("#-distinct-states", String.format("%d", SearchStatistics.totalDistinctStates));
@@ -610,6 +630,8 @@ public void recordStats() {
610630
StatWriter.log("%-choices-unexplored-data", String.format("%.1f", getUnexploredDataChoicesPercent()));
611631
StatWriter.log("#-tasks-finished", String.format("%d", searchStrategy.getFinishedTasks().size()));
612632
StatWriter.log("#-tasks-pending", String.format("%d", searchStrategy.getPendingTasks().size()));
633+
StatWriter.log("ql-#-states", String.format("%d", ChoiceSelectorQL.getChoiceQL().getNumStates()));
634+
StatWriter.log("ql-#-actions", String.format("%d", ChoiceSelectorQL.getChoiceQL().getNumActions()));
613635
}
614636

615637
private void printCurrentStatus(double newRuntime) {
@@ -621,6 +643,7 @@ private void printCurrentStatus(double newRuntime) {
621643
s.append(String.format("\n Unexplored: %d", getNumUnexploredChoices()));
622644
s.append(String.format("\n FinishedTasks: %d", searchStrategy.getFinishedTasks().size()));
623645
s.append(String.format("\n PendingTasks: %d", searchStrategy.getPendingTasks().size()));
646+
s.append(String.format("\n Timelines: %d", timelines.size()));
624647
if (PExplicitGlobal.getConfig().getStateCachingMode() != StateCachingMode.None) {
625648
s.append(String.format("\n States: %d", SearchStatistics.totalStates));
626649
s.append(String.format("\n DistinctStates: %d", SearchStatistics.totalDistinctStates));
@@ -635,6 +658,7 @@ private void printProgressHeader(boolean consolePrint) {
635658
s.append(StringUtils.center("Step", 7));
636659

637660
s.append(StringUtils.center("Schedule", 12));
661+
s.append(StringUtils.center("Timelines", 12));
638662
s.append(StringUtils.center("Unexplored", 24));
639663

640664
if (PExplicitGlobal.getConfig().getStateCachingMode() != StateCachingMode.None) {
@@ -677,6 +701,7 @@ protected void printProgress(boolean forcePrint) {
677701
s.append(StringUtils.center(String.format("%d", stepNumber), 7));
678702

679703
s.append(StringUtils.center(String.format("%d", SearchStatistics.iteration), 12));
704+
s.append(StringUtils.center(String.format("%d", timelines.size()), 12));
680705
s.append(
681706
StringUtils.center(
682707
String.format(

0 commit comments

Comments
 (0)