From c7dd1588d045322e543cac5e326bb32d94cf24ba Mon Sep 17 00:00:00 2001
From: Ao Li <5557706+aoli-al@users.noreply.github.com>
Date: Mon, 8 Apr 2024 17:56:58 -0400
Subject: [PATCH 01/21] Add feedback strategy. (#715)
* Add feedback guided scheduling algorithms.
* Fix tests.
* Add location information to events.
* fix change.
---
.../CheckerCore/Actors/Events/Event.cs | 1 +
.../CheckerCore/Actors/Logging/JsonWriter.cs | 30 +-
.../CheckerCore/CheckerConfiguration.cs | 51 ++-
Src/PChecker/CheckerCore/Pattern/EventObj.cs | 22 ++
.../Pattern/EventPatternObserver.cs | 188 +++++++++
Src/PChecker/CheckerCore/Pattern/IMatcher.cs | 10 +
.../Random/IRandomValueGenerator.cs | 2 +
.../SystematicTesting/ControlledRuntime.cs | 23 +-
.../SystematicTesting/OperationScheduler.cs | 4 +-
.../Operations/AsyncOperation.cs | 3 +
.../Feedback/Coverage/AbstractSchedule.cs | 70 ++++
.../Coverage/AbstractScheduleObserver.cs | 348 +++++++++++++++++
.../Coverage/ActivityCoverageReporter.cs | 0
.../Coverage/ActorRuntimeLogEventCoverage.cs | 0
.../Coverage/ActorRuntimeLogGraphBuilder.cs | 0
.../Feedback/Coverage/ConflictOpMonitor.cs | 114 ++++++
.../Feedback}/Coverage/CoverageInfo.cs | 2 +
.../Feedback/Coverage/ISendEventMonitor.cs | 15 +
.../Feedback/Coverage/TimelineObserver.cs | 217 +++++++++++
.../Feedback/FeedbackGuidedStrategy.cs | 305 +++++++++++++++
.../Feedback/Generator/IGenerator.cs | 18 +
.../Feedback/Generator/IInputGenerator.cs | 22 ++
.../Feedback/Generator/IScheduleGenerator.cs | 18 +
.../Feedback/Generator/Mutator/IMutator.cs | 6 +
.../Generator/Mutator/PCTScheduleMutator.cs | 17 +
.../Generator/Mutator/POSScheduleMutator.cs | 16 +
.../Generator/Mutator/PctcpScheduleMutator.cs | 19 +
.../Generator/Mutator/RandomInputMutator.cs | 17 +
.../Mutator/RandomScheduleMutator.cs | 17 +
.../Feedback/Generator/Mutator/Utils.cs | 38 ++
.../Generator/Object/RandomChoices.cs | 50 +++
.../Generator/PCTScheduleGenerator.cs | 62 +++
.../Generator/POSScheduleGenerator.cs | 67 ++++
.../Feedback/Generator/ParametricProvider.cs | 27 ++
.../Generator/PctcpScheduleGenerator.cs | 68 ++++
.../Generator/RandomInputGenerator.cs | 101 +++++
.../Generator/RandomScheduleGenerator.cs | 59 +++
.../Feedback/IFeedbackGuidedStrategy.cs | 12 +
.../Strategies/Feedback/MaxHeap.cs | 88 +++++
.../Feedback/TwoStageFeedbackStrategy.cs | 36 ++
.../Strategies/Probabilistic/PCTCP/Chain.cs | 33 ++
.../Probabilistic/PCTCP/OperationWithId.cs | 3 +
.../Probabilistic/PCTCP/VectorClockWrapper.cs | 8 +
.../Probabilistic/PCTCPScheduler.cs | 366 ++++++++++++++++++
.../Strategies/Probabilistic/PCTScheduler.cs | 189 +++++++++
.../Strategies/Probabilistic/POSScheduler.cs | 156 ++++++++
.../Strategies/Probabilistic/POSStrategy.cs | 48 +++
.../Probabilistic/PrioritizedScheduler.cs | 11 +
.../PrioritizedSchedulingStrategy.cs | 114 ++++++
.../Probabilistic/PriorizationProvider.cs | 7 +
.../PriorizationSchedulingBase.cs | 243 ++++++++++++
.../Probabilistic/QLearningStrategy.cs | 90 ++++-
.../Strategies/Probabilistic/RFFScheduler.cs | 174 +++++++++
.../RandomPriorizationProvider.cs | 27 ++
.../Probabilistic/RandomStrategy.cs | 6 +-
.../SystematicTesting/Strategies/Utils.cs | 44 +++
.../SystematicTesting/TestReport.cs | 13 +
.../SystematicTesting/TestingEngine.cs | 213 +++++++++-
.../Backend/CSharp/CSharpCodeGenerator.cs | 106 ++++-
.../CompilerCore/Backend/IRTransformer.cs | 3 +
Src/PCompiler/CompilerCore/Parser/PLexer.g4 | 1 +
Src/PCompiler/CompilerCore/Parser/PParser.g4 | 8 +
.../TypeChecker/AST/Declarations/Function.cs | 6 +-
.../AST/Declarations/FunctionSignature.cs | 2 +
.../AST/Statements/ConstraintStmt.cs | 15 +
.../CompilerCore/TypeChecker/Analyzer.cs | 7 +
.../ConstraintVariableCollector.cs | 33 ++
.../TypeChecker/ControlFlowChecker.cs | 1 +
.../TypeChecker/DeclarationStubVisitor.cs | 20 +
.../TypeChecker/DeclarationVisitor.cs | 24 ++
.../CompilerCore/TypeChecker/ExprVisitor.cs | 24 +-
.../TypeChecker/FunctionBodyVisitor.cs | 27 ++
.../TypeChecker/FunctionValidator.cs | 2 +-
.../TypeChecker/ScenarioEventVisitor.cs | 20 +
.../CompilerCore/TypeChecker/Scope.cs | 8 +
.../CompilerCore/TypeChecker/TypeResolver.cs | 2 +-
.../TypeChecker/Types/NamedTupleEntry.cs | 11 +
.../PCommandLine/Options/PCheckerOptions.cs | 64 ++-
Src/PRuntimes/PCSharpRuntime/PEvent.cs | 8 +-
Src/PRuntimes/PCSharpRuntime/PMachine.cs | 8 +-
Tutorial/2_TwoPhaseCommit/timeline.txt | 0
81 files changed, 4223 insertions(+), 85 deletions(-)
create mode 100644 Src/PChecker/CheckerCore/Pattern/EventObj.cs
create mode 100644 Src/PChecker/CheckerCore/Pattern/EventPatternObserver.cs
create mode 100644 Src/PChecker/CheckerCore/Pattern/IMatcher.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractSchedule.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractScheduleObserver.cs
rename Src/PChecker/CheckerCore/{ => SystematicTesting/Strategies/Feedback}/Coverage/ActivityCoverageReporter.cs (100%)
rename Src/PChecker/CheckerCore/{ => SystematicTesting/Strategies/Feedback}/Coverage/ActorRuntimeLogEventCoverage.cs (100%)
rename Src/PChecker/CheckerCore/{ => SystematicTesting/Strategies/Feedback}/Coverage/ActorRuntimeLogGraphBuilder.cs (100%)
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ConflictOpMonitor.cs
rename Src/PChecker/CheckerCore/{ => SystematicTesting/Strategies/Feedback}/Coverage/CoverageInfo.cs (98%)
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ISendEventMonitor.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/TimelineObserver.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IGenerator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IInputGenerator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IScheduleGenerator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/IMutator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PCTScheduleMutator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/POSScheduleMutator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PctcpScheduleMutator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomInputMutator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomScheduleMutator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/Utils.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/RandomChoices.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PCTScheduleGenerator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/POSScheduleGenerator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/ParametricProvider.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PctcpScheduleGenerator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomInputGenerator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomScheduleGenerator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IFeedbackGuidedStrategy.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/MaxHeap.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/TwoStageFeedbackStrategy.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/Chain.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/OperationWithId.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/VectorClockWrapper.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCPScheduler.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTScheduler.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSStrategy.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedScheduler.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedSchedulingStrategy.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationProvider.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationSchedulingBase.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RFFScheduler.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomPriorizationProvider.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Utils.cs
create mode 100644 Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/ConstraintStmt.cs
create mode 100644 Src/PCompiler/CompilerCore/TypeChecker/ConstraintVariableCollector.cs
create mode 100644 Src/PCompiler/CompilerCore/TypeChecker/ScenarioEventVisitor.cs
create mode 100644 Tutorial/2_TwoPhaseCommit/timeline.txt
diff --git a/Src/PChecker/CheckerCore/Actors/Events/Event.cs b/Src/PChecker/CheckerCore/Actors/Events/Event.cs
index a33f298172..132cc5c69b 100644
--- a/Src/PChecker/CheckerCore/Actors/Events/Event.cs
+++ b/Src/PChecker/CheckerCore/Actors/Events/Event.cs
@@ -11,5 +11,6 @@ namespace PChecker.Actors.Events
[DataContract]
public abstract class Event
{
+ public int Loc { get; set; }
}
}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/Actors/Logging/JsonWriter.cs b/Src/PChecker/CheckerCore/Actors/Logging/JsonWriter.cs
index 2802f9e715..acc6adc74f 100644
--- a/Src/PChecker/CheckerCore/Actors/Logging/JsonWriter.cs
+++ b/Src/PChecker/CheckerCore/Actors/Logging/JsonWriter.cs
@@ -11,7 +11,7 @@ namespace PChecker.Actors.Logging
///
/// Class for handling generating the vector clock for a log entry
///
- internal class VectorClockGenerator
+ public class VectorClockGenerator
{
///
/// Nested class for handling FIFO send receive requests.
@@ -61,7 +61,7 @@ internal FifoSendReceiveMapping()
///
/// Field declaration that keeps track of a global vector clock map of all the machines.
///
- private readonly Dictionary> _contextVcMap;
+ public readonly Dictionary> ContextVcMap;
///
/// Field declaration that keeps track of unprocessed send requests. I.e., when a send request happened
@@ -85,7 +85,7 @@ internal FifoSendReceiveMapping()
///
public VectorClockGenerator()
{
- _contextVcMap = new Dictionary>();
+ ContextVcMap = new Dictionary>();
_unhandledSendRequests = new Dictionary>();
_machines = new HashSet();
_sendRequestsCount = new Dictionary();
@@ -205,7 +205,7 @@ private void updateMachineVcMap(string machine, Dictionary senderVc
{
// Get a set of all machine names to update between the sender vc map and the current machine vc map (minus the current machine)
var machinesToUpdateInVc =
- new HashSet(_contextVcMap[machine].Keys.Union(senderVcMap.Keys).Except(new[] { machine }));
+ new HashSet(ContextVcMap[machine].Keys.Union(senderVcMap.Keys).Except(new[] { machine }));
// Update local machine's vector clock in _contextVcMap, outside of itself, since it was already updated (incremented) from above
// right before the switch case.
@@ -213,17 +213,17 @@ private void updateMachineVcMap(string machine, Dictionary senderVc
// the current machine's vector clock. Details can be found here: https://en.wikipedia.org/wiki/Vector_clock
foreach (var machineToUpdate in machinesToUpdateInVc)
{
- if (_contextVcMap[machine].TryGetValue(machineToUpdate, out var localMachineToUpdateValue))
+ if (ContextVcMap[machine].TryGetValue(machineToUpdate, out var localMachineToUpdateValue))
{
if (senderVcMap.TryGetValue(machineToUpdate, out var senderMachineToUpdateValue))
{
- _contextVcMap[machine][machineToUpdate] =
+ ContextVcMap[machine][machineToUpdate] =
Math.Max(senderMachineToUpdateValue, localMachineToUpdateValue);
}
}
else
{
- _contextVcMap[machine].Add(machineToUpdate, senderVcMap[machineToUpdate]);
+ ContextVcMap[machine].Add(machineToUpdate, senderVcMap[machineToUpdate]);
}
}
}
@@ -243,11 +243,11 @@ public void HandleLogEntry(LogEntry logEntry)
if (MachineIsNew(machine))
{
_machines.Add(machine);
- _contextVcMap.Add(machine, new Dictionary { { machine, 0 } });
+ ContextVcMap.Add(machine, new Dictionary { { machine, 0 } });
}
// Always update the local machine count by one on any event.
- _contextVcMap[machine][machine] += 1;
+ ContextVcMap[machine][machine] += 1;
switch (logType)
{
@@ -273,13 +273,13 @@ public void HandleLogEntry(LogEntry logEntry)
// Update the sendReqId with the send count of it.
sendReqId += $":_{_sendRequestsCount[hashedGeneralSendReqId].SentCount}";
var hashedSendReqId = HashString(sendReqId);
- _unhandledSendRequests.Add(hashedSendReqId, CopyVcMap(_contextVcMap[machine]));
+ _unhandledSendRequests.Add(hashedSendReqId, CopyVcMap(ContextVcMap[machine]));
break;
// For MonitorProcessEvents, tie it to the senderMachine's current vector clock
// so that there is some association in the timeline
case "MonitorProcessEvent":
- if (logDetails.Sender != null) updateMachineVcMap(machine, _contextVcMap[logDetails.Sender]);
+ if (logDetails.Sender != null) updateMachineVcMap(machine, ContextVcMap[logDetails.Sender]);
break;
// On dequeue OR receive event, has the string containing information about the current machine that dequeued (i.e. received the event),
@@ -317,7 +317,7 @@ public void HandleLogEntry(LogEntry logEntry)
}
// Update the log entry with the vector clock.
- logEntry.Details.Clock = CopyVcMap(_contextVcMap[machine]);
+ logEntry.Details.Clock = CopyVcMap(ContextVcMap[machine]);
}
}
@@ -533,7 +533,7 @@ public class JsonWriter
///
/// Vector clock generator instance to help with vector clock generation.
///
- private readonly VectorClockGenerator _vcGenerator;
+ internal VectorClockGenerator VcGenerator {get;}
///
/// Getter for accessing log entry details.
@@ -552,7 +552,7 @@ public JsonWriter()
{
_logs = new List();
_log = new LogEntry();
- _vcGenerator = new VectorClockGenerator();
+ VcGenerator = new VectorClockGenerator();
}
///
@@ -716,7 +716,7 @@ public void AddToLogs(bool updateVcMap = false)
{
if (updateVcMap)
{
- _vcGenerator.HandleLogEntry(_log);
+ VcGenerator.HandleLogEntry(_log);
}
_logs.Add(_log);
diff --git a/Src/PChecker/CheckerCore/CheckerConfiguration.cs b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
index 43e557cf92..e27f18bb4c 100644
--- a/Src/PChecker/CheckerCore/CheckerConfiguration.cs
+++ b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
@@ -257,6 +257,12 @@ public int MaxSchedulingSteps
[DataMember]
public uint TestingProcessId;
+ ///
+ /// The source of the pattern generator.
+ ///
+ [DataMember]
+ public string PatternSource;
+
///
/// Additional assembly specifications to instrument for code coverage, besides those in the
/// dependency graph between and the Microsoft.Coyote DLLs.
@@ -286,6 +292,42 @@ public int MaxSchedulingSteps
[DataMember]
public string JvmArgs;
+ ///
+ /// For feedback strategy, save input if the pattern are partially matched.
+ ///
+ [DataMember]
+ public bool SavePartialMatch;
+
+ ///
+ /// For feedback strategy, discard saved generators if the size of the buffer is greater than N.
+ ///
+ [DataMember]
+ public int DiscardAfter;
+
+ ///
+ /// For feedback strategy, schedule generator mutations based on diversity.
+ ///
+ [DataMember]
+ public bool DiversityBasedPriority;
+
+ ///
+ /// For feedback strategy, ignore the pattern feedback.
+ ///
+ [DataMember]
+ public bool IgnorePatternFeedback;
+
+ ///
+ /// For feedback strategy, use priority based sampling.
+ ///
+ [DataMember]
+ public bool PriorityBasedSampling;
+
+ ///
+ /// Enable conflict analysis for scheduling optimization.
+ ///
+ [DataMember]
+ public bool EnableConflictAnalysis;
+
///
/// Initializes a new instance of the class.
///
@@ -307,7 +349,7 @@ protected CheckerConfiguration()
RandomGeneratorSeed = null;
IncrementalSchedulingSeed = false;
PerformFullExploration = false;
- MaxFairSchedulingSteps = 100000; // 10 times the unfair steps
+ MaxFairSchedulingSteps = 10000; // 10 times the unfair steps
MaxUnfairSchedulingSteps = 10000;
UserExplicitlySetMaxFairSchedulingSteps = false;
TestingProcessId = 0;
@@ -331,9 +373,16 @@ protected CheckerConfiguration()
EnableColoredConsoleOutput = false;
DisableEnvironmentExit = true;
+ SavePartialMatch = true;
+ DiscardAfter = 100;
+ DiversityBasedPriority = true;
+ IgnorePatternFeedback = false;
+ PriorityBasedSampling = true;
+ EnableConflictAnalysis = false;
PSymArgs = "";
JvmArgs = "";
+ PatternSource = "";
}
///
diff --git a/Src/PChecker/CheckerCore/Pattern/EventObj.cs b/Src/PChecker/CheckerCore/Pattern/EventObj.cs
new file mode 100644
index 0000000000..2accf8d86b
--- /dev/null
+++ b/Src/PChecker/CheckerCore/Pattern/EventObj.cs
@@ -0,0 +1,22 @@
+using PChecker.Actors.Events;
+using PChecker.Specifications.Monitors;
+
+namespace PChecker.Matcher;
+
+public class EventObj
+{
+ public Event Event;
+ public string? Sender;
+ public string? Receiver;
+ public string State;
+ public int Index;
+
+ public EventObj(Event e, string? sender, string? receiver, string state, int index)
+ {
+ Event = e;
+ Sender = sender;
+ Receiver = receiver;
+ State = state;
+ Index = index;
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/Pattern/EventPatternObserver.cs b/Src/PChecker/CheckerCore/Pattern/EventPatternObserver.cs
new file mode 100644
index 0000000000..c0dfdaa26f
--- /dev/null
+++ b/Src/PChecker/CheckerCore/Pattern/EventPatternObserver.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using PChecker.Actors;
+using PChecker.Actors.Events;
+using PChecker.Actors.Logging;
+using PChecker.Matcher;
+
+namespace PChecker.Feedback;
+
+internal class EventPatternObserver : IActorRuntimeLog
+{
+ private MethodInfo _matcher;
+ private Dictionary _senderMap = new();
+ private List _events = new();
+ public EventPatternObserver(MethodInfo matcher)
+ {
+ _matcher = matcher;
+ }
+
+ public void OnCreateActor(ActorId id, string creatorName, string creatorType)
+ {
+
+ }
+
+ public void OnCreateStateMachine(ActorId id, string creatorName, string creatorType)
+ {
+ }
+
+ public void OnExecuteAction(ActorId id, string handlingStateName, string currentStateName, string actionName)
+ {
+
+ }
+
+ public void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName, Event e,
+ Guid opGroupId, bool isTargetHalted)
+ {
+ _senderMap[e] = senderName;
+ }
+
+ public void OnRaiseEvent(ActorId id, string stateName, Event e)
+ {
+
+ }
+
+ public void OnEnqueueEvent(ActorId id, Event e)
+ {
+
+ }
+
+ public void OnDequeueEvent(ActorId id, string stateName, Event e)
+ {
+ _events.Add(new EventObj(e, _senderMap.GetValueOrDefault(e), id.Name, stateName, _events.Count));
+ }
+
+
+ public void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked)
+ {
+
+ }
+
+ public void OnWaitEvent(ActorId id, string stateName, Type eventType)
+ {
+
+ }
+
+ public void OnWaitEvent(ActorId id, string stateName, params Type[] eventTypes)
+ {
+
+ }
+
+ public void OnStateTransition(ActorId id, string stateName, bool isEntry)
+ {
+
+ }
+
+ public void OnGotoState(ActorId id, string currentStateName, string newStateName)
+ {
+ }
+
+ public void OnPushState(ActorId id, string currentStateName, string newStateName)
+ {
+
+ }
+
+ public void OnPopState(ActorId id, string currentStateName, string restoredStateName)
+ {
+
+ }
+
+ public void OnDefaultEventHandler(ActorId id, string stateName)
+ {
+
+ }
+
+ public void OnHalt(ActorId id, int inboxSize)
+ {
+
+ }
+
+ public void OnHandleRaisedEvent(ActorId id, string stateName, Event e)
+ {
+
+ }
+
+ public void OnPopStateUnhandledEvent(ActorId id, string stateName, Event e)
+ {
+
+ }
+
+ public void OnExceptionThrown(ActorId id, string stateName, string actionName, Exception ex)
+ {
+
+ }
+
+ public void OnExceptionHandled(ActorId id, string stateName, string actionName, Exception ex)
+ {
+
+ }
+
+ public void OnCreateMonitor(string monitorType)
+ {
+
+ }
+
+ public void OnMonitorExecuteAction(string monitorType, string stateName, string actionName)
+ {
+
+ }
+
+ public void OnMonitorProcessEvent(string monitorType, string stateName, string senderName, string senderType,
+ string senderStateName, Event e)
+ {
+ _events.Add(new EventObj(e, senderName, null, stateName, _events.Count));
+ }
+
+ public void OnMonitorRaiseEvent(string monitorType, string stateName, Event e)
+ {
+
+ }
+
+ public void OnMonitorStateTransition(string monitorType, string stateName, bool isEntry, bool? isInHotState)
+ {
+
+ }
+
+ public void OnMonitorError(string monitorType, string stateName, bool? isInHotState)
+ {
+
+ }
+
+ public void OnRandom(object result, string callerName, string callerType)
+ {
+
+ }
+
+ public void OnAssertionFailure(string error)
+ {
+
+ }
+
+ public void OnStrategyDescription(string strategyName, string description)
+ {
+
+ }
+
+ public void OnCompleted()
+ {
+ }
+
+ public virtual int ShouldSave()
+ {
+ return (int) _matcher.Invoke(null, new [] { _events });
+ }
+
+ public virtual bool IsMatched()
+ {
+ int result = (int) _matcher.Invoke(null, new [] { _events });
+ return result == 1;
+ }
+
+
+ public void Reset()
+ {
+ _events.Clear();
+ _senderMap.Clear();
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/Pattern/IMatcher.cs b/Src/PChecker/CheckerCore/Pattern/IMatcher.cs
new file mode 100644
index 0000000000..2faa030882
--- /dev/null
+++ b/Src/PChecker/CheckerCore/Pattern/IMatcher.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using PChecker.Matcher;
+
+namespace PChecker.Feedback;
+
+public interface IMatcher
+{
+
+ public int IsMatched(List events);
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/Random/IRandomValueGenerator.cs b/Src/PChecker/CheckerCore/Random/IRandomValueGenerator.cs
index 8e3084ced9..71d58cbac3 100644
--- a/Src/PChecker/CheckerCore/Random/IRandomValueGenerator.cs
+++ b/Src/PChecker/CheckerCore/Random/IRandomValueGenerator.cs
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using System;
+
namespace PChecker.Random
{
///
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs b/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
index c5983e709a..ac91696d2f 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
@@ -18,6 +18,7 @@
using PChecker.Actors.Managers.Mocks;
using PChecker.Coverage;
using PChecker.Exceptions;
+using PChecker.Feedback;
using PChecker.Random;
using PChecker.Runtime;
using PChecker.Specifications.Monitors;
@@ -65,6 +66,13 @@ internal sealed class ControlledRuntime : ActorRuntime
///
internal readonly int? RootTaskId;
+ ///
+ /// The observer that extracts the timeline information of the scheduling.
+ ///
+ internal readonly TimelineObserver TimelineObserver = new();
+
+ public List SendEventMonitors = new();
+
///
/// Returns the current hashed state of the monitors.
@@ -148,6 +156,7 @@ internal ControlledRuntime(CheckerConfiguration checkerConfiguration, ISchedulin
// Update the current asynchronous control flow with this runtime instance,
// allowing future retrieval in the same asynchronous call stack.
AssignAsyncControlFlowRuntime(this);
+ RegisterLog(TimelineObserver);
}
///
@@ -425,8 +434,7 @@ internal override void SendEvent(ActorId targetId, Event e, Actor sender, Guid o
}
///
- internal override async Task SendEventAndExecuteAsync(ActorId targetId, Event e, Actor sender,
- Guid opGroupId)
+ internal override async Task SendEventAndExecuteAsync(ActorId targetId, Event e, Actor sender, Guid opGroupId)
{
Assert(sender is StateMachine, "Only an actor can call 'SendEventAndExecuteAsync': avoid " +
"calling it directly from the test method; instead call it through a test driver actor.");
@@ -460,6 +468,13 @@ private EnqueueStatus EnqueueEvent(ActorId targetId, Event e, Actor sender, Guid
"Cannot send event '{0}' to actor id '{1}' that is not bound to an actor instance.",
e.GetType().FullName, targetId.Value);
+ Scheduler.ScheduledOperation.LastEvent = e;
+ Scheduler.ScheduledOperation.LastSentReceiver = targetId.ToString();
+
+ foreach (var monitor in SendEventMonitors) {
+ monitor.OnSendEvent(sender.Id, e.Loc, targetId, LogWriter.JsonLogger.VcGenerator);
+ }
+
Scheduler.ScheduleNextEnabledOperation(AsyncOperationType.Send);
ResetProgramCounter(sender as StateMachine);
@@ -480,6 +495,9 @@ private EnqueueStatus EnqueueEvent(ActorId targetId, Event e, Actor sender, Guid
return EnqueueStatus.Dropped;
}
+ foreach (var monitor in SendEventMonitors) {
+ monitor.OnSendEventDone(sender.Id, e.Loc, targetId, LogWriter.JsonLogger.VcGenerator);
+ }
var enqueueStatus = EnqueueEvent(target, e, sender, opGroupId);
if (enqueueStatus == EnqueueStatus.Dropped)
{
@@ -517,6 +535,7 @@ private EnqueueStatus EnqueueEvent(Actor actor, Event e, Actor sender, Guid opGr
LogWriter.LogSendEvent(actor.Id, sender?.Id.Name, sender?.Id.Type, stateName,
e, opGroupId, isTargetHalted: false);
+
return actor.Enqueue(e, opGroupId, eventInfo);
}
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/OperationScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/OperationScheduler.cs
index e21e6770e2..a148bd4586 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/OperationScheduler.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/OperationScheduler.cs
@@ -150,7 +150,7 @@ internal void ScheduleNextEnabledOperation(AsyncOperationType type)
}
// Get and order the operations by their id.
- var ops = OperationMap.Values.OrderBy(op => op.Id);
+ var ops = OperationMap.Values.OrderBy(op => op.Id).ToList();
// Try enable any operation that is currently waiting, but has its dependencies already satisfied.
foreach (var op in ops)
@@ -162,6 +162,8 @@ internal void ScheduleNextEnabledOperation(AsyncOperationType type)
}
}
+ // ops = Utils.FindHighPriorityOperations(ops, CheckerConfiguration.InterestingEvents);
+
if (!Strategy.GetNextOperation(current, ops, out var next))
{
// Checks if the program has deadlocked.
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs b/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs
index cac165309f..a94337e3a8 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using PChecker.Actors.Events;
#if !DEBUG
using System.Diagnostics;
#endif
@@ -49,6 +50,8 @@ internal abstract class AsyncOperation : IAsyncOperation
/// True if the next awaiter is controlled, else false.
///
internal bool IsAwaiterControlled;
+ public Event? LastEvent = null;
+ public string LastSentReceiver = "";
///
/// Initializes a new instance of the class.
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractSchedule.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractSchedule.cs
new file mode 100644
index 0000000000..3d0b14d9d8
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractSchedule.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Cryptography.X509Certificates;
+using PChecker.Actors;
+using PChecker.Random;
+
+
+enum State {
+ PosReachR,
+ PosExctdW,
+ PosNoInfo,
+ PosSat,
+ NegExctdW,
+ NegReachW,
+ NegOtherW,
+ NegNoInfo,
+ NegUnsat,
+}
+
+public record Constraint(Operation op1, Operation op2, bool positive)
+{
+ public override string ToString()
+ {
+ return $"({op1}, {op2}, {positive})";
+ }
+}
+public record AbstractSchedule(HashSet constraints) {
+
+ internal AbstractSchedule Mutate(List allConstraints, IRandomValueGenerator random)
+ {
+ List constraints = new(this.constraints);
+
+ int op = random.Next(4);
+ switch (op) {
+ case 0: {
+
+ int index = random.Next(allConstraints.Count);
+ constraints.Add(allConstraints[index]);
+ break;
+ }
+ case 1: {
+ if (constraints.Count > 1) {
+ int index = random.Next(constraints.Count);
+ constraints.RemoveAt(index);
+ index = random.Next(allConstraints.Count);
+ constraints.Add(allConstraints[index]);
+ }
+ break;
+ }
+ case 2: {
+ if (constraints.Count > 1) {
+ int index = random.Next(constraints.Count);
+ constraints.RemoveAt(index);
+ }
+ break;
+ }
+ case 3: {
+ if (constraints.Count > 1) {
+ int index = random.Next(constraints.Count);
+ var c = constraints[index];
+ constraints.RemoveAt(index);
+ constraints.Add(new Constraint(c.op1, c.op2, !c.positive));
+ }
+ break;
+ }
+ }
+ return new(constraints.ToHashSet());
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractScheduleObserver.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractScheduleObserver.cs
new file mode 100644
index 0000000000..36723486f4
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractScheduleObserver.cs
@@ -0,0 +1,348 @@
+using System.Collections.Generic;
+using System.Linq;
+using PChecker.Actors;
+using PChecker.Actors.Logging;
+using PChecker.SystematicTesting.Operations;
+
+internal class AbstractScheduleObserver : ISendEventMonitor
+{
+ AbstractSchedule abstractSchedule;
+ Dictionary> opQueue = new();
+ Dictionary constraintState = new();
+ public Dictionary> avoidSendTo = new();
+ public Dictionary> avoidSchedule = new();
+ public Dictionary> lookingForSchedule = new();
+ public Dictionary> lookingForSendTo = new();
+ public Dictionary> relevantConstraintsByReceiver = new();
+ public Dictionary> relevantConstraintsByOp = new();
+ public bool newConstraint = false;
+
+ public Dictionary visitedConstraints = new();
+ public Dictionary allVisitedConstraints = new();
+
+ public void OnNewAbstractSchedule(AbstractSchedule schedule)
+ {
+ abstractSchedule = schedule;
+ newConstraint = false;
+
+ // Reset everything;
+ opQueue.Clear();
+ avoidSendTo.Clear();
+ avoidSchedule.Clear();
+ constraintState.Clear();
+ lookingForSchedule.Clear();
+ lookingForSendTo.Clear();
+ relevantConstraintsByOp.Clear();
+ relevantConstraintsByReceiver.Clear();
+ visitedConstraints.Clear();
+
+ foreach (var constraint in abstractSchedule.constraints) {
+ if (constraint.positive) {
+ constraintState[constraint] = State.PosNoInfo;
+ } else {
+ constraintState[constraint] = State.NegNoInfo;
+ }
+
+ if (!avoidSendTo.ContainsKey(constraint.op1.Receiver)) {
+ avoidSendTo[constraint.op1.Receiver] = new();
+ }
+
+ if (!lookingForSendTo.ContainsKey(constraint.op1.Receiver)) {
+ lookingForSendTo[constraint.op1.Receiver] = new();
+ }
+
+ if (!relevantConstraintsByReceiver.ContainsKey(constraint.op1.Receiver)) {
+ relevantConstraintsByReceiver[constraint.op1.Receiver] = new();
+ }
+
+ if (!relevantConstraintsByOp.ContainsKey(constraint.op1)) {
+ relevantConstraintsByOp[constraint.op1] = new();
+ }
+
+ if (!relevantConstraintsByOp.ContainsKey(constraint.op2)) {
+ relevantConstraintsByOp[constraint.op2] = new();
+ }
+
+ if (!avoidSchedule.ContainsKey(constraint.op1)) {
+ avoidSchedule[constraint.op1] = new();
+ }
+
+ if (!avoidSchedule.ContainsKey(constraint.op2)) {
+ avoidSchedule[constraint.op2] = new();
+ }
+
+ if (!lookingForSchedule.ContainsKey(constraint.op1)) {
+ lookingForSchedule[constraint.op1] = new();
+ }
+
+ if (!lookingForSchedule.ContainsKey(constraint.op2)) {
+ lookingForSchedule[constraint.op2] = new();
+ }
+
+
+ relevantConstraintsByOp[constraint.op1].Add(constraint);
+ relevantConstraintsByOp[constraint.op2].Add(constraint);
+ }
+ }
+
+
+ public HashSet GetRelevantConstraints(Operation op)
+ {
+ var constraints = new HashSet();
+ if (relevantConstraintsByReceiver.ContainsKey(op.Receiver)) {
+ constraints.UnionWith(relevantConstraintsByReceiver[op.Receiver]);
+ }
+ if (relevantConstraintsByOp.ContainsKey(op)) {
+ constraints.UnionWith(relevantConstraintsByOp[op]);
+ }
+ return constraints;
+ }
+
+ public void OnExecute(Operation op)
+ {
+ foreach (var constraint in GetRelevantConstraints(op))
+ {
+ var newState = constraintState[constraint];
+ if (constraint.positive)
+ {
+ if (constraint.op1 == op)
+ {
+ newState = State.PosExctdW;
+ }
+ else if (constraintState[constraint] == State.PosReachR && constraint.op2 == op)
+ {
+ newState = State.PosNoInfo;
+ }
+ else if (constraintState[constraint] == State.PosExctdW && constraint.op2 == op)
+ {
+ newState = State.PosSat;
+ relevantConstraintsByOp[constraint.op1].Remove(constraint);
+ relevantConstraintsByOp[constraint.op2].Remove(constraint);
+ }
+ else if (constraintState[constraint] == State.PosExctdW && avoidSendTo[op.Receiver].Contains(constraint))
+ {
+ newState = State.PosNoInfo;
+ }
+ }
+ else
+ {
+ if (constraint.op1 == op)
+ {
+ newState = State.NegExctdW;
+ }
+ else if (constraintState[constraint] == State.NegExctdW && constraint.op2 != op)
+ {
+ newState = State.NegOtherW;
+ }
+ else if (constraintState[constraint] == State.NegOtherW && constraint.op2 == op)
+ {
+ newState = State.NegOtherW;
+ }
+ else if (constraintState[constraint] == State.NegExctdW && constraint.op2 == op)
+ {
+ newState = State.NegUnsat;
+ relevantConstraintsByOp[constraint.op1].Remove(constraint);
+ relevantConstraintsByOp[constraint.op2].Remove(constraint);
+ }
+
+ }
+ if (newState != constraintState[constraint])
+ {
+ CleanState(constraint);
+ constraintState[constraint] = newState;
+ UpdateLookFor(constraint);
+ }
+ }
+
+ }
+
+ public void OnNewOp(Operation op)
+ {
+ foreach (var constraint in GetRelevantConstraints(op))
+ {
+ var newState = constraintState[constraint];
+ if (constraint.positive)
+ {
+ if (constraintState[constraint] != State.PosExctdW && constraint.op2 == op)
+ {
+ newState = State.PosReachR;
+ }
+ }
+ else
+ {
+ if (constraint.op1 == op)
+ {
+ newState = State.NegReachW;
+ }
+ }
+ if (newState != constraintState[constraint])
+ {
+ CleanState(constraint);
+ constraintState[constraint] = newState;
+ UpdateLookFor(constraint);
+ }
+ }
+ }
+
+ public void CleanState(Constraint constraint)
+ {
+ switch (constraintState[constraint])
+ {
+ case State.PosReachR:
+ avoidSchedule[constraint.op2].Remove(constraint);
+ lookingForSchedule[constraint.op1].Remove(constraint);
+ break;
+ case State.PosExctdW:
+ lookingForSchedule[constraint.op2].Remove(constraint);
+ avoidSendTo[constraint.op1.Receiver].Remove(constraint);
+ relevantConstraintsByReceiver[constraint.op1.Receiver].Remove(constraint);
+ break;
+ case State.NegExctdW:
+ avoidSchedule[constraint.op2].Remove(constraint);
+ lookingForSendTo[constraint.op1.Receiver].Remove(constraint);
+ relevantConstraintsByReceiver[constraint.op1.Receiver].Remove(constraint);
+ break;
+ case State.NegReachW:
+ avoidSchedule[constraint.op1].Remove(constraint);
+ break;
+ case State.NegOtherW:
+ lookingForSchedule[constraint.op2].Remove(constraint);
+ break;
+ }
+ }
+
+ public void UpdateLookFor(Constraint constraint)
+ {
+ switch (constraintState[constraint])
+ {
+ case State.PosReachR:
+ avoidSchedule[constraint.op2].Add(constraint);
+ lookingForSchedule[constraint.op1].Add(constraint);
+ break;
+ case State.PosExctdW:
+ lookingForSchedule[constraint.op2].Add(constraint);
+ avoidSendTo[constraint.op1.Receiver].Add(constraint);
+ relevantConstraintsByReceiver[constraint.op1.Receiver].Add(constraint);
+ break;
+ case State.NegExctdW:
+ avoidSchedule[constraint.op2].Add(constraint);
+ lookingForSendTo[constraint.op1.Receiver].Add(constraint);
+ relevantConstraintsByReceiver[constraint.op1.Receiver].Add(constraint);
+ break;
+ case State.NegReachW:
+ avoidSchedule[constraint.op1].Add(constraint);
+ break;
+ case State.NegOtherW:
+ lookingForSchedule[constraint.op2].Add(constraint);
+ break;
+ }
+ }
+
+ public void OnSendEvent(ActorId sender, int loc, ActorId receiver, VectorClockGenerator currentVc)
+ {
+ var receiverName = receiver.ToString();
+ var senderName = sender.ToString();
+
+ OnNewOp(new Operation(senderName, receiverName, loc));
+ }
+
+ public void OnSendEventDone(ActorId sender, int loc, ActorId receiver, VectorClockGenerator currentVc)
+ {
+ var receiverName = receiver.ToString();
+ var senderName = sender.ToString();
+
+ if (!opQueue.ContainsKey(receiverName))
+ {
+ opQueue[receiverName] = new();
+ }
+ var queue = opQueue[receiverName];
+
+ queue.Add(new Operation(senderName, receiverName, loc));
+ OnExecute(new Operation(senderName, receiverName, loc));
+
+ if (queue.Count > 1) {
+ var op1 = queue[queue.Count - 2];
+ var op2 = queue[queue.Count - 1];
+
+ var c = new Constraint(op1, op2, true);
+
+ if (!visitedConstraints.ContainsKey(c)) {
+ visitedConstraints[c] = 0;
+ }
+ visitedConstraints[c] += 1;
+ }
+ }
+
+ public int GetTraceHash() {
+ if (visitedConstraints.Count == 0) {
+ return "".GetHashCode();
+ }
+ string s = visitedConstraints.ToList().Select(it => $"<{it.Key}, {it.Value}>").OrderBy(it => it).Aggregate((current, next) => current + "," + next);
+ return s.GetHashCode();
+ }
+
+ public bool CheckNoveltyAndUpdate()
+ {
+ bool isNovel = false;
+ foreach (var constraint in visitedConstraints) {
+ if (!allVisitedConstraints.ContainsKey(constraint.Key))
+ {
+ allVisitedConstraints[constraint.Key] = 0;
+ }
+ if (constraint.Value > allVisitedConstraints[constraint.Key])
+ {
+ allVisitedConstraints[constraint.Key] = constraint.Value;
+ isNovel = true;
+ }
+ }
+ return isNovel;
+ }
+
+ public bool CheckAbstractTimelineSatisfied()
+ {
+ return constraintState.All(it => {
+ if (it.Key.positive) {
+ return it.Value == State.PosSat;
+ } else {
+ return it.Value != State.NegUnsat;
+ }
+ });
+ }
+
+ public bool ShouldAvoid(AsyncOperation op)
+ {
+ if (op.Type == AsyncOperationType.Send)
+ {
+ var operation = new Operation(op.Name, op.LastSentReceiver, op.LastEvent!.Loc);
+ if (avoidSchedule.ContainsKey(operation))
+ {
+ return true;
+ }
+ if (avoidSendTo.ContainsKey(operation.Receiver)
+ && avoidSendTo[operation.Receiver].Any(it => it.op2 != operation))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public bool ShouldTake(AsyncOperation op)
+ {
+ if (op.Type == AsyncOperationType.Send)
+ {
+ var operation = new Operation(op.Name, op.LastSentReceiver, op.LastEvent!.Loc);
+ if (lookingForSchedule.ContainsKey(operation))
+ {
+ return true;
+ }
+ if (lookingForSendTo.ContainsKey(operation.Receiver) &&
+ lookingForSendTo[operation.Receiver].Any(it => it.op2 == operation))
+ {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/Coverage/ActivityCoverageReporter.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ActivityCoverageReporter.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/Coverage/ActivityCoverageReporter.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ActivityCoverageReporter.cs
diff --git a/Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogEventCoverage.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ActorRuntimeLogEventCoverage.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogEventCoverage.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ActorRuntimeLogEventCoverage.cs
diff --git a/Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogGraphBuilder.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ActorRuntimeLogGraphBuilder.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogGraphBuilder.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ActorRuntimeLogGraphBuilder.cs
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ConflictOpMonitor.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ConflictOpMonitor.cs
new file mode 100644
index 0000000000..561d7f0e86
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ConflictOpMonitor.cs
@@ -0,0 +1,114 @@
+using System.Collections.Generic;
+using System.Linq;
+using PChecker.Actors;
+using PChecker.Actors.Logging;
+using PChecker.SystematicTesting.Operations;
+
+namespace PChecker.Feedback;
+
+
+public class ConflictOpMonitor: ISendEventMonitor
+{
+
+
+ // This dictionary stores all operations received by a machine.
+ // Each operation is labeled with ActorId, source location, and its corresponding
+ // vector clock timestamp.
+ private Dictionary)>> incomingOps = new();
+
+ private Dictionary> conflictOps = new();
+
+
+ public void OnSendEvent(ActorId sender, int loc, ActorId receiver, VectorClockGenerator currentVc)
+ {
+ var receiverKey = receiver.ToString();
+ var senderKey = sender.ToString();
+ var currentOp = new Operation(senderKey, receiverKey, loc);
+ if (!incomingOps.ContainsKey(receiverKey))
+ {
+ incomingOps.Add(receiverKey, new HashSet<(Operation, Dictionary)>());
+ }
+ var opsSet = incomingOps[receiverKey];
+
+
+
+ if (currentVc.ContextVcMap.TryGetValue(sender.Name, out var vectorClock))
+ {
+
+ foreach (var op in opsSet)
+ {
+ if (op.Item1.Sender == currentOp.Sender)
+ {
+ continue;
+ }
+
+ if (!IsLEQ(op.Item2, vectorClock) && !IsLEQ(vectorClock, op.Item2))
+ {
+ AddConflictOp(op.Item1, currentOp);
+ }
+ }
+ opsSet.Add((currentOp, vectorClock
+ .ToDictionary(entry => entry.Key, entry => entry.Value)));
+ }
+ }
+
+ public void OnSendEventDone(ActorId sender, int loc, ActorId receiver, VectorClockGenerator currentVc) {}
+
+ internal bool IsRacing(AsyncOperation op1, AsyncOperation op2)
+ {
+ if (op1.Type != AsyncOperationType.Send || op2.Type != AsyncOperationType.Send) {
+ return false;
+ }
+
+ var operation1 = new Operation(op1.Name, op1.LastSentReceiver, op1.LastEvent!.Loc);
+ var operation2 = new Operation(op2.Name, op2.LastSentReceiver, op2.LastEvent!.Loc);
+
+ if (conflictOps.TryGetValue(operation1, out var ops)) {
+ return ops.Contains(operation2);
+ }
+ return false;
+ }
+
+ public void Reset() {
+ incomingOps.Clear();
+ }
+
+ bool IsLEQ(Dictionary vc1, Dictionary vc2)
+ {
+ foreach (var key in vc1.Keys.Union(vc2.Keys))
+ {
+ var op1 = vc1.GetValueOrDefault(key, 0);
+ var op2 = vc2.GetValueOrDefault(key, 0);
+ if (op1 > op2)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void AddConflictOp(Operation op1, Operation op2)
+ {
+ if (!conflictOps.ContainsKey(op1)) {
+ conflictOps[op1] = new HashSet();
+ }
+ if (!conflictOps.ContainsKey(op2)) {
+ conflictOps[op2] = new HashSet();
+ }
+ conflictOps[op1].Add(op2);
+ conflictOps[op2].Add(op1);
+ }
+ internal bool IsConflictingOp(AsyncOperation op)
+ {
+ if (op.Type != AsyncOperationType.Send) {
+ return false;
+ }
+
+ var operation = new Operation(op.Name, op.LastSentReceiver, op.LastEvent!.Loc);
+ if (conflictOps.TryGetValue(operation, out var ops ))
+ {
+ return ops.Count != 0;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/Coverage/CoverageInfo.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/CoverageInfo.cs
similarity index 98%
rename from Src/PChecker/CheckerCore/Coverage/CoverageInfo.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/CoverageInfo.cs
index dcca7a6f00..642e88e561 100644
--- a/Src/PChecker/CheckerCore/Coverage/CoverageInfo.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/CoverageInfo.cs
@@ -54,6 +54,8 @@ public CoverageInfo()
Machines = new HashSet();
MachinesToStates = new Dictionary>();
RegisteredEvents = new Dictionary>();
+ EventInfo = new EventCoverage();
+ CoverageGraph = new Graph();
}
///
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ISendEventMonitor.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ISendEventMonitor.cs
new file mode 100644
index 0000000000..394ddb3e9e
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ISendEventMonitor.cs
@@ -0,0 +1,15 @@
+using PChecker.Actors;
+using PChecker.Actors.Logging;
+
+public record Operation(string Sender, string Receiver, int Loc) {
+ public override string ToString()
+ {
+ return $"<{Sender}, {Receiver}, {Loc}>";
+ }
+
+}
+public interface ISendEventMonitor {
+ public void OnSendEvent(ActorId sender, int loc, ActorId receiver, VectorClockGenerator currentVc);
+
+ public void OnSendEventDone(ActorId sender, int loc, ActorId receiver, VectorClockGenerator currentVc);
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/TimelineObserver.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/TimelineObserver.cs
new file mode 100644
index 0000000000..0c0759e3ca
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/TimelineObserver.cs
@@ -0,0 +1,217 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using PChecker.Actors;
+using PChecker.Actors.Events;
+using PChecker.Actors.Logging;
+
+namespace PChecker.Feedback;
+
+public class TimelineObserver: IActorRuntimeLog
+{
+
+ private HashSet<(string, string, string)> _timelines = new();
+ private Dictionary> _allEvents = new();
+ private Dictionary> _orderedEvents = new();
+
+ public static readonly List<(int, int)> Coefficients = new();
+ public static int NumOfCoefficients = 50;
+
+ static TimelineObserver()
+ {
+ // Fix seed to generate same random numbers across runs.
+ var rand = new System.Random(0);
+
+ for (int i = 0; i < NumOfCoefficients; i++)
+ {
+ Coefficients.Add((rand.Next(), rand.Next()));
+ }
+ }
+
+ public void OnCreateActor(ActorId id, string creatorName, string creatorType)
+ {
+
+ }
+
+ public void OnCreateStateMachine(ActorId id, string creatorName, string creatorType)
+ {
+ }
+
+ public void OnExecuteAction(ActorId id, string handlingStateName, string currentStateName, string actionName)
+ {
+
+ }
+
+ public void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName, Event e,
+ Guid opGroupId, bool isTargetHalted)
+ {
+ }
+
+ public void OnRaiseEvent(ActorId id, string stateName, Event e)
+ {
+
+ }
+
+ public void OnEnqueueEvent(ActorId id, Event e)
+ {
+
+ }
+
+ public void OnDequeueEvent(ActorId id, string stateName, Event e)
+ {
+ string actor = id.Type;
+
+ _allEvents.TryAdd(actor, new());
+ _orderedEvents.TryAdd(actor, new());
+
+ string name = e.GetType().Name;
+ foreach (var ev in _allEvents[actor])
+ {
+ _timelines.Add((actor, ev, name));
+ }
+ _allEvents[actor].Add(name);
+ _orderedEvents[actor].Add(name);
+ }
+
+ public int GetTimelineHash()
+ {
+ return GetAbstractTimeline().GetHashCode();
+ }
+
+ public string GetAbstractTimeline()
+ {
+ var tls = _timelines.Select(it => $"<{it.Item1}, {it.Item2}, {it.Item3}>").ToList();
+ tls.Sort();
+ return string.Join(";", tls);
+ }
+
+ public string GetTimeline()
+ {
+ return string.Join(";", _orderedEvents.Select(it =>
+ {
+ var events = string.Join(",", it.Value);
+ return $"{it.Key}: {events}";
+ }));
+ }
+
+ public List GetTimelineMinhash()
+ {
+ List minHash = new();
+ var timelineHash = _timelines.Select(it => it.GetHashCode());
+ foreach (var (a, b) in Coefficients)
+ {
+ int minValue = Int32.MaxValue;
+ foreach (var value in timelineHash)
+ {
+ int hash = a * value + b;
+ minValue = Math.Min(minValue, hash);
+ }
+ minHash.Add(minValue);
+ }
+ return minHash;
+ }
+
+ public void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked)
+ {
+
+ }
+
+ public void OnWaitEvent(ActorId id, string stateName, Type eventType)
+ {
+
+ }
+
+ public void OnWaitEvent(ActorId id, string stateName, params Type[] eventTypes)
+ {
+
+ }
+
+ public void OnStateTransition(ActorId id, string stateName, bool isEntry)
+ {
+
+ }
+
+ public void OnGotoState(ActorId id, string currentStateName, string newStateName)
+ {
+ }
+
+ public void OnDefaultEventHandler(ActorId id, string stateName)
+ {
+
+ }
+
+ public void OnHalt(ActorId id, int inboxSize)
+ {
+
+ }
+
+ public void OnHandleRaisedEvent(ActorId id, string stateName, Event e)
+ {
+
+ }
+
+ public void OnPopStateUnhandledEvent(ActorId id, string stateName, Event e)
+ {
+
+ }
+
+ public void OnExceptionThrown(ActorId id, string stateName, string actionName, Exception ex)
+ {
+
+ }
+
+ public void OnExceptionHandled(ActorId id, string stateName, string actionName, Exception ex)
+ {
+
+ }
+
+ public void OnCreateMonitor(string monitorType)
+ {
+
+ }
+
+ public void OnMonitorExecuteAction(string monitorType, string stateName, string actionName)
+ {
+
+ }
+
+ public void OnMonitorProcessEvent(string monitorType, string stateName, string senderName, string senderType,
+ string senderStateName, Event e)
+ {
+
+ }
+
+ public void OnMonitorRaiseEvent(string monitorType, string stateName, Event e)
+ {
+
+ }
+
+ public void OnMonitorStateTransition(string monitorType, string stateName, bool isEntry, bool? isInHotState)
+ {
+
+ }
+
+ public void OnMonitorError(string monitorType, string stateName, bool? isInHotState)
+ {
+
+ }
+
+ public void OnRandom(object result, string callerName, string callerType)
+ {
+
+ }
+
+ public void OnAssertionFailure(string error)
+ {
+
+ }
+
+ public void OnStrategyDescription(string strategyName, string description)
+ {
+
+ }
+
+ public void OnCompleted()
+ {
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
new file mode 100644
index 0000000000..7d3f4a82f7
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
@@ -0,0 +1,305 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using PChecker.Generator;
+using PChecker.Feedback;
+using AsyncOperation = PChecker.SystematicTesting.Operations.AsyncOperation;
+using Debug = System.Diagnostics.Debug;
+
+namespace PChecker.SystematicTesting.Strategies.Feedback;
+
+
+internal class FeedbackGuidedStrategy : IFeedbackGuidedStrategy
+ where TInput: IInputGenerator
+ where TSchedule: IScheduleGenerator
+{
+ public record StrategyGenerator(TInput InputGenerator, TSchedule ScheduleGenerator);
+
+ public record GeneratorRecord(int Priority, StrategyGenerator Generator, List MinHash);
+
+ protected StrategyGenerator Generator;
+
+ private readonly int _maxScheduledSteps;
+
+ protected int ScheduledSteps;
+
+ private readonly HashSet _visitedTimelines = new();
+
+ private List _savedGenerators = new ();
+ private int _pendingMutations = 0;
+ private HashSet _visitedGenerators = new HashSet();
+ private GeneratorRecord? _currentParent = null;
+
+ private readonly bool _savePartialMatch;
+ private readonly bool _diversityBasedPriority;
+ private readonly bool _ignorePatternFeedback;
+ private readonly int _discardAfter;
+ private readonly bool _priorityBasedSampling;
+ private System.Random _rnd = new System.Random();
+
+
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public FeedbackGuidedStrategy(CheckerConfiguration checkerConfiguration, TInput input, TSchedule schedule)
+ {
+ if (schedule is PctScheduleGenerator)
+ {
+ _maxScheduledSteps = checkerConfiguration.MaxUnfairSchedulingSteps;
+ }
+ else
+ {
+ _maxScheduledSteps = checkerConfiguration.MaxFairSchedulingSteps;
+ }
+ Generator = new StrategyGenerator(input, schedule);
+ _savePartialMatch = checkerConfiguration.SavePartialMatch;
+ _diversityBasedPriority = checkerConfiguration.DiversityBasedPriority;
+ _discardAfter = checkerConfiguration.DiscardAfter;
+ _ignorePatternFeedback = checkerConfiguration.IgnorePatternFeedback;
+ _priorityBasedSampling = checkerConfiguration.PriorityBasedSampling;
+ }
+
+ ///
+ public virtual bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
+ {
+ // var enabledOperations = _nfa != null? _nfa.FindHighPriorityOperations(ops) : ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
+ next = Generator.ScheduleGenerator.NextRandomOperation(ops.ToList(), current);
+ ScheduledSteps++;
+ return next != null;
+ }
+
+ ///
+ public bool GetNextBooleanChoice(AsyncOperation current, int maxValue, out bool next)
+ {
+ next = Generator.InputGenerator.Next(maxValue) == 0;
+ ScheduledSteps++;
+ return true;
+ }
+
+ ///
+ public bool GetNextIntegerChoice(AsyncOperation current, int maxValue, out int next)
+ {
+ next = Generator.InputGenerator.Next(maxValue);
+ ScheduledSteps++;
+ return true;
+ }
+
+ ///
+ public virtual bool PrepareForNextIteration()
+ {
+ ScheduledSteps = 0;
+ PrepareNextInput();
+ return true;
+ }
+
+ ///
+ public int GetScheduledSteps()
+ {
+ return ScheduledSteps;
+ }
+
+ ///
+ public bool HasReachedMaxSchedulingSteps()
+ {
+ if (_maxScheduledSteps == 0)
+ {
+ return false;
+ }
+
+ return ScheduledSteps >= _maxScheduledSteps;
+ }
+
+ ///
+ public bool IsFair()
+ {
+ return true;
+ }
+
+ ///
+ public string GetDescription()
+ {
+ return "feedback";
+ }
+
+ ///
+ public void Reset()
+ {
+ ScheduledSteps = 0;
+ }
+
+ private int ComputeDiversity(int timeline, List hash)
+ {
+ if (!_visitedTimelines.Add(timeline))
+ {
+ return 0;
+ }
+
+ if (!_priorityBasedSampling)
+ {
+ return 20;
+ }
+
+ if (_savedGenerators.Count == 0 || !_diversityBasedPriority)
+ {
+ return 20;
+ }
+
+ var maxSim = int.MinValue;
+ foreach (var record in _savedGenerators)
+ {
+ var timelineHash = record.MinHash;
+ var similarity = 0;
+ for (int i = 0; i < hash.Count; i++)
+ {
+ if (hash[i] == timelineHash[i])
+ {
+ similarity += 1;
+ }
+ }
+
+ maxSim = Math.Max(maxSim, similarity);
+ }
+
+
+ return (hash.Count - maxSim) * 10 + 20;
+ }
+
+ ///
+ /// This method observes the results of previous run and prepare for the next run.
+ ///
+ /// The ControlledRuntime of previous run.
+ public virtual void ObserveRunningResults(EventPatternObserver patternObserver, ControlledRuntime runtime)
+ {
+ var timelineHash = runtime.TimelineObserver.GetTimelineHash();
+ var timelineMinhash = runtime.TimelineObserver.GetTimelineMinhash();
+
+ int diversityScore = ComputeDiversity(timelineHash, timelineMinhash);
+
+ if (diversityScore == 0)
+ {
+ return;
+ }
+
+ int priority = 0;
+ if (patternObserver == null || _ignorePatternFeedback || !_priorityBasedSampling)
+ {
+ priority = diversityScore;
+ }
+ else
+ {
+ int coverageResult = patternObserver.ShouldSave();
+ if (coverageResult == 1 || _savePartialMatch)
+ {
+ double coverageScore = 1.0 / coverageResult;
+ priority = (int)(diversityScore * coverageScore);
+ }
+ }
+
+ if (priority > 0)
+ {
+ var record = new GeneratorRecord(priority, Generator, timelineMinhash);
+ if (_savedGenerators.Count == 0)
+ {
+ _savedGenerators.Add(record);
+ return;
+ }
+
+ // Maybe use binary search to speed up in the future.
+ var index = 0;
+ while (index < _savedGenerators.Count && priority < _savedGenerators[index].Priority)
+ {
+ index += 1;
+ }
+ if (index >= _savedGenerators.Count)
+ {
+ _savedGenerators.Add(record);
+ }
+ else
+ {
+ _savedGenerators.Insert(index, record);
+ }
+
+ if (_priorityBasedSampling && _savedGenerators.Count > _discardAfter)
+ {
+ var last = _savedGenerators.Last();
+ _visitedGenerators.Remove(last);
+ _savedGenerators.RemoveAt(_savedGenerators.Count - 1);
+ }
+ }
+ }
+
+ public int TotalSavedInputs()
+ {
+ return _savedGenerators.Count;
+ }
+
+ private void PrepareNextInput()
+ {
+ Generator.ScheduleGenerator.PrepareForNextInput();
+ if (_savedGenerators.Count == 0)
+ {
+ // Mutate current input if no input is saved.
+ Generator = NewGenerator();
+ }
+ else
+ {
+ if (!_priorityBasedSampling && _pendingMutations == 0)
+ {
+ _currentParent = _savedGenerators[_rnd.Next(_savedGenerators.Count)];
+ _pendingMutations = 50;
+ }
+
+ if (_currentParent == null)
+ {
+ _currentParent = _savedGenerators.First();
+ _visitedGenerators.Add(_currentParent);
+ _pendingMutations = _currentParent.Priority;
+ _pendingMutations = 50;
+ }
+
+ if (_pendingMutations == 0)
+ {
+ bool found = false;
+ foreach (var generator in _savedGenerators)
+ {
+ if (_visitedGenerators.Contains(generator)) continue;
+ _currentParent = generator;
+ _visitedGenerators.Add(generator);
+ _pendingMutations = generator.Priority;
+ _pendingMutations = 50;
+ found = true;
+ }
+
+ if (!found)
+ {
+ _visitedGenerators.Clear();
+ _currentParent = _savedGenerators.First();
+ _visitedGenerators.Add(_currentParent);
+ _pendingMutations = _currentParent.Priority;
+ _pendingMutations = 50;
+ }
+ }
+
+ Generator = MutateGenerator(_currentParent.Generator);
+ _pendingMutations -= 1;
+ }
+ }
+
+
+ protected virtual StrategyGenerator MutateGenerator(StrategyGenerator prev)
+ {
+ return new StrategyGenerator(prev.InputGenerator.Mutate(), prev.ScheduleGenerator.Mutate());
+ }
+
+ protected virtual StrategyGenerator NewGenerator()
+ {
+ return new StrategyGenerator(Generator.InputGenerator.New(), Generator.ScheduleGenerator.New());
+ }
+
+ public void DumpStats(TextWriter writer)
+ {
+ writer.WriteLine($"..... Total saved: {TotalSavedInputs()}, pending mutations: {_pendingMutations}, visited generators: {_visitedGenerators.Count}");
+ }
+}
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IGenerator.cs
new file mode 100644
index 0000000000..6a043dc691
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IGenerator.cs
@@ -0,0 +1,18 @@
+namespace PChecker.Generator;
+
+public interface IGenerator
+{
+ ///
+ /// Mutate the current generator and create a new one.
+ ///
+ /// A new generator.
+ T Mutate();
+
+ ///
+ /// Copy the current generator and create a new one.
+ ///
+ /// A new generator.
+ T Copy();
+
+ T New();
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IInputGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IInputGenerator.cs
new file mode 100644
index 0000000000..a8ce3b097f
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IInputGenerator.cs
@@ -0,0 +1,22 @@
+namespace PChecker.Generator;
+
+public interface IInputGenerator : IGenerator
+{
+
+ ///
+ /// Returns a non-negative random number.
+ ///
+ int Next();
+
+ ///
+ /// Returns a non-negative random number less than maxValue.
+ ///
+ /// Exclusive upper bound
+ int Next(int maxValue);
+
+ ///
+ /// Returns a random floating-point number that is greater
+ /// than or equal to 0.0, and less than 1.0.
+ ///
+ double NextDouble();
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IScheduleGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IScheduleGenerator.cs
new file mode 100644
index 0000000000..4850f55ef6
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IScheduleGenerator.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+using PChecker.SystematicTesting.Operations;
+
+namespace PChecker.Generator;
+
+internal interface IScheduleGenerator: IGenerator
+{
+ ///
+ /// Get the next scheduled operation.
+ ///
+ /// All enabled operations.
+ /// Current operation.
+ /// Next enabled operation.
+ public AsyncOperation? NextRandomOperation(List enabledOperations, AsyncOperation current);
+
+
+ public void PrepareForNextInput();
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/IMutator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/IMutator.cs
new file mode 100644
index 0000000000..93302c6d3a
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/IMutator.cs
@@ -0,0 +1,6 @@
+namespace PChecker.Generator.Mutator;
+
+public interface IMutator
+{
+ T Mutate(T prev);
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PCTScheduleMutator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PCTScheduleMutator.cs
new file mode 100644
index 0000000000..eec20e4076
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PCTScheduleMutator.cs
@@ -0,0 +1,17 @@
+namespace PChecker.Generator.Mutator;
+
+internal class PCTScheduleMutator : IMutator
+{
+ private int _meanMutationCount = 5;
+ private int _meanMutationSize = 5;
+ private System.Random _random = new();
+ public PctScheduleGenerator Mutate(PctScheduleGenerator prev)
+ {
+ return new PctScheduleGenerator(prev.Random,
+ Utils.MutateRandomChoices(prev.PriorityChoices, _meanMutationCount, _meanMutationSize, _random),
+ Utils.MutateRandomChoices(prev.SwitchPointChoices, _meanMutationCount, _meanMutationSize, _random),
+ prev.MaxPrioritySwitchPoints,
+ prev.ScheduleLength
+ );
+ }
+}
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/POSScheduleMutator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/POSScheduleMutator.cs
new file mode 100644
index 0000000000..d94b042661
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/POSScheduleMutator.cs
@@ -0,0 +1,16 @@
+namespace PChecker.Generator.Mutator;
+
+internal class POSScheduleMutator: IMutator
+{
+ private int _meanMutationCount = 5;
+ private int _meanMutationSize = 5;
+ private System.Random _random = new();
+ public POSScheduleGenerator Mutate(POSScheduleGenerator prev)
+ {
+ return new POSScheduleGenerator(prev.Random,
+ Utils.MutateRandomChoices(prev.PriorityChoices, _meanMutationCount, _meanMutationSize, _random),
+ Utils.MutateRandomChoices(prev.SwitchPointChoices, _meanMutationCount, _meanMutationSize, _random),
+ prev.Monitor
+ );
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PctcpScheduleMutator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PctcpScheduleMutator.cs
new file mode 100644
index 0000000000..b057aeac5a
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PctcpScheduleMutator.cs
@@ -0,0 +1,19 @@
+namespace PChecker.Generator.Mutator;
+
+internal class PctcpScheduleMutator: IMutator
+{
+ private int _meanMutationCount = 5;
+ private int _meanMutationSize = 5;
+ private System.Random _random = new();
+ public PctcpScheduleGenerator Mutate(PctcpScheduleGenerator prev)
+ {
+ return new PctcpScheduleGenerator(prev.Random,
+ Utils.MutateRandomChoices(prev.PriorityChoices, _meanMutationCount, _meanMutationSize, _random),
+ Utils.MutateRandomChoices(prev.SwitchPointChoices, _meanMutationCount, _meanMutationSize, _random),
+ prev.MaxPrioritySwitchPoints,
+ prev.ScheduleLength,
+ prev.VcWrapper
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomInputMutator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomInputMutator.cs
new file mode 100644
index 0000000000..33409f939a
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomInputMutator.cs
@@ -0,0 +1,17 @@
+using System;
+using System.IO;
+using PChecker.Generator.Object;
+
+namespace PChecker.Generator.Mutator;
+
+public class RandomInputMutator : IMutator
+{
+ private readonly int _meanMutationCount = 10;
+ private readonly int _meanMutationSize = 10;
+ private System.Random _random = new();
+ public RandomInputGenerator Mutate(RandomInputGenerator prev)
+ {
+ return new RandomInputGenerator(prev.Random, Utils.MutateRandomChoices(prev.IntChoices, _meanMutationCount, _meanMutationSize, _random),
+ Utils.MutateRandomChoices(prev.DoubleChoices, _meanMutationCount, _meanMutationSize, _random));
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomScheduleMutator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomScheduleMutator.cs
new file mode 100644
index 0000000000..ac6aed409c
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomScheduleMutator.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using PChecker.Generator.Object;
+
+namespace PChecker.Generator.Mutator;
+
+internal class RandomScheduleMutator : IMutator
+{
+ private readonly int _meanMutationCount = 10;
+ private readonly int _meanMutationSize = 10;
+ private System.Random _random = new();
+ public RandomScheduleGenerator Mutate(RandomScheduleGenerator prev)
+ {
+ return new RandomScheduleGenerator(prev.Random, Utils.MutateRandomChoices(prev.IntChoices, _meanMutationCount, _meanMutationSize, _random));
+ }
+
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/Utils.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/Utils.cs
new file mode 100644
index 0000000000..8ae1e5b165
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/Utils.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Linq;
+using PChecker.Generator.Object;
+
+namespace PChecker.Generator.Mutator;
+
+public class Utils
+{
+ public static int SampleGeometric(double p, double random) {
+ var result = Math.Ceiling(Math.Log(1 - random) / Math.Log(1 - p));
+ return (int)result;
+ }
+ public static RandomChoices MutateRandomChoices (RandomChoices randomChoices, int meanMutationCount, int meanMutationSize, System.Random random)
+ where T: IConvertible
+ {
+ meanMutationCount = Math.Max(Math.Min(randomChoices.Data.Count / 3, meanMutationCount), 1);
+ meanMutationSize = Math.Max(Math.Min(randomChoices.Data.Count / 3, meanMutationSize), 1);
+ RandomChoices newChoices = new RandomChoices(randomChoices);
+ int mutations = Utils.SampleGeometric(1.0f / meanMutationCount, random.NextDouble());
+
+ while (mutations-- > 0)
+ {
+ int offset = random.Next(newChoices.Data.Count);
+ int mutationSize = Utils.SampleGeometric(1.0f / meanMutationSize, random.NextDouble());
+ for (int i = offset; i < offset + mutationSize; i++)
+ {
+ if (i >= newChoices.Data.Count)
+ {
+ break;
+ }
+
+ newChoices.Data[i] = newChoices.GenerateNew();
+ }
+ }
+
+ return newChoices;
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/RandomChoices.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/RandomChoices.cs
new file mode 100644
index 0000000000..e32d1e007e
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/RandomChoices.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Data.Common;
+using PChecker.Exceptions;
+
+namespace PChecker.Generator.Object;
+
+public class RandomChoices
+where T: IConvertible
+{
+ private readonly System.Random _random;
+ public int Pos;
+ public List Data = new();
+
+ public RandomChoices(System.Random random)
+ {
+ _random = random;
+ }
+
+ public RandomChoices(RandomChoices other)
+ {
+ _random = other._random;
+ Data = new List(other.Data);
+ }
+
+ public T Next()
+ {
+ if (Pos == Data.Count)
+ {
+ Data.Add(GenerateNew());
+ }
+ return Data[Pos++];
+ }
+
+ public T GenerateNew()
+ {
+ if (typeof(T).IsAssignableFrom(typeof(int)))
+ {
+ return (T) Convert.ChangeType(_random.Next(), typeof(T));
+ }
+ else if (typeof(T).IsAssignableFrom(typeof(double)))
+ {
+ return (T) Convert.ChangeType(_random.NextDouble(), typeof(T));
+ }
+ else
+ {
+ throw new RuntimeException("The random choices only supports int and double type.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PCTScheduleGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PCTScheduleGenerator.cs
new file mode 100644
index 0000000000..0a0ed19401
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PCTScheduleGenerator.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using PChecker.Generator.Mutator;
+using PChecker.Generator.Object;
+using PChecker.SystematicTesting.Operations;
+using PChecker.SystematicTesting.Strategies.Probabilistic;
+
+namespace PChecker.Generator;
+
+internal sealed class PctScheduleGenerator: PCTScheduler, IScheduleGenerator
+{
+ public System.Random Random;
+ public RandomChoices PriorityChoices;
+ public RandomChoices SwitchPointChoices;
+
+ public PctScheduleGenerator(System.Random random, RandomChoices? priorityChoices, RandomChoices? switchPointChoices, int numSwitchPoints, int maxScheduleLength):
+ base(numSwitchPoints, maxScheduleLength,
+ new ParametricProvider(
+ priorityChoices != null ? new RandomChoices(priorityChoices) : new RandomChoices(random),
+ switchPointChoices != null ? new RandomChoices(switchPointChoices) : new RandomChoices(random)))
+ {
+ Random = random;
+ var provider = (ParametricProvider) Provider;
+ PriorityChoices = provider.PriorityChoices;
+ SwitchPointChoices = provider.SwitchPointChoices;
+ }
+
+ public PctScheduleGenerator(CheckerConfiguration checkerConfiguration):
+ this(new System.Random((int?)checkerConfiguration.RandomGeneratorSeed ?? Guid.NewGuid().GetHashCode()), null, null, checkerConfiguration.StrategyBound, 0)
+ {
+ }
+
+ public PctScheduleGenerator Mutate()
+ {
+ return new PCTScheduleMutator().Mutate(this);
+ }
+
+ public PctScheduleGenerator New()
+ {
+ return new PctScheduleGenerator(Random, null, null, MaxPrioritySwitchPoints, ScheduleLength);
+ }
+
+ public PctScheduleGenerator Copy()
+ {
+ return new PctScheduleGenerator(Random, PriorityChoices, SwitchPointChoices, MaxPrioritySwitchPoints, ScheduleLength);
+ }
+
+ public AsyncOperation? NextRandomOperation(List enabledOperations, AsyncOperation current)
+ {
+ if (GetNextOperation(current, enabledOperations, out var next)) {
+ return next;
+ } else {
+ return null;
+ }
+ }
+
+
+ public void PrepareForNextInput()
+ {
+ PrepareForNextIteration();
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/POSScheduleGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/POSScheduleGenerator.cs
new file mode 100644
index 0000000000..fffc0ba15d
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/POSScheduleGenerator.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using PChecker.Feedback;
+using PChecker.Generator.Mutator;
+using PChecker.Generator.Object;
+using PChecker.SystematicTesting.Operations;
+using PChecker.SystematicTesting.Strategies.Probabilistic;
+
+namespace PChecker.Generator;
+
+internal class POSScheduleGenerator: POSScheduler, IScheduleGenerator
+{
+ public System.Random Random;
+ public RandomChoices PriorityChoices;
+ public RandomChoices SwitchPointChoices;
+ public ConflictOpMonitor? Monitor;
+
+ public POSScheduleGenerator(System.Random random, RandomChoices? priorityChoices, RandomChoices? switchPointChoices,
+ ConflictOpMonitor? monitor):
+ base(new ParametricProvider(
+ priorityChoices != null ? new RandomChoices(priorityChoices) : new RandomChoices(random),
+ switchPointChoices != null ? new RandomChoices(switchPointChoices) : new RandomChoices(random)),
+ monitor)
+ {
+ Random = random;
+ var provider = (ParametricProvider) Provider;
+ PriorityChoices = provider.PriorityChoices;
+ SwitchPointChoices = provider.SwitchPointChoices;
+ Monitor = monitor;
+ }
+
+ public POSScheduleGenerator(CheckerConfiguration checkerConfiguration, ConflictOpMonitor? monitor):
+ this(new System.Random((int?)checkerConfiguration.RandomGeneratorSeed ?? Guid.NewGuid().GetHashCode()), null,
+ null, monitor)
+ {
+ }
+
+ public POSScheduleGenerator Mutate()
+ {
+ return new POSScheduleMutator().Mutate(this);
+ }
+
+ public POSScheduleGenerator New()
+ {
+ return new POSScheduleGenerator(Random, null, null, Monitor);
+ }
+
+ public POSScheduleGenerator Copy()
+ {
+ return new POSScheduleGenerator(Random, PriorityChoices, SwitchPointChoices, Monitor);
+ }
+
+ public AsyncOperation? NextRandomOperation(List enabledOperations, AsyncOperation current)
+ {
+ if (GetNextOperation(current, enabledOperations, out var next)) {
+ return next;
+ } else {
+ return null;
+ }
+ }
+
+ public void PrepareForNextInput()
+ {
+ PrepareForNextIteration();
+ }
+
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/ParametricProvider.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/ParametricProvider.cs
new file mode 100644
index 0000000000..0ffc657564
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/ParametricProvider.cs
@@ -0,0 +1,27 @@
+using PChecker.Generator.Object;
+using PChecker.SystematicTesting.Strategies.Probabilistic;
+
+namespace PChecker.Generator;
+
+internal class ParametricProvider: PriorizationProvider
+{
+ public RandomChoices PriorityChoices;
+ public RandomChoices SwitchPointChoices;
+ public ParametricProvider(RandomChoices priority, RandomChoices switchPoint)
+ {
+ PriorityChoices = priority;
+ SwitchPointChoices = switchPoint;
+ }
+
+ public int AssignPriority(int numOps)
+ {
+
+ return PriorityChoices.Next() % numOps + 1;
+ }
+
+ public double SwitchPointChoice()
+ {
+ return SwitchPointChoices.Next();
+ }
+
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PctcpScheduleGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PctcpScheduleGenerator.cs
new file mode 100644
index 0000000000..34ffe087d0
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PctcpScheduleGenerator.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using PChecker.Generator.Mutator;
+using PChecker.Generator.Object;
+using PChecker.SystematicTesting.Operations;
+using PChecker.SystematicTesting.Strategies.Probabilistic;
+using PChecker.SystematicTesting.Strategies.Probabilistic.pctcp;
+
+namespace PChecker.Generator;
+
+internal class PctcpScheduleGenerator: PCTCPScheduler, IScheduleGenerator
+{
+
+ public System.Random Random;
+ public RandomChoices PriorityChoices;
+ public RandomChoices SwitchPointChoices;
+
+ public PctcpScheduleGenerator(System.Random random, RandomChoices? priorityChoices, RandomChoices?
+ switchPointChoices, int numSwitchPoints, int maxScheduleLength, VectorClockWrapper wrapper):
+ base(numSwitchPoints, maxScheduleLength,
+ new ParametricProvider(
+ priorityChoices != null ? new RandomChoices(priorityChoices) : new RandomChoices(random),
+ switchPointChoices != null ? new RandomChoices(switchPointChoices) : new
+ RandomChoices(random)), wrapper)
+ {
+ Random = random;
+ var provider = (ParametricProvider) Provider;
+ PriorityChoices = provider.PriorityChoices;
+ SwitchPointChoices = provider.SwitchPointChoices;
+ }
+ public PctcpScheduleGenerator(CheckerConfiguration checkerConfiguration, VectorClockWrapper wrapper):
+ this(new System.Random((int?)checkerConfiguration.RandomGeneratorSeed ?? Guid.NewGuid().GetHashCode()), null,
+ null, checkerConfiguration.StrategyBound, 0, wrapper)
+ {
+ }
+
+ public PctcpScheduleGenerator Mutate()
+ {
+ return new PctcpScheduleMutator().Mutate(this);
+ }
+
+ public PctcpScheduleGenerator New()
+ {
+ return new PctcpScheduleGenerator(Random, null, null, MaxPrioritySwitchPoints, ScheduleLength, VcWrapper);
+ }
+
+ public PctcpScheduleGenerator Copy()
+ {
+ return new PctcpScheduleGenerator(Random, PriorityChoices, SwitchPointChoices, MaxPrioritySwitchPoints,
+ ScheduleLength, VcWrapper);
+ }
+
+ public AsyncOperation? NextRandomOperation(List enabledOperations, AsyncOperation current)
+ {
+ if (GetNextOperation(current, enabledOperations, out var next)) {
+ return next;
+ } else {
+ return null;
+ }
+ }
+
+
+ public void PrepareForNextInput()
+ {
+ PrepareForNextIteration();
+ }
+
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomInputGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomInputGenerator.cs
new file mode 100644
index 0000000000..bde03ddd3c
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomInputGenerator.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using PChecker.Generator.Mutator;
+using PChecker.Generator.Object;
+
+namespace PChecker.Generator
+{
+
+ ///
+ /// This class implements a JQF-style stream-based input generator.
+ /// See more: https://github.com/rohanpadhye/JQF
+ ///
+ public class RandomInputGenerator : IInputGenerator
+ {
+ ///
+ /// Device for generating random numbers.
+ ///
+ internal readonly System.Random Random;
+
+ internal RandomChoices IntChoices;
+ internal RandomChoices DoubleChoices;
+
+ public RandomInputGenerator(System.Random random, RandomChoices? intChoices, RandomChoices? doubleChoices)
+ {
+ Random = random;
+ IntChoices = intChoices != null ? new RandomChoices(intChoices) : new RandomChoices(Random);
+ DoubleChoices = doubleChoices != null ? new RandomChoices(doubleChoices) : new RandomChoices(Random);
+ }
+
+
+ ///
+ /// Create a stream based value generator using CheckerConfiguration.
+ ///
+ ///
+ public RandomInputGenerator(CheckerConfiguration checkerConfiguration):
+ this(new System.Random((int?)checkerConfiguration.RandomGeneratorSeed ?? Guid.NewGuid().GetHashCode()), null, null)
+ {
+ }
+
+ ///
+ /// Create a default stream based value generator.
+ ///
+ public RandomInputGenerator():
+ this(new System.Random(Guid.NewGuid().GetHashCode()), null, null)
+ {
+ }
+
+
+ ///
+ /// Create a stream based value generator with an existing generator.
+ ///
+ ///
+ public RandomInputGenerator(RandomInputGenerator other) : this(other.Random, other.IntChoices, other.DoubleChoices)
+ {
+ }
+
+ ///
+ /// Returns a non-negative random number.
+ ///
+ public int Next()
+ {
+ return IntChoices.Next();
+ }
+
+
+ ///
+ /// Returns a non-negative random number less than the specified max value.
+ ///
+ /// Exclusive upper bound.
+ public int Next(int maxValue)
+ {
+ var value = maxValue == 0 ? 0 : Next() % maxValue;
+ return value;
+ }
+
+ ///
+ /// Returns a random floating-point number that is greater
+ /// than or equal to 0.0, and less than 1.0.
+ ///
+ public double NextDouble()
+ {
+ return DoubleChoices.Next();
+ }
+
+ public RandomInputGenerator Mutate()
+ {
+ return new RandomInputMutator().Mutate(this);
+ }
+
+ public RandomInputGenerator Copy()
+ {
+ return new RandomInputGenerator(this);
+ }
+
+ public RandomInputGenerator New()
+ {
+ return new RandomInputGenerator(Random, null, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomScheduleGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomScheduleGenerator.cs
new file mode 100644
index 0000000000..98f64b77a8
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomScheduleGenerator.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using PChecker.Generator.Mutator;
+using PChecker.Generator.Object;
+using PChecker.SystematicTesting.Operations;
+
+namespace PChecker.Generator;
+
+internal class RandomScheduleGenerator: IScheduleGenerator
+{
+ internal readonly System.Random Random;
+
+ public RandomChoices IntChoices;
+
+ public RandomScheduleGenerator(System.Random random, RandomChoices? intChoices)
+ {
+ Random = random;
+ IntChoices = intChoices != null ? new RandomChoices(intChoices) : new RandomChoices(Random);
+ }
+
+ public RandomScheduleGenerator(CheckerConfiguration checkerConfiguration):
+ this(new System.Random((int?)checkerConfiguration.RandomGeneratorSeed ?? Guid.NewGuid().GetHashCode()) , null)
+ {
+ }
+
+ public AsyncOperation? NextRandomOperation(List enabledOperations, AsyncOperation current)
+ {
+ if (enabledOperations.Count == 0)
+ {
+ return null;
+ }
+
+ if (enabledOperations.Count == 1)
+ {
+ return enabledOperations[0];
+ }
+ var idx = IntChoices.Next() % enabledOperations.Count;
+ return enabledOperations[idx];
+ }
+
+ public RandomScheduleGenerator Mutate()
+ {
+ return new RandomScheduleMutator().Mutate(this);
+ }
+
+ public RandomScheduleGenerator Copy()
+ {
+ return new RandomScheduleGenerator(Random, IntChoices);
+ }
+
+ public void PrepareForNextInput()
+ {
+ }
+
+ public RandomScheduleGenerator New()
+ {
+ return new RandomScheduleGenerator(Random, null);
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IFeedbackGuidedStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IFeedbackGuidedStrategy.cs
new file mode 100644
index 0000000000..84f3eec289
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IFeedbackGuidedStrategy.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+using PChecker.Feedback;
+
+namespace PChecker.SystematicTesting.Strategies.Feedback;
+
+internal interface IFeedbackGuidedStrategy: ISchedulingStrategy
+{
+ public void ObserveRunningResults(EventPatternObserver patternObserver, ControlledRuntime runtime);
+ public int TotalSavedInputs();
+ public void DumpStats(TextWriter writer);
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/MaxHeap.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/MaxHeap.cs
new file mode 100644
index 0000000000..b04f504de4
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/MaxHeap.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+
+namespace PChecker.SystematicTesting.Strategies.Feedback;
+
+public class MaxHeap
+{
+ public readonly List Elements = new();
+ private IComparer _comparer;
+
+ public MaxHeap(IComparer cmp)
+ {
+ _comparer = cmp;
+ }
+
+ private int GetLeftChildIndex(int elementIndex) => 2 * elementIndex + 1;
+ private int GetRightChildIndex(int elementIndex) => 2 * elementIndex + 2;
+ private int GetParentIndex(int elementIndex) => (elementIndex - 1) / 2;
+
+ private bool HasLeftChild(int elementIndex) => GetLeftChildIndex(elementIndex) < Elements.Count;
+ private bool HasRightChild(int elementIndex) => GetRightChildIndex(elementIndex) < Elements.Count;
+ private bool IsRoot(int elementIndex) => elementIndex == 0;
+
+ private TValue GetLeftChild(int elementIndex) => Elements[GetLeftChildIndex(elementIndex)];
+ private TValue GetRightChild(int elementIndex) => Elements[GetRightChildIndex(elementIndex)];
+ private TValue GetParent(int elementIndex) => Elements[GetParentIndex(elementIndex)];
+
+ private void Swap(int firstIndex, int secondIndex)
+ {
+ (Elements[firstIndex], Elements[secondIndex]) = (Elements[secondIndex], Elements[firstIndex]);
+ }
+
+ public TValue Peek()
+ {
+ return Elements[0];
+ }
+
+ public TValue Pop()
+ {
+ var result = Elements[0];
+ Elements[0] = Elements[Elements.Count - 1];
+ Elements.RemoveAt(Elements.Count - 1);
+
+ ReCalculateDown();
+
+ return result;
+ }
+
+ public void Add(TValue element)
+ {
+ Elements.Add(element);
+ ReCalculateUp();
+ }
+
+ private void ReCalculateDown()
+ {
+ int index = 0;
+ while (HasLeftChild(index))
+ {
+ var biggerIndex = GetLeftChildIndex(index);
+ if (HasRightChild(index) &&
+ _comparer.Compare(GetRightChild(index), GetLeftChild(index)) > 0)
+ {
+ biggerIndex = GetRightChildIndex(index);
+ }
+
+ if (_comparer.Compare(Elements[biggerIndex], Elements[index]) < 0)
+ {
+ break;
+ }
+
+ Swap(biggerIndex, index);
+ index = biggerIndex;
+ }
+ }
+
+ private void ReCalculateUp()
+ {
+ var index = Elements.Count - 1;
+ while (!IsRoot(index) && _comparer.Compare(Elements[index], GetParent(index)) > 0)
+ {
+ var parentIndex = GetParentIndex(index);
+ Swap(parentIndex, index);
+ index = parentIndex;
+ }
+ }
+
+}
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/TwoStageFeedbackStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/TwoStageFeedbackStrategy.cs
new file mode 100644
index 0000000000..3fdc1485ca
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/TwoStageFeedbackStrategy.cs
@@ -0,0 +1,36 @@
+using PChecker.Generator;
+using PChecker.Feedback;
+
+namespace PChecker.SystematicTesting.Strategies.Feedback;
+
+
+internal class TwoStageFeedbackStrategy : FeedbackGuidedStrategy
+ where TInput: IInputGenerator
+ where TSchedule: IScheduleGenerator
+{
+
+ private int _numScheduleMutationWithoutNewSaved = 0;
+
+ // This number should be less than `FeedbackGuidedStrategy._maxMutationsWithoutNewSaved`
+ private readonly int _maxScheduleMutationsWithoutNewSaved = 25;
+ public TwoStageFeedbackStrategy(CheckerConfiguration checkerConfiguration, TInput input, TSchedule schedule) : base(checkerConfiguration, input, schedule)
+ {
+ }
+
+ protected override StrategyGenerator MutateGenerator(StrategyGenerator prev)
+ {
+ if (_numScheduleMutationWithoutNewSaved > _maxScheduleMutationsWithoutNewSaved)
+ {
+ _numScheduleMutationWithoutNewSaved = 0;
+ return new StrategyGenerator(
+ Generator.InputGenerator.Mutate(),
+ // do not mutate schedule to save time?
+ Generator.ScheduleGenerator.Copy()
+ );
+ }
+ return new StrategyGenerator(
+ Generator.InputGenerator.Copy(),
+ Generator.ScheduleGenerator.Mutate()
+ );
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/Chain.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/Chain.cs
new file mode 100644
index 0000000000..add66d209d
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/Chain.cs
@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+
+namespace PChecker.SystematicTesting.Strategies.Probabilistic.pctcp;
+
+public class Chain
+{
+ public List Ops = new();
+ public int CurrentIndex = 0;
+
+ public OperationWithId CurrentOp() {
+ if (CurrentIndex < Ops.Count)
+ {
+ return Ops[CurrentIndex];
+ }
+ return null;
+ }
+
+ public List SliceSuccessors(int op)
+ {
+ var index = Ops.FindIndex(it => it.Id == op);
+ return Ops.GetRange(index, Ops.Count - index - 1);
+ }
+
+ public void AppendAll(List ops)
+ {
+ Ops.AddRange(ops);
+ }
+
+ public void RemoveAll(List ops)
+ {
+ Ops.RemoveAll(it => ops.Contains(it));
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/OperationWithId.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/OperationWithId.cs
new file mode 100644
index 0000000000..343f83979c
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/OperationWithId.cs
@@ -0,0 +1,3 @@
+namespace PChecker.SystematicTesting.Strategies.Probabilistic.pctcp;
+
+public record OperationWithId(string Sender, string Receiver, int Loc, int Id);
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/VectorClockWrapper.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/VectorClockWrapper.cs
new file mode 100644
index 0000000000..46982c4d69
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/VectorClockWrapper.cs
@@ -0,0 +1,8 @@
+using PChecker.Actors.Logging;
+
+namespace PChecker.SystematicTesting.Strategies.Probabilistic.pctcp;
+
+public class VectorClockWrapper
+{
+ public VectorClockGenerator CurrentVC;
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCPScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCPScheduler.cs
new file mode 100644
index 0000000000..dd6c0fd540
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCPScheduler.cs
@@ -0,0 +1,366 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using PChecker.Actors.Logging;
+using PChecker.IO.Debugging;
+using PChecker.SystematicTesting.Operations;
+using PChecker.SystematicTesting.Strategies.Probabilistic.pctcp;
+
+namespace PChecker.SystematicTesting.Strategies.Probabilistic;
+
+
+internal class PCTCPScheduler: PrioritizedScheduler
+{
+ public readonly PriorizationProvider Provider;
+
+ private int ScheduledSteps;
+ public readonly int MaxPrioritySwitchPoints;
+ public int ScheduleLength;
+ private int _nextPriorityChangePoint;
+ private int _numSwitchPointsLeft;
+ private int _nextOperationId = 0;
+ private Dictionary _chainedOperations = new();
+ private List _chains = new();
+ private Dictionary> _vectorClockMap = new();
+ private Dictionary> _predMap = new();
+ private Dictionary _operationMap = new();
+ private Dictionary _chainMap = new();
+ private Dictionary _nextOperationMap = new();
+ internal VectorClockWrapper VcWrapper;
+
+ public PCTCPScheduler(int maxPrioritySwitchPoints, int scheduleLength, PriorizationProvider provider,
+ VectorClockWrapper vcWrapper)
+ {
+ Provider = provider;
+ ScheduledSteps = 0;
+ ScheduleLength = scheduleLength;
+ MaxPrioritySwitchPoints = maxPrioritySwitchPoints;
+ _numSwitchPointsLeft = maxPrioritySwitchPoints;
+ VcWrapper = vcWrapper;
+
+ double switchPointProbability = 0.1;
+ if (ScheduleLength != 0)
+ {
+ switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
+ }
+ _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice());
+ }
+
+ public virtual bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
+ {
+ next = null;
+ var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
+ if (enabledOperations.Count == 0)
+ {
+ if (_nextPriorityChangePoint == ScheduledSteps)
+ {
+ MovePriorityChangePointForward();
+ }
+ return false;
+ }
+
+ var highestEnabledOp = GetPrioritizedOperation(enabledOperations, current);
+ if (next is null)
+ {
+ next = highestEnabledOp;
+ }
+
+ ScheduledSteps++;
+ return true;
+ }
+
+ private void OnNewOperation(AsyncOperation operation)
+ {
+ Dictionary vc;
+ if (VcWrapper.CurrentVC.ContextVcMap.ContainsKey(operation.Name))
+ {
+ vc = VcWrapper.CurrentVC
+ .ContextVcMap[operation.Name]
+ .ToDictionary(entry => entry.Key, entry => entry.Value);
+ }
+ else
+ {
+ vc = new();
+ }
+
+ OperationWithId op;
+ if (operation.Type == AsyncOperationType.Send)
+ {
+ op = new OperationWithId(operation.Name, operation.LastSentReceiver, operation
+ .LastEvent!.Loc, _nextOperationId++);
+ }
+ else
+ {
+ op = new OperationWithId(operation.Name, "", 0, _nextOperationId++);
+ }
+
+ _vectorClockMap[op.Id] = vc;
+ _chainedOperations[operation.Name] = op.Id;
+ _operationMap[op.Id] = op;
+ _predMap[op.Id] = new();
+
+ for (int i = 0; i < op.Id - 1; i++)
+ {
+ if (IsLT(_vectorClockMap[i], _vectorClockMap[op.Id]))
+ {
+ _predMap[op.Id].Add(i);
+ }
+ }
+
+ if (!PlaceInChains(op))
+ {
+ Chain newChain = new();
+ newChain.Ops.Add(op);
+ _chainMap[op.Id] = newChain;
+ if (_chains.Count == 0)
+ {
+ _chains.Add(newChain);
+ }
+ else
+ {
+ var index = Provider.AssignPriority(_chains.Count);
+ _chains.Insert(index, newChain);
+ }
+ }
+ }
+
+ private bool PlaceInChains(OperationWithId op)
+ {
+ // var currentQ = _chains.
+ for (int i = 0; i < _chains.Count; i++)
+ {
+ var chain = _chains[i];
+ if (chain.Ops.Count > 0)
+ {
+ var tail = chain.Ops.Last();
+ if (IsLT(_vectorClockMap[tail.Id], _vectorClockMap[op.Id]))
+ {
+ chain.Ops.Add(op);
+ _nextOperationMap[tail.Id] = op.Id;
+ _chainMap[op.Id] = chain;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ bool IsLT(Dictionary vc1, Dictionary vc2)
+ {
+ bool hasLess = false;
+ foreach (var key in vc1.Keys.Union(vc2.Keys))
+ {
+ var op1 = vc1.GetValueOrDefault(key, 0);
+ var op2 = vc2.GetValueOrDefault(key, 0);
+ if (op1 >= op2)
+ {
+ return false;
+ }
+
+ if (op1 < op2)
+ {
+ hasLess = true;
+ }
+ }
+ return hasLess;
+ }
+
+ private void MovePriorityChangePointForward()
+ {
+ _nextPriorityChangePoint += 1;
+ Debug.WriteLine(" Moving priority change to '{0}'.", _nextPriorityChangePoint);
+ }
+ private OperationWithId GetHighestPriorityEnabledOperation(IEnumerable choices)
+ {
+ OperationWithId highestPriorityOp = null;
+ int currentPriority = Int32.MaxValue;
+ int currentChainIndex = Int32.MaxValue;
+ foreach (var op in choices)
+ {
+ var id = _chainedOperations[op.Name];
+ var chain = _chainMap[id];
+ var priotiy = _chains.IndexOf(chain);
+ if (priotiy < currentPriority)
+ {
+ highestPriorityOp = _operationMap[id];
+ currentPriority = priotiy;
+ currentChainIndex = chain.Ops.IndexOf(highestPriorityOp);
+ }
+
+ if (priotiy == currentPriority)
+ {
+ var index = chain.Ops.IndexOf(_operationMap[id]);
+ if (index < currentChainIndex)
+ {
+ highestPriorityOp = _operationMap[id];
+ currentChainIndex = index;
+ }
+ }
+ }
+ return highestPriorityOp;
+ }
+
+ private (int, int, Dictionary) FindReducingSequence()
+ {
+ var queue = new Queue();
+ foreach (var chain in _chains)
+ {
+ if (chain.Ops.Count > 0)
+ {
+ queue.Enqueue(chain.Ops.First().Id);
+ }
+ }
+
+ var pairs = new Dictionary();
+
+ while (queue.Count > 0)
+ {
+ var opId = queue.Dequeue();
+ foreach (var chain in _chains)
+ {
+ if (chain == _chainMap[opId]) continue;
+ if (chain.Ops.Count <= 0) continue;
+ if (IsLT(_vectorClockMap[chain.Ops.Last().Id], _vectorClockMap[opId]))
+ {
+ return (chain.Ops.Last().Id, opId, pairs);
+ }
+ }
+ var temp = _predMap[opId].Where(it => _nextOperationMap.ContainsKey(it)
+ && !pairs.ContainsKey(_nextOperationMap[it]))
+ .ToList();
+ foreach (var predOp in temp)
+ {
+ queue.Enqueue(_nextOperationMap[predOp]);
+ pairs[_nextOperationMap[predOp]] = (predOp, opId);
+ }
+
+ }
+ return (-1, -1, pairs);
+ }
+
+ private void ReduceChains()
+ {
+ var (pred, op, pairs) = FindReducingSequence();
+
+ if (pred == -1) return;
+
+ do
+ {
+ var predChain = _chainMap[pred];
+ var opChain = _chainMap[op];
+ var ids = opChain.SliceSuccessors(op);
+ predChain.Ops.AddRange(ids);
+ opChain.Ops.RemoveAll(it => ids.Contains(it));
+ foreach (var id in ids)
+ {
+ _chainMap[id.Id] = predChain;
+ }
+
+ _nextOperationMap[pred] = op;
+
+ if (opChain.Ops.Count > 0)
+ {
+ _nextOperationMap.Remove(opChain.Ops.Last().Id);
+ }
+
+ if (!pairs.ContainsKey(op))
+ {
+ _chains.Remove(opChain);
+ break;
+ }
+ pred = pairs[op].Item1;
+ op = pairs[op].Item2;
+ } while (true);
+
+ }
+
+ ///
+ /// Returns the prioritized operation.
+ ///
+ private AsyncOperation GetPrioritizedOperation(List ops, AsyncOperation current)
+ {
+ bool newOpAdded = false;
+ foreach (var op in ops.Where(op => !_chainedOperations.ContainsKey(op.Name)))
+ {
+ OnNewOperation(op);
+ newOpAdded = true;
+ }
+
+ if (newOpAdded)
+ {
+ ReduceChains();
+ }
+
+
+ var prioritizedSchedulable = GetHighestPriorityEnabledOperation(ops);
+ if (_nextPriorityChangePoint == ScheduledSteps)
+ {
+ if (ops.Count == 1)
+ {
+ MovePriorityChangePointForward();
+ }
+ else
+ {
+ var chain = _chainMap[prioritizedSchedulable.Id];
+ _chains.Remove(chain);
+ _chains.Add(chain);
+
+ _numSwitchPointsLeft -= 1;
+ // Update the next priority change point.
+ if (_numSwitchPointsLeft > 0)
+ {
+ double switchPointProbability = 0.1;
+ if (ScheduleLength != 0)
+ {
+ switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
+ }
+ _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice()) + ScheduledSteps;
+ }
+ }
+ }
+
+ AsyncOperation scheduledOperation = null;
+ if (prioritizedSchedulable != null)
+ {
+ scheduledOperation = ops.First(it => it.Name == prioritizedSchedulable.Sender);
+ _chainedOperations.Remove(scheduledOperation.Name);
+ Debug.WriteLine(" scheduled operation: " + scheduledOperation.Name);
+ }
+
+ return scheduledOperation;
+ }
+
+ public void Reset()
+ {
+ ScheduleLength = 0;
+ ScheduledSteps = 0;
+ _chainedOperations.Clear();
+ _vectorClockMap.Clear();
+ _chains.Clear();
+ _nextOperationMap.Clear();
+ _nextOperationId = 0;
+ }
+
+ ///
+ public virtual bool PrepareForNextIteration()
+ {
+ ScheduleLength = Math.Max(ScheduleLength, ScheduledSteps);
+ ScheduledSteps = 0;
+ _nextOperationId = 0;
+ _numSwitchPointsLeft = MaxPrioritySwitchPoints;
+ _chainedOperations.Clear();
+ _vectorClockMap.Clear();
+ _chains.Clear();
+ _nextOperationMap.Clear();
+ _chainMap.Clear();
+
+ double switchPointProbability = 0.1;
+ if (ScheduleLength != 0)
+ {
+ switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
+ }
+ _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice());
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTScheduler.cs
new file mode 100644
index 0000000000..c0263c68e1
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTScheduler.cs
@@ -0,0 +1,189 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using PChecker.SystematicTesting.Operations;
+using Debug = PChecker.IO.Debugging.Debug;
+
+namespace PChecker.SystematicTesting.Strategies.Probabilistic;
+
+internal class PCTScheduler: PrioritizedScheduler
+{
+ public readonly PriorizationProvider Provider;
+
+ ///
+ /// The number of scheduled steps.
+ ///
+ private int ScheduledSteps;
+
+ ///
+ /// Max number of priority switch points.
+ ///
+ public readonly int MaxPrioritySwitchPoints;
+
+ ///
+ /// Approximate length of the schedule across all iterations.
+ ///
+ public int ScheduleLength;
+
+ ///
+ /// List of prioritized operations.
+ ///
+ private readonly List PrioritizedOperations;
+
+ private int _nextPriorityChangePoint;
+ private int _numSwitchPointsLeft;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PCTScheduler(int maxPrioritySwitchPoints, int scheduleLength, PriorizationProvider provider)
+ {
+ Provider = provider;
+ ScheduledSteps = 0;
+ ScheduleLength = scheduleLength;
+ MaxPrioritySwitchPoints = maxPrioritySwitchPoints;
+ PrioritizedOperations = new List();
+ _numSwitchPointsLeft = maxPrioritySwitchPoints;
+
+ double switchPointProbability = 0.1;
+ if (ScheduleLength != 0)
+ {
+ switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
+ }
+ _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice());
+ }
+
+ public virtual bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
+ {
+ ScheduledSteps++;
+ next = null;
+ var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
+ if (enabledOperations.Count == 0)
+ {
+ if (_nextPriorityChangePoint == ScheduledSteps)
+ {
+ MovePriorityChangePointForward();
+ }
+ return false;
+ }
+
+ var highestEnabledOp = GetPrioritizedOperation(enabledOperations, current);
+ if (next is null)
+ {
+ next = highestEnabledOp;
+ }
+
+ return true;
+ }
+
+ private void MovePriorityChangePointForward()
+ {
+ _nextPriorityChangePoint += 1;
+ Debug.WriteLine(" Moving priority change to '{0}'.", _nextPriorityChangePoint);
+ }
+ private AsyncOperation GetHighestPriorityEnabledOperation(IEnumerable choices)
+ {
+ AsyncOperation prioritizedOp = null;
+ foreach (var entity in PrioritizedOperations)
+ {
+ if (choices.Any(m => m == entity))
+ {
+ prioritizedOp = entity;
+ break;
+ }
+ }
+
+ return prioritizedOp;
+ }
+
+
+ ///
+ /// Returns the prioritized operation.
+ ///
+ private AsyncOperation GetPrioritizedOperation(List ops, AsyncOperation current)
+ {
+ if (PrioritizedOperations.Count == 0)
+ {
+ PrioritizedOperations.Add(current);
+ }
+
+ foreach (var op in ops.Where(op => !PrioritizedOperations.Contains(op)))
+ {
+ var mIndex = Provider.AssignPriority(PrioritizedOperations.Count);
+ PrioritizedOperations.Insert(mIndex, op);
+ Debug.WriteLine(" Detected new operation '{0}' at index '{1}'.", op.Id, mIndex);
+ }
+
+
+ var prioritizedSchedulable = GetHighestPriorityEnabledOperation(ops);
+ if (_nextPriorityChangePoint == ScheduledSteps)
+ {
+ if (ops.Count == 1)
+ {
+ MovePriorityChangePointForward();
+ }
+ else
+ {
+ PrioritizedOperations.Remove(prioritizedSchedulable);
+ PrioritizedOperations.Add(prioritizedSchedulable);
+ Debug.WriteLine(" Operation '{0}' changes to lowest priority.", prioritizedSchedulable);
+
+ _numSwitchPointsLeft -= 1;
+ // Update the next priority change point.
+ if (_numSwitchPointsLeft > 0)
+ {
+ double switchPointProbability = 0.1;
+ if (ScheduleLength != 0)
+ {
+ switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
+ }
+ _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice()) + ScheduledSteps;
+ }
+
+ }
+ }
+
+ if (Debug.IsEnabled)
+ {
+ Debug.WriteLine(" Prioritized schedulable '{0}'.", prioritizedSchedulable);
+ Debug.Write(" Priority list: ");
+ for (var idx = 0; idx < PrioritizedOperations.Count; idx++)
+ {
+ if (idx < PrioritizedOperations.Count - 1)
+ {
+ Debug.Write("'{0}', ", PrioritizedOperations[idx]);
+ }
+ else
+ {
+ Debug.WriteLine("'{0}'.", PrioritizedOperations[idx]);
+ }
+ }
+ }
+
+ return ops.First(op => op.Equals(prioritizedSchedulable));
+ }
+
+ public void Reset()
+ {
+ ScheduleLength = 0;
+ ScheduledSteps = 0;
+ PrioritizedOperations.Clear();
+ }
+
+ ///
+ public virtual bool PrepareForNextIteration()
+ {
+ ScheduleLength = Math.Max(ScheduleLength, ScheduledSteps);
+ ScheduledSteps = 0;
+ _numSwitchPointsLeft = MaxPrioritySwitchPoints;
+
+ PrioritizedOperations.Clear();
+ double switchPointProbability = 0.1;
+ if (ScheduleLength != 0)
+ {
+ switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
+ }
+ _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice());
+ return true;
+ }
+}
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs
new file mode 100644
index 0000000000..589ae13099
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs
@@ -0,0 +1,156 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using PChecker.Feedback;
+using PChecker.IO.Debugging;
+using PChecker.SystematicTesting.Operations;
+
+namespace PChecker.SystematicTesting.Strategies.Probabilistic;
+
+internal class POSScheduler: PrioritizedScheduler
+{
+ internal readonly PriorizationProvider Provider;
+
+ ///
+ /// List of prioritized operations.
+ ///
+ private readonly List PrioritizedOperations;
+
+ public ConflictOpMonitor? ConflictOpMonitor;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public POSScheduler(PriorizationProvider provider, ConflictOpMonitor? monitor)
+ {
+ Provider = provider;
+ PrioritizedOperations = new List();
+ ConflictOpMonitor = monitor;
+ }
+
+ public bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
+ {
+ next = null;
+ var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
+ if (enabledOperations.Count == 0)
+ {
+ return false;
+ }
+
+ var highestEnabledOp = GetPrioritizedOperation(enabledOperations, current);
+ next = highestEnabledOp;
+ if (next.Type == AsyncOperationType.Send)
+ {
+ ResetPriorities(next, enabledOperations);
+ }
+ return true;
+ }
+
+ void ResetPriorities(AsyncOperation next, IEnumerable ops)
+ {
+ foreach (var op in ops)
+ {
+ if (op.Type == AsyncOperationType.Send)
+ {
+ if (op.LastSentReceiver == next.LastSentReceiver)
+ {
+ PrioritizedOperations.Remove(op);
+ }
+ }
+ }
+ PrioritizedOperations.Remove(next);
+ }
+
+ private AsyncOperation GetHighestPriorityEnabledOperation(IEnumerable choices)
+ {
+ AsyncOperation prioritizedOp = null;
+ foreach (var entity in PrioritizedOperations)
+ {
+ if (choices.Any(m => m == entity))
+ {
+ prioritizedOp = entity;
+ break;
+ }
+ }
+
+ return prioritizedOp;
+ }
+
+ ///
+ /// Returns the prioritized operation.
+ ///
+ private AsyncOperation GetPrioritizedOperation(List ops, AsyncOperation current)
+ {
+ if (PrioritizedOperations.Count == 0)
+ {
+ PrioritizedOperations.Add(current);
+ }
+
+ foreach (var op in ops.Where(op => !PrioritizedOperations.Contains(op)))
+ {
+ var mIndex = Provider.AssignPriority(PrioritizedOperations.Count);
+ PrioritizedOperations.Insert(mIndex, op);
+ Debug.WriteLine(" Detected new operation '{0}' at index '{1}'.", op.Id, mIndex);
+ }
+
+ if (FindNonRacingOperation(ops, out var next))
+ {
+ return next;
+ }
+
+ var prioritizedSchedulable = GetHighestPriorityEnabledOperation(ops);
+
+ if (Debug.IsEnabled)
+ {
+ Debug.WriteLine(" Prioritized schedulable '{0}'.", prioritizedSchedulable);
+ Debug.Write(" Priority list: ");
+ for (var idx = 0; idx < PrioritizedOperations.Count; idx++)
+ {
+ if (idx < PrioritizedOperations.Count - 1)
+ {
+ Debug.Write("'{0}', ", PrioritizedOperations[idx]);
+ }
+ else
+ {
+ Debug.WriteLine("'{0}'.", PrioritizedOperations[idx]);
+ }
+ }
+ }
+
+ return ops.First(op => op.Equals(prioritizedSchedulable));
+ }
+
+ private bool FindNonRacingOperation(IEnumerable ops, out AsyncOperation next)
+ {
+ var nonRacingOps = ops.Where(op => op.Type != AsyncOperationType.Send);
+ if (!nonRacingOps.Any() && ConflictOpMonitor != null)
+ {
+ nonRacingOps = ops.Where(op => !ConflictOpMonitor.IsConflictingOp(op));
+ }
+
+ if (!nonRacingOps.Any())
+ {
+ next = null;
+ return false;
+ }
+ if (!nonRacingOps.Skip(1).Any())
+ {
+ next = nonRacingOps.First();
+ return true;
+ }
+ next = GetHighestPriorityEnabledOperation(nonRacingOps);
+ return true;
+ }
+
+ public void Reset()
+ {
+ PrioritizedOperations.Clear();
+ }
+
+ ///
+ public virtual bool PrepareForNextIteration()
+ {
+ PrioritizedOperations.Clear();
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSStrategy.cs
new file mode 100644
index 0000000000..6968e1c6ee
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSStrategy.cs
@@ -0,0 +1,48 @@
+using PChecker.Feedback;
+using PChecker.Random;
+using PChecker.SystematicTesting.Operations;
+
+namespace PChecker.SystematicTesting.Strategies.Probabilistic;
+
+internal class POSStrategy: POSScheduler, ISchedulingStrategy
+{
+ ///
+ /// Random value generator.
+ ///
+ private readonly IRandomValueGenerator RandomValueGenerator;
+
+ public POSStrategy(int maxSteps, ConflictOpMonitor? monitor, IRandomValueGenerator random)
+ : base(new RandomPriorizationProvider(random), monitor)
+ {
+ }
+
+ public bool GetNextBooleanChoice(AsyncOperation current, int maxValue, out bool next)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public bool GetNextIntegerChoice(AsyncOperation current, int maxValue, out int next)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public int GetScheduledSteps()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public bool HasReachedMaxSchedulingSteps()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public bool IsFair()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public string GetDescription()
+ {
+ throw new System.NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedScheduler.cs
new file mode 100644
index 0000000000..7c38a0629c
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedScheduler.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+using PChecker.SystematicTesting.Operations;
+
+namespace PChecker.SystematicTesting.Strategies.Probabilistic;
+
+internal interface PrioritizedScheduler
+{
+ public bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next);
+ public void Reset();
+ public bool PrepareForNextIteration();
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedSchedulingStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedSchedulingStrategy.cs
new file mode 100644
index 0000000000..72660d7f97
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedSchedulingStrategy.cs
@@ -0,0 +1,114 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using PChecker.Feedback;
+using PChecker.IO.Debugging;
+using PChecker.Random;
+using PChecker.SystematicTesting.Operations;
+
+namespace PChecker.SystematicTesting.Strategies.Probabilistic
+{
+ ///
+ /// A priority-based probabilistic scheduling strategy.
+ ///
+ ///
+ /// This strategy is described in the following paper:
+ /// https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/asplos277-pct.pdf
+ ///
+ internal class PrioritizedSchedulingStrategy: ISchedulingStrategy
+ {
+
+ ///
+ /// Random value generator.
+ ///
+ private readonly IRandomValueGenerator RandomValueGenerator;
+
+ ///
+ /// The maximum number of steps to schedule.
+ ///
+ private readonly int MaxScheduledSteps;
+
+ private int _scheduledSteps;
+
+ private PrioritizedScheduler _scheduler;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PrioritizedSchedulingStrategy(int maxSteps, IRandomValueGenerator random, PrioritizedScheduler scheduler)
+ {
+ RandomValueGenerator = random;
+ MaxScheduledSteps = maxSteps;
+ _scheduler = scheduler;
+ }
+
+ ///
+ public bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
+ {
+ _scheduledSteps++;
+ return _scheduler.GetNextOperation(current, ops, out next);
+ }
+
+ ///
+ public bool GetNextBooleanChoice(AsyncOperation current, int maxValue, out bool next)
+ {
+ next = false;
+ if (RandomValueGenerator.Next(maxValue) == 0)
+ {
+ next = true;
+ }
+
+ _scheduledSteps++;
+
+ return true;
+ }
+
+ ///
+ public bool GetNextIntegerChoice(AsyncOperation current, int maxValue, out int next)
+ {
+ next = RandomValueGenerator.Next(maxValue);
+ _scheduledSteps++;
+ return true;
+ }
+
+ ///
+ public int GetScheduledSteps() => _scheduledSteps;
+
+ ///
+ public bool HasReachedMaxSchedulingSteps()
+ {
+ if (MaxScheduledSteps == 0)
+ {
+ return false;
+ }
+
+ return _scheduledSteps >= MaxScheduledSteps;
+ }
+
+ ///
+ public bool IsFair() => false;
+
+ ///
+ public string GetDescription()
+ {
+ var text = $"pct[seed '" + RandomValueGenerator.Seed + "']";
+ return text;
+ }
+
+ public bool PrepareForNextIteration() {
+ _scheduledSteps = 0;
+ return _scheduler.PrepareForNextIteration();
+ }
+
+
+ ///
+ public void Reset()
+ {
+ _scheduledSteps = 0;
+ _scheduler.Reset();
+ }
+ }
+}
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationProvider.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationProvider.cs
new file mode 100644
index 0000000000..d4cb446516
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationProvider.cs
@@ -0,0 +1,7 @@
+namespace PChecker.SystematicTesting.Strategies.Probabilistic;
+
+public interface PriorizationProvider
+{
+ public int AssignPriority(int numOps);
+ public double SwitchPointChoice();
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationSchedulingBase.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationSchedulingBase.cs
new file mode 100644
index 0000000000..3894b96fc8
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationSchedulingBase.cs
@@ -0,0 +1,243 @@
+
+
+using System.Collections.Generic;
+using System.Linq;
+using PChecker.Feedback;
+using PChecker.SystematicTesting.Operations;
+using PChecker.Generator.Mutator;
+using PChecker.IO.Debugging;
+using System;
+
+namespace PChecker.SystematicTesting.Strategies.Probabilistic;
+
+internal class PriorizationSchedulingBase
+{
+ public readonly PriorizationProvider Provider;
+
+ ///
+ /// The number of scheduled steps.
+ ///
+ private int ScheduledSteps;
+
+ ///
+ /// Max number of priority switch points.
+ ///
+ public readonly int MaxPrioritySwitchPoints;
+
+ ///
+ /// Approximate length of the schedule across all iterations.
+ ///
+ public int ScheduleLength;
+
+ ///
+ /// List of prioritized operations.
+ ///
+ private readonly List PrioritizedOperations;
+
+ public ConflictOpMonitor? ConflictOpMonitor;
+ private int _nextPriorityChangePoint;
+ private int _numSwitchPointsLeft;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PriorizationSchedulingBase(int maxPrioritySwitchPoints, int scheduleLength, PriorizationProvider provider, ConflictOpMonitor? monitor)
+ {
+ Provider = provider;
+ ScheduledSteps = 0;
+ ScheduleLength = scheduleLength;
+ MaxPrioritySwitchPoints = maxPrioritySwitchPoints;
+ PrioritizedOperations = new List();
+ ConflictOpMonitor = monitor;
+ _numSwitchPointsLeft = maxPrioritySwitchPoints;
+
+ double switchPointProbability = 0.1;
+ if (ScheduleLength != 0)
+ {
+ switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
+ }
+ _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice());
+ }
+
+ public virtual bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
+ {
+ ScheduledSteps++;
+ next = null;
+ var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
+ if (enabledOperations.Count == 0)
+ {
+ if (ConflictOpMonitor == null && _nextPriorityChangePoint == ScheduledSteps)
+ {
+ MovePriorityChangePointForward();
+ }
+ return false;
+ }
+
+ var highestEnabledOp = GetPrioritizedOperation(enabledOperations, current);
+ if (next is null)
+ {
+ next = highestEnabledOp;
+ }
+ if (ConflictOpMonitor != null)
+ {
+ ResetPriorities(next, enabledOperations);
+ }
+
+ return true;
+ }
+
+ public void ResetPriorities(AsyncOperation next, IEnumerable ops)
+ {
+ foreach (var op in ops)
+ {
+ if (op != next && ConflictOpMonitor.IsRacing(next, op))
+ {
+ PrioritizedOperations.Remove(op);
+ }
+ }
+ PrioritizedOperations.Remove(next);
+ }
+
+ private void MovePriorityChangePointForward()
+ {
+ _nextPriorityChangePoint += 1;
+ Debug.WriteLine(" Moving priority change to '{0}'.", _nextPriorityChangePoint);
+ }
+ private AsyncOperation GetHighestPriorityEnabledOperation(IEnumerable choices)
+ {
+ AsyncOperation prioritizedOp = null;
+ foreach (var entity in PrioritizedOperations)
+ {
+ if (choices.Any(m => m == entity))
+ {
+ prioritizedOp = entity;
+ break;
+ }
+ }
+
+ return prioritizedOp;
+ }
+
+
+
+ ///
+ /// Returns the prioritized operation.
+ ///
+ private AsyncOperation GetPrioritizedOperation(List ops, AsyncOperation current)
+ {
+ if (PrioritizedOperations.Count == 0)
+ {
+ PrioritizedOperations.Add(current);
+ }
+
+ foreach (var op in ops.Where(op => !PrioritizedOperations.Contains(op)))
+ {
+ var mIndex = Provider.AssignPriority(PrioritizedOperations.Count);
+ PrioritizedOperations.Insert(mIndex, op);
+ Debug.WriteLine(" Detected new operation '{0}' at index '{1}'.", op.Id, mIndex);
+ }
+
+ if (ConflictOpMonitor != null && FindNonRacingOperation(ops, out var next))
+ {
+ return next;
+ }
+
+ var prioritizedSchedulable = GetHighestPriorityEnabledOperation(ops);
+ if (ConflictOpMonitor == null && _nextPriorityChangePoint == ScheduledSteps)
+ {
+ if (ops.Count == 1)
+ {
+ MovePriorityChangePointForward();
+ }
+ else
+ {
+ PrioritizedOperations.Remove(prioritizedSchedulable);
+ PrioritizedOperations.Add(prioritizedSchedulable);
+ Debug.WriteLine(" Operation '{0}' changes to lowest priority.", prioritizedSchedulable);
+
+ _numSwitchPointsLeft -= 1;
+ // Update the next priority change point.
+ if (_numSwitchPointsLeft > 0)
+ {
+ double switchPointProbability = 0.1;
+ if (ScheduleLength != 0)
+ {
+ switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
+ }
+ _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice()) + ScheduledSteps;
+ }
+
+ }
+ }
+
+ if (Debug.IsEnabled)
+ {
+ Debug.WriteLine(" Prioritized schedulable '{0}'.", prioritizedSchedulable);
+ Debug.Write(" Priority list: ");
+ for (var idx = 0; idx < PrioritizedOperations.Count; idx++)
+ {
+ if (idx < PrioritizedOperations.Count - 1)
+ {
+ Debug.Write("'{0}', ", PrioritizedOperations[idx]);
+ }
+ else
+ {
+ Debug.WriteLine("'{0}'.", PrioritizedOperations[idx]);
+ }
+ }
+ }
+
+ return ops.First(op => op.Equals(prioritizedSchedulable));
+ }
+
+ private bool FindNonRacingOperation(IEnumerable ops, out AsyncOperation next)
+ {
+ var nonRacingOps = ops.Where(op => op.Type != AsyncOperationType.Send);
+ if (!nonRacingOps.Any())
+ {
+ var sendOps = ops.Where(op => op.Type == AsyncOperationType.Send);
+ nonRacingOps = ops.Where(op => !ConflictOpMonitor.IsConflictingOp(op));
+ }
+
+ if (!nonRacingOps.Any())
+ {
+ next = null;
+ return false;
+ }
+ else if (!nonRacingOps.Skip(1).Any())
+ {
+ next = nonRacingOps.First();
+ return true;
+ }
+ else
+ {
+ next = GetHighestPriorityEnabledOperation(nonRacingOps);
+ return true;
+ }
+
+ }
+
+ public void Reset()
+ {
+ ScheduleLength = 0;
+ ScheduledSteps = 0;
+ PrioritizedOperations.Clear();
+ }
+
+ ///
+ public virtual bool PrepareForNextIteration()
+ {
+ ScheduleLength = Math.Max(ScheduleLength, ScheduledSteps);
+ ScheduledSteps = 0;
+ _numSwitchPointsLeft = MaxPrioritySwitchPoints;
+
+ PrioritizedOperations.Clear();
+ double switchPointProbability = 0.1;
+ if (ScheduleLength != 0)
+ {
+ switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
+ }
+ _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice());
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
index ba90bcf613..4b23127301 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
@@ -3,17 +3,20 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
+using PChecker.Feedback;
using System.Text;
using PChecker.Random;
using PChecker.SystematicTesting.Operations;
+using PChecker.SystematicTesting.Strategies.Feedback;
namespace PChecker.SystematicTesting.Strategies.Probabilistic
{
///
/// A probabilistic scheduling strategy that uses Q-learning.
///
- internal class QLearningStrategy : RandomStrategy
+ internal class QLearningStrategy : RandomStrategy, IFeedbackGuidedStrategy
{
///
/// Map from program states to a map from next operations to their quality values.
@@ -78,11 +81,13 @@ internal class QLearningStrategy : RandomStrategy
///
private int Epochs;
+ private bool _diversityFeedback;
+
///
/// Initializes a new instance of the class.
/// It uses the specified random number generator.
///
- public QLearningStrategy(int maxSteps, IRandomValueGenerator random)
+ public QLearningStrategy(int maxSteps, IRandomValueGenerator random, bool diversityFeedback)
: base(maxSteps, random)
{
this.OperationQTable = new Dictionary>();
@@ -97,6 +102,7 @@ public QLearningStrategy(int maxSteps, IRandomValueGenerator random)
this.FailureInjectionReward = -1000;
this.BasicActionReward = -1;
this.Epochs = 0;
+ _diversityFeedback = diversityFeedback;
}
///
@@ -148,7 +154,6 @@ public override bool GetNextIntegerChoice(AsyncOperation current, int maxValue,
///
public override bool PrepareForNextIteration()
{
- this.LearnQValues();
this.ExecutionPath.Clear();
this.PreviousOperation = 0;
this.Epochs++;
@@ -358,18 +363,69 @@ private void InitializeIntegerChoiceQValues(int state, int maxValue)
}
}
- ///
- /// Learn Q values using data from the current execution.
- ///
- private void LearnQValues()
+ private readonly HashSet _visitedTimelines = new();
+ private readonly List> _savedTimelines = new();
+ private int ComputeDiversity(int timeline, List hash)
{
- var pathBuilder = new StringBuilder();
+ if (!_visitedTimelines.Add(timeline))
+ {
+ return 0;
+ }
+
+ if (_savedTimelines.Count == 0)
+ {
+ return 20;
+ }
+
+ var maxSim = int.MinValue;
+ foreach (var record in _savedTimelines)
+ {
+ var similarity = 0;
+ for (int i = 0; i < hash.Count; i++)
+ {
+ if (hash[i] == record[i])
+ {
+ similarity += 1;
+ }
+ }
+
+ maxSim = Math.Max(maxSim, similarity);
+ }
+
+
+ return (hash.Count - maxSim) * 10 + 20;
+ }
+
+ public void ObserveRunningResults(EventPatternObserver patternObserver, ControlledRuntime runtime)
+ {
+ var timelineHash = runtime.TimelineObserver.GetTimelineHash();
+ var timelineMinhash = runtime.TimelineObserver.GetTimelineMinhash();
+
+ int priority = 1;
+
+ if (_diversityFeedback)
+ {
+ int diversityScore = ComputeDiversity(timelineHash, timelineMinhash);
+ if (patternObserver == null)
+ {
+ priority = diversityScore;
+ }
+ else
+ {
+ int coverageResult = patternObserver.ShouldSave();
+ priority = diversityScore / coverageResult;
+ }
+
+ if (priority != 0)
+ {
+ _savedTimelines.Add(timelineMinhash);
+ }
+ priority += 1;
+ }
- int idx = 0;
var node = this.ExecutionPath.First;
while (node != null && node.Next != null)
{
- pathBuilder.Append($"{node.Value.op},");
var (_, _, state) = node.Value;
var (nextOp, nextType, nextState) = node.Next.Value;
@@ -386,8 +442,8 @@ private void LearnQValues()
// Compute the reward. Program states that are visited with higher frequency result into lesser rewards.
var freq = this.TransitionFrequencies[nextState];
- double reward = (nextType == AsyncOperationType.InjectFailure ?
- this.FailureInjectionReward : this.BasicActionReward) * freq;
+ double reward = ((nextType == AsyncOperationType.InjectFailure ?
+ this.FailureInjectionReward : this.BasicActionReward) * freq) / priority;
if (reward > 0)
{
// The reward has underflowed.
@@ -407,8 +463,16 @@ private void LearnQValues()
(this.LearningRate * (reward + (this.Gamma * maxQ)));
node = node.Next;
- idx++;
}
}
+
+ public int TotalSavedInputs()
+ {
+ return 0;
+ }
+
+ public void DumpStats(TextWriter writer)
+ {
+ }
}
}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RFFScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RFFScheduler.cs
new file mode 100644
index 0000000000..11d27c2e26
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RFFScheduler.cs
@@ -0,0 +1,174 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using PChecker.Feedback;
+using PChecker.Random;
+using PChecker.SystematicTesting.Operations;
+using PChecker.SystematicTesting.Strategies.Probabilistic;
+
+internal class ScheduleRecord
+{
+ public int NumVisit {get; set; }
+ public int FuzzLevel {get; set; }
+ public int Priority {get; set;}
+ public AbstractSchedule Schedule;
+
+ public ScheduleRecord(int numVisit, int fuzzLevel, AbstractSchedule schedule) {
+ NumVisit = numVisit;
+ FuzzLevel = fuzzLevel;
+ Schedule = schedule;
+ }
+
+}
+internal class RFFScheduler: PrioritizedScheduler
+{
+ // public List<(AbstractSchedule, )> savedSchedules = new();
+ public Dictionary TraceRecords = new();
+ public int SavedTraces = 0;
+ public int TotalExec = 1;
+ int Skip = 0;
+ int Adj = 1;
+ int SchedNonDets = 0;
+ int parentIndex = 0;
+ int count = 0;
+ internal AbstractSchedule currentSchedule;
+ internal AbstractScheduleObserver observer;
+ internal List savedSchedules = new();
+ public IRandomValueGenerator random;
+ private POSScheduler _posScheduler;
+
+ public RFFScheduler(IRandomValueGenerator random, ConflictOpMonitor monitor, AbstractScheduleObserver observer)
+ {
+ this.observer = observer;
+ this.random = random;
+ currentSchedule = new AbstractSchedule(new HashSet());
+ observer.OnNewAbstractSchedule(currentSchedule);
+ _posScheduler = new POSScheduler(new RandomPriorizationProvider(random), monitor);
+ }
+
+ public bool PrepareForNextIteration()
+ {
+ _posScheduler.PrepareForNextIteration();
+ // We should always check novelty to update global states.
+ if (observer.CheckNoveltyAndUpdate() || observer.CheckAbstractTimelineSatisfied())
+ {
+ int traceHash = observer.GetTraceHash();
+
+ if (!TraceRecords.ContainsKey(traceHash))
+ {
+ TraceRecords[traceHash] = new ScheduleRecord(0, 0, currentSchedule);
+ savedSchedules.Add(TraceRecords[traceHash]);
+ }
+ var record = TraceRecords[traceHash];
+ record.NumVisit += 1;
+
+ int u = TotalExec / (SavedTraces + Adj);
+
+ int factor;
+ if (record.NumVisit <= u)
+ {
+ if (record.FuzzLevel < 31)
+ {
+ record.FuzzLevel += 1;
+ }
+
+ factor = (1 << record.FuzzLevel) / u;
+ Skip = 0;
+ }
+ else
+ {
+ factor = 0;
+ Skip += 1;
+ if (Skip >= SchedNonDets)
+ {
+ Skip = 0;
+ Adj += 1;
+ }
+ }
+ int PerfScore = Math.Min(factor * 1, 50);
+ record.Priority = PerfScore;
+ SavedTraces += 1;
+ }
+ TotalExec += 1;
+
+
+ if (parentIndex == -1 && savedSchedules.Count > 0)
+ {
+ parentIndex = 0;
+ }
+
+ if (parentIndex == -1)
+ {
+ currentSchedule = currentSchedule.Mutate(observer.allVisitedConstraints.Keys.ToList(), random);
+ return true;
+ }
+
+ if (count < savedSchedules[parentIndex].Priority)
+ {
+ currentSchedule = savedSchedules[parentIndex].Schedule.Mutate(observer.allVisitedConstraints.Keys.ToList(), random);
+ count += 1;
+ } else {
+ parentIndex += 1;
+ if (parentIndex >= savedSchedules.Count) {
+ parentIndex = 0;
+ }
+ count = 0;
+ }
+
+ observer.OnNewAbstractSchedule(currentSchedule);
+ return true;
+ }
+
+ public void Reset()
+ {
+ _posScheduler.Reset();
+ }
+
+ public bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
+ {
+ var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
+ if (enabledOperations.Count == 0)
+ {
+ next = null;
+ return false;
+ }
+ if (enabledOperations.Count == 1)
+ {
+ next = enabledOperations[0];
+ return true;
+ }
+
+ var highPrioOps = new List();
+ var normalPrioOps = new List();
+ var lowPrioOps = new List();
+ foreach (var op in enabledOperations)
+ {
+ var avoid = observer.ShouldAvoid(op);
+ var take = observer.ShouldTake(op);
+
+ if (avoid && !take)
+ {
+ lowPrioOps.Add(op);
+ }
+ else if (!avoid && take)
+ {
+ highPrioOps.Add(op);
+ }
+ else
+ {
+ normalPrioOps.Add(op);
+ }
+
+ }
+
+ if (highPrioOps.Count > 0)
+ {
+ return _posScheduler.GetNextOperation(current, highPrioOps, out next);
+ }
+ if (normalPrioOps.Count > 0)
+ {
+ return _posScheduler.GetNextOperation(current, normalPrioOps, out next);
+ }
+ return _posScheduler.GetNextOperation(current, lowPrioOps, out next);
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomPriorizationProvider.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomPriorizationProvider.cs
new file mode 100644
index 0000000000..c757366cd4
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomPriorizationProvider.cs
@@ -0,0 +1,27 @@
+using PChecker.Random;
+
+namespace PChecker.SystematicTesting.Strategies.Probabilistic;
+
+internal class RandomPriorizationProvider: PriorizationProvider
+{
+
+ ///
+ /// Random value generator.
+ ///
+ private readonly IRandomValueGenerator RandomValueGenerator;
+
+ public RandomPriorizationProvider(IRandomValueGenerator generator)
+ {
+ RandomValueGenerator = generator;
+ }
+ public int AssignPriority(int numOps)
+ {
+ return RandomValueGenerator.Next(numOps) + 1;
+ }
+
+ public double SwitchPointChoice()
+ {
+ return RandomValueGenerator.NextDouble();
+ }
+
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomStrategy.cs
index 7bd654b618..eefa755621 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomStrategy.cs
@@ -48,7 +48,11 @@ public virtual bool GetNextOperation(AsyncOperation current, IEnumerable 1) {
+ idx = RandomValueGenerator.Next(enabledOperations.Count);
+ }
+
next = enabledOperations[idx];
ScheduledSteps++;
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Utils.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Utils.cs
new file mode 100644
index 0000000000..d4b3a8a0c1
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Utils.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using PChecker.SystematicTesting.Operations;
+
+namespace PChecker.SystematicTesting.Strategies;
+
+public class Utils
+{
+ internal static List FindHighPriorityOperations(IEnumerable ops, HashSet interestingEvents)
+ {
+ var highOps = ops.Where(it =>
+
+ {
+ if (it.Status == AsyncOperationStatus.Enabled)
+ {
+ if (it is ActorOperation act)
+ {
+ if (act.Type == AsyncOperationType.Send)
+ {
+ if (act.LastEvent != null)
+ {
+ return !interestingEvents.Contains(act.LastEvent.GetType());
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ ).ToList();
+ if (highOps.Count != 0)
+ {
+ return highOps;
+ }
+ return ops.Where(
+ op =>
+ {
+ return op.Status is AsyncOperationStatus.Enabled;
+ }
+ ).ToList();
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs
index 81ee7583a6..24fd70057b 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs
@@ -100,6 +100,19 @@ public class TestReport
[DataMember]
public HashSet InternalErrors { get; internal set; }
+
+ ///
+ /// Set of hashes of timelines discovered by the scheduler.
+ ///
+ [DataMember]
+ public HashSet ExploredTimelines = new();
+
+ ///
+ /// Number of schedulings that satisfies the pattern.
+ ///
+ [DataMember]
+ public Dictionary ValidScheduling = new();
+
///
/// Lock for the test report.
///
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
index 0c7fb0bca2..ed668c03ea 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -17,6 +18,8 @@
using PChecker.Actors;
using PChecker.Actors.Logging;
using PChecker.Coverage;
+using PChecker.Feedback;
+using PChecker.Generator;
using PChecker.IO;
using PChecker.IO.Debugging;
using PChecker.IO.Logging;
@@ -24,10 +27,13 @@
using PChecker.Runtime;
using PChecker.SystematicTesting.Strategies;
using PChecker.SystematicTesting.Strategies.Exhaustive;
+using PChecker.SystematicTesting.Strategies.Feedback;
using PChecker.SystematicTesting.Strategies.Probabilistic;
+using PChecker.SystematicTesting.Strategies.Probabilistic.pctcp;
using PChecker.SystematicTesting.Strategies.Special;
using PChecker.SystematicTesting.Traces;
using PChecker.Utilities;
+using Debug = PChecker.IO.Debugging.Debug;
using Task = PChecker.Tasks.Task;
namespace PChecker.SystematicTesting
@@ -59,6 +65,14 @@ public class TestingEngine
///
internal readonly ISchedulingStrategy Strategy;
+ private EventPatternObserver? _eventPatternObserver;
+
+ private ConflictOpMonitor? _conflictOpMonitor;
+
+ private VectorClockWrapper? _vcWrapper;
+
+ private AbstractScheduleObserver? _abstractScheduleObserver;
+
///
/// Random value generator used by the scheduling strategies.
///
@@ -147,12 +161,18 @@ public class TestingEngine
///
private int PrintGuard;
+ private StreamWriter TimelineFileStream;
+
+
///
/// Creates a new systematic testing engine.
///
public static TestingEngine Create(CheckerConfiguration checkerConfiguration) =>
Create(checkerConfiguration, LoadAssembly(checkerConfiguration.AssemblyToBeAnalyzed));
+ private Stopwatch watch;
+ private bool ShouldEmitTrace;
+
///
/// Creates a new systematic testing engine.
///
@@ -179,17 +199,26 @@ public static TestingEngine Create(CheckerConfiguration checkerConfiguration, As
}
TestMethodInfo testMethodInfo = null;
+ EventPatternObserver eventMatcher = null;
try
{
testMethodInfo = TestMethodInfo.GetFromAssembly(assembly, checkerConfiguration.TestCaseName);
Console.Out.WriteLine($".. Test case :: {testMethodInfo.Name}");
+
+ Type t = assembly.GetType("PImplementation.GlobalFunctions");
+ if (checkerConfiguration.PatternSource.Length > 0)
+ {
+ var result = t.GetMethod(checkerConfiguration.PatternSource,
+ BindingFlags.Public | BindingFlags.Static)!;
+ eventMatcher = new EventPatternObserver(result);
+ }
}
catch
{
Error.ReportAndExit($"Failed to get test method '{checkerConfiguration.TestCaseName}' from assembly '{assembly.FullName}'");
}
- return new TestingEngine(checkerConfiguration, testMethodInfo);
+ return new TestingEngine(checkerConfiguration, testMethodInfo, eventMatcher);
}
///
@@ -236,13 +265,19 @@ internal TestingEngine(CheckerConfiguration checkerConfiguration, Delegate test)
{
}
+ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo testMethodInfo)
+ : this(checkerConfiguration, testMethodInfo, null)
+ {
+ }
+
///
/// Initializes a new instance of the class.
///
- private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo testMethodInfo)
+ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo testMethodInfo, EventPatternObserver observer)
{
_checkerConfiguration = checkerConfiguration;
TestMethodInfo = testMethodInfo;
+ _eventPatternObserver = observer;
Logger = new ConsoleLogger();
ErrorReporter = new ErrorReporter(checkerConfiguration, Logger);
@@ -259,12 +294,16 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
CancellationTokenSource = new CancellationTokenSource();
PrintGuard = 1;
-
+ TimelineFileStream = new StreamWriter(checkerConfiguration.OutputDirectory + "timeline.txt");
// Initialize a new instance of JsonVerboseLogs if running in verbose mode.
if (checkerConfiguration.IsVerbose)
{
JsonVerboseLogs = new List>();
}
+ if (checkerConfiguration.EnableConflictAnalysis || checkerConfiguration.SchedulingStrategy == "rff")
+ {
+ _conflictOpMonitor = new ConflictOpMonitor();
+ }
if (checkerConfiguration.SchedulingStrategy is "replay")
{
@@ -278,13 +317,38 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
}
else if (checkerConfiguration.SchedulingStrategy is "pct")
{
- Strategy = new PCTStrategy(checkerConfiguration.MaxUnfairSchedulingSteps, checkerConfiguration.StrategyBound,
- RandomValueGenerator);
+ var scheduler = new PCTScheduler(checkerConfiguration.StrategyBound, 0,
+ new RandomPriorizationProvider(RandomValueGenerator));
+ Strategy = new PrioritizedSchedulingStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
+ RandomValueGenerator, scheduler);
+ }
+ else if (checkerConfiguration.SchedulingStrategy is "pctcp")
+ {
+ _vcWrapper = new VectorClockWrapper();
+ var scheduler = new PCTCPScheduler(checkerConfiguration.StrategyBound, 0,
+ new RandomPriorizationProvider(RandomValueGenerator), _vcWrapper);
+ Strategy = new PrioritizedSchedulingStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
+ RandomValueGenerator, scheduler);
+ }
+ else if (checkerConfiguration.SchedulingStrategy is "pos")
+ {
+ var scheduler = new POSScheduler(new RandomPriorizationProvider(RandomValueGenerator), _conflictOpMonitor);
+ Strategy = new PrioritizedSchedulingStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
+ RandomValueGenerator, scheduler);
+ }
+ else if (checkerConfiguration.SchedulingStrategy is "rff")
+ {
+ _abstractScheduleObserver = new AbstractScheduleObserver();
+ var scheduler = new RFFScheduler(RandomValueGenerator, _conflictOpMonitor, _abstractScheduleObserver);
+ Strategy = new PrioritizedSchedulingStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
+ RandomValueGenerator, scheduler);
}
else if (checkerConfiguration.SchedulingStrategy is "fairpct")
{
var prefixLength = checkerConfiguration.MaxUnfairSchedulingSteps;
- var prefixStrategy = new PCTStrategy(prefixLength, checkerConfiguration.StrategyBound, RandomValueGenerator);
+ var scheduler = new PCTScheduler(checkerConfiguration.StrategyBound, 0,
+ new RandomPriorizationProvider(RandomValueGenerator));
+ var prefixStrategy = new PrioritizedSchedulingStrategy(prefixLength, RandomValueGenerator, scheduler);
var suffixStrategy = new RandomStrategy(checkerConfiguration.MaxFairSchedulingSteps, RandomValueGenerator);
Strategy = new ComboStrategy(prefixStrategy, suffixStrategy);
}
@@ -295,12 +359,43 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
}
else if (checkerConfiguration.SchedulingStrategy is "rl")
{
- Strategy = new QLearningStrategy(checkerConfiguration.MaxUnfairSchedulingSteps, RandomValueGenerator);
+ Strategy = new QLearningStrategy(checkerConfiguration.MaxUnfairSchedulingSteps, RandomValueGenerator,
+ checkerConfiguration.DiversityBasedPriority);
}
else if (checkerConfiguration.SchedulingStrategy is "dfs")
{
Strategy = new DFSStrategy(checkerConfiguration.MaxUnfairSchedulingSteps);
}
+ else if (checkerConfiguration.SchedulingStrategy is "feedback")
+ {
+ Strategy = new FeedbackGuidedStrategy(
+ _checkerConfiguration, new RandomInputGenerator(checkerConfiguration), new RandomScheduleGenerator(checkerConfiguration));
+ }
+ else if (checkerConfiguration.SchedulingStrategy is "2stagefeedback")
+ {
+ Strategy = new TwoStageFeedbackStrategy(_checkerConfiguration, new RandomInputGenerator(checkerConfiguration), new RandomScheduleGenerator(checkerConfiguration));
+ }
+ else if (checkerConfiguration.SchedulingStrategy is "feedbackpct")
+ {
+ Strategy = new FeedbackGuidedStrategy(_checkerConfiguration, new RandomInputGenerator(checkerConfiguration), new PctScheduleGenerator(checkerConfiguration));
+ }
+ else if (checkerConfiguration.SchedulingStrategy is "feedbackpctcp")
+ {
+ _vcWrapper = new VectorClockWrapper();
+ Strategy = new FeedbackGuidedStrategy(_checkerConfiguration, new
+ RandomInputGenerator(checkerConfiguration), new PctcpScheduleGenerator(checkerConfiguration, _vcWrapper));
+ }
+ else if (checkerConfiguration.SchedulingStrategy is "feedbackpos")
+ {
+ Strategy = new FeedbackGuidedStrategy(
+ _checkerConfiguration,
+ new RandomInputGenerator(checkerConfiguration),
+ new POSScheduleGenerator(_checkerConfiguration, _conflictOpMonitor));
+ }
+ else if (checkerConfiguration.SchedulingStrategy is "2stagefeedbackpct")
+ {
+ Strategy = new TwoStageFeedbackStrategy(_checkerConfiguration, new RandomInputGenerator(checkerConfiguration), new PctScheduleGenerator(checkerConfiguration));
+ }
else if (checkerConfiguration.SchedulingStrategy is "portfolio")
{
Error.ReportAndExit("Portfolio testing strategy is only " +
@@ -380,6 +475,10 @@ private System.Threading.Tasks.Task CreateTestingTask()
var options = string.Empty;
if (_checkerConfiguration.SchedulingStrategy is "random" ||
_checkerConfiguration.SchedulingStrategy is "pct" ||
+ _checkerConfiguration.SchedulingStrategy is "poc" ||
+ _checkerConfiguration.SchedulingStrategy is "feedbackpct" ||
+ _checkerConfiguration.SchedulingStrategy is "feedbackpctcp" ||
+ _checkerConfiguration.SchedulingStrategy is "feedbackpos" ||
_checkerConfiguration.SchedulingStrategy is "fairpct" ||
_checkerConfiguration.SchedulingStrategy is "probabilistic" ||
_checkerConfiguration.SchedulingStrategy is "rl")
@@ -394,9 +493,10 @@ _checkerConfiguration.SchedulingStrategy is "probabilistic" ||
{
try
{
+
// Invokes the user-specified initialization method.
TestMethodInfo.InitializeAllIterations();
-
+ watch = Stopwatch.StartNew();
var maxIterations = IsReplayModeEnabled ? 1 : _checkerConfiguration.TestingIterations;
int i = 0;
while (maxIterations == 0 || i < maxIterations)
@@ -496,13 +596,31 @@ private void RunNextIteration(int schedule)
try
{
+ ShouldEmitTrace = false;
// Creates a new instance of the controlled runtime.
runtime = new ControlledRuntime(_checkerConfiguration, Strategy, RandomValueGenerator);
+ if (_conflictOpMonitor != null)
+ {
+ runtime.SendEventMonitors.Add(_conflictOpMonitor);
+ }
+ if (_abstractScheduleObserver != null)
+ {
+ runtime.SendEventMonitors.Add(_abstractScheduleObserver);
+ }
+ if (_eventPatternObserver != null)
+ {
+ runtime.RegisterLog(_eventPatternObserver);
+ }
// Always output a json log of the error
JsonLogger = new JsonWriter();
runtime.SetJsonLogger(JsonLogger);
+ if (_vcWrapper != null)
+ {
+ _vcWrapper.CurrentVC = JsonLogger.VcGenerator;
+ }
+
// If verbosity is turned off, then intercept the program log, and also redirect
// the standard output and error streams to a nul logger.
if (!_checkerConfiguration.IsVerbose)
@@ -530,6 +648,11 @@ private void RunNextIteration(int schedule)
callback(schedule);
}
+ if (Strategy is IFeedbackGuidedStrategy strategy)
+ {
+ strategy.ObserveRunningResults(_eventPatternObserver, runtime);
+ }
+
// Checks that no monitor is in a hot state at termination. Only
// checked if no safety property violations have been found.
if (!runtime.Scheduler.BugFound)
@@ -552,7 +675,7 @@ private void RunNextIteration(int schedule)
GatherTestingStatistics(runtime);
- if (!IsReplayModeEnabled && TestReport.NumOfFoundBugs > 0)
+ if (ShouldEmitTrace || (!IsReplayModeEnabled && TestReport.NumOfFoundBugs > 0))
{
if (runtimeLogger != null)
{
@@ -561,7 +684,12 @@ private void RunNextIteration(int schedule)
}
ConstructReproducableTrace(runtime);
+ if (_checkerConfiguration.OutputDirectory != null)
+ {
+ TryEmitTraces(_checkerConfiguration.OutputDirectory, "trace_0");
+ }
}
+
}
finally
{
@@ -572,6 +700,18 @@ private void RunNextIteration(int schedule)
Console.SetError(stdErr);
}
+
+ if (ShouldPrintIteration(schedule))
+ {
+ var seconds = watch.Elapsed.TotalSeconds;
+ Logger.WriteLine($"Elapsed: {seconds}, " +
+ $"# timelines: {TestReport.ExploredTimelines.Count}");
+ if (Strategy is IFeedbackGuidedStrategy s)
+ {
+ s.DumpStats(Logger);
+ }
+ }
+
if (!IsReplayModeEnabled && _checkerConfiguration.PerformFullExploration && runtime.Scheduler.BugFound)
{
Logger.WriteLine($"..... Schedule #{schedule + 1} " +
@@ -579,9 +719,15 @@ private void RunNextIteration(int schedule)
$"[task-{_checkerConfiguration.TestingProcessId}]");
}
- // Cleans up the runtime before the next schedule starts.
+ // Cleans up the runtime before the next iteration starts.
+ if (_eventPatternObserver != null)
+ {
+ runtime.RemoveLog(_eventPatternObserver);
+ }
runtimeLogger?.Dispose();
runtime?.Dispose();
+ _eventPatternObserver?.Reset();
+ _conflictOpMonitor?.Reset();
}
}
@@ -611,6 +757,11 @@ public string GetReport()
return TestReport.GetText(_checkerConfiguration, "...");
}
+ public void TryEmitTimeline(TimelineObserver observer)
+ {
+ TimelineFileStream.WriteLine(observer.GetTimeline());
+ }
+
///
/// Returns an object where the value null is replaced with "null"
///
@@ -700,14 +851,14 @@ public void TryEmitTraces(string directory, string file)
JsonSerializer.Serialize(jsonStreamFile, JsonLogger.Logs, jsonSerializerConfig);
}
- if (Graph != null)
+ if (Graph != null && !_checkerConfiguration.PerformFullExploration)
{
var graphPath = directory + file + "_" + index + ".dgml";
Graph.SaveDgml(graphPath, true);
Logger.WriteLine($"..... Writing {graphPath}");
}
- if (!_checkerConfiguration.PerformFullExploration)
+ if (!_checkerConfiguration.PerformFullExploration || ShouldEmitTrace)
{
// Emits the reproducable trace, if it exists.
if (!string.IsNullOrEmpty(ReproducableTrace))
@@ -859,12 +1010,36 @@ private void GatherTestingStatistics(ControlledRuntime runtime)
report.CoverageInfo.CoverageGraph = Graph;
}
- var coverageInfo = runtime.GetCoverageInfo();
- report.CoverageInfo.Merge(coverageInfo);
- TestReport.Merge(report);
+ int shouldSave = 1;
+
+ if (_eventPatternObserver != null)
+ {
+ shouldSave = _eventPatternObserver.ShouldSave();
+ TestReport.ValidScheduling.TryAdd(shouldSave, 0);
+ TestReport.ValidScheduling[shouldSave] += 1;
- // Also save the graph snapshot of the last schedule, if there is one.
- Graph = coverageInfo.CoverageGraph;
+ }
+
+ if (shouldSave == 1)
+ {
+ var coverageInfo = runtime.GetCoverageInfo();
+ report.CoverageInfo.Merge(coverageInfo);
+ TestReport.Merge(report);
+
+ if (TestReport.ExploredTimelines.Add(runtime.TimelineObserver.GetTimelineHash()))
+ {
+ // if (_checkerConfiguration.IsVerbose)
+ // {
+ // Logger.WriteLine($"... New timeline observed: {runtime.TimelineObserver.GetTimeline()}");
+ // }
+ TryEmitTimeline(runtime.TimelineObserver);
+ ShouldEmitTrace = true;
+ }
+ // Also save the graph snapshot of the last iteration, if there is one.
+ Graph = coverageInfo.CoverageGraph;
+ // Also save the graph snapshot of the last schedule, if there is one.
+ Graph = coverageInfo.CoverageGraph;
+ }
}
///
@@ -970,6 +1145,10 @@ private bool ShouldPrintIteration(int schedule)
var count = schedule.ToString().Length - 1;
var guard = "1" + (count > 0 ? string.Concat(Enumerable.Repeat("0", count)) : string.Empty);
PrintGuard = int.Parse(guard);
+ if (PrintGuard > 1000)
+ {
+ PrintGuard = 1000;
+ }
}
return schedule % PrintGuard == 0;
diff --git a/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs b/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs
index 69e5343d4a..fa2bd5fb1a 100644
--- a/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs
+++ b/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs
@@ -22,6 +22,8 @@ public class CSharpCodeGenerator : ICodeGenerator
///
public bool HasCompilationStage => true;
+ private int _sendEventIndex = 0;
+
public void Compile(ICompilerConfiguration job)
{
var csprojName = $"{job.ProjectName}.csproj";
@@ -151,6 +153,7 @@ private void WriteSourcePrologue(CompilationContext context, StringWriter output
{
context.WriteLine(output, "using PChecker;");
context.WriteLine(output, "using PChecker.Actors;");
+ context.WriteLine(output, "using PChecker.Matcher;");
context.WriteLine(output, "using PChecker.Actors.Events;");
context.WriteLine(output, "using PChecker.Runtime;");
context.WriteLine(output, "using PChecker.Specifications;");
@@ -484,8 +487,8 @@ private void WriteEvent(CompilationContext context, StringWriter output, PEvent
var payloadType = GetCSharpType(pEvent.PayloadType, true);
context.WriteLine(output, $"internal partial class {declName} : PEvent");
context.WriteLine(output, "{");
- context.WriteLine(output, $"public {declName}() : base() {{}}");
- context.WriteLine(output, $"public {declName} ({payloadType} payload): base(payload)" + "{ }");
+ context.WriteLine(output, $"public {declName}() : base(-1) {{}}");
+ context.WriteLine(output, $"public {declName}({payloadType} payload, int loc): base(payload, loc)" + "{ }");
context.WriteLine(output, $"public override IPrtValue Clone() {{ return new {declName}();}}");
context.WriteLine(output, "}");
@@ -510,12 +513,12 @@ private void WriteMachine(CompilationContext context, StringWriter output, Machi
var cTorType = GetCSharpType(machine.PayloadType, true);
context.Write(output, "public class ConstructorEvent : PEvent");
context.Write(output, "{");
- context.Write(output, $"public ConstructorEvent({cTorType} val) : base(val) {{ }}");
+ context.Write(output, $"public ConstructorEvent({cTorType} val, int loc) : base(val, loc) {{ }}");
context.WriteLine(output, "}");
context.WriteLine(output);
context.WriteLine(output,
- $"protected override Event GetConstructorEvent(IPrtValue value) {{ return new ConstructorEvent(({cTorType})value); }}");
+ $"protected override Event GetConstructorEvent(IPrtValue value) {{ return new ConstructorEvent(({cTorType})value, {_sendEventIndex++}); }}");
// create the constructor to initialize the sends, creates and receives list
WriteMachineConstructor(context, output, machine);
@@ -706,7 +709,7 @@ private void WriteFunction(CompilationContext context, StringWriter output, Func
var staticKeyword = isStatic ? "static " : "";
var asyncKeyword = isAsync ? "async " : "";
- var returnType = GetCSharpType(signature.ReturnType);
+ var returnType = function.Role != FunctionRole.Scenario ? GetCSharpType(signature.ReturnType) : "int";
if (isAsync)
{
@@ -719,6 +722,10 @@ private void WriteFunction(CompilationContext context, StringWriter output, Func
{
functionParameters = "Event currentMachine_dequeuedEvent";
}
+ else if (function.Role == FunctionRole.Scenario)
+ {
+ functionParameters = "List events";
+ }
else
{
functionParameters = string.Join(
@@ -727,7 +734,7 @@ private void WriteFunction(CompilationContext context, StringWriter output, Func
$"{GetCSharpType(param.Type)} {context.Names.GetNameForDecl(param)}"));
}
- if (isStatic) // then we need to generate two versions of the function
+ if (isStatic && function.Role != FunctionRole.Scenario) // then we need to generate two versions of the function
{
// for machine
var seperator = functionParameters == "" ? "" : ", ";
@@ -783,14 +790,69 @@ private void WriteFunctionBody(CompilationContext context, StringWriter output,
$"{GetCSharpType(type, true)} {context.Names.GetNameForDecl(local)} = {GetDefaultValue(type)};");
}
- foreach (var bodyStatement in function.Body.Statements)
+ if (function.Role != FunctionRole.Scenario)
+ {
+ foreach (var bodyStatement in function.Body.Statements)
+ {
+ WriteStmt(context: context, output: output, function: function, stmt: bodyStatement);
+ }
+ }
+ else
{
- WriteStmt(context: context, output: output, function: function, stmt: bodyStatement);
+ WriteScenario(context, output, function);
}
+
context.WriteLine(output, "}");
}
+ private void WriteScenario(CompilationContext context, StringWriter output, Function function)
+ {
+ int numOfStmt = function.Body.Statements.Count + 1;
+ context.WriteLine(output, $"int state = {numOfStmt};");
+ var eventPredicates = string.Join(" or ", function.Signature.ParameterEvents.Select(it => it.Name));
+ context.WriteLine(output, $"events = events.Where(it => it.Event is {eventPredicates}).ToList();");
+ WriteConstraintsRecursive(context, output, function, 0, new HashSet(), 0);
+ context.WriteLine(output, "return state;");
+ }
+
+ private void WriteConstraintsRecursive(CompilationContext context, StringWriter output, Function function, int index, HashSet visitedVariables, int satisfiedConstraints)
+ {
+ if (index >= function.Signature.Parameters.Count)
+ {
+ context.WriteLine(output, "return 1;");
+ return;
+ }
+ var param = function.Signature.Parameters[index];
+ var e = function.Signature.ParameterEvents[index];
+ visitedVariables.Add(param);
+ var start = index == 0 ? "0" : $"i{index - 1} + 1";
+ var paramName = context.Names.GetNameForDecl(param);
+ context.WriteLine(output, $"for (var i{index} = {start} ; i{index} < events.Count; i{index} ++) " + "{");
+ context.WriteLine(output, $"var {paramName}_obj = events[i{index}];");
+ context.WriteLine(output, $"if ({paramName}_obj.Event is not {e.Name}) continue;");
+ context.WriteLine(output, $"var {paramName} = ((PEvent) {paramName}_obj.Event).Payload;");
+
+ foreach (var bodyStatement in function.Body.Statements)
+ {
+ if (bodyStatement is ConstraintStmt stmt)
+ {
+ var variables = ConstraintVariableCollector.FindVariablesRecursive(stmt.Constraint);
+ if (variables.Contains(param) && visitedVariables.IsSupersetOf(variables))
+ {
+ context.Write(output, $"if (!(");
+ WriteExpr(context, output, stmt.Constraint);
+ context.WriteLine(output, $")) continue;");
+ satisfiedConstraints += 1;
+ context.WriteLine(output, $"state = Math.Min({function.Body.Statements.Count - satisfiedConstraints + 1}, state);");
+ }
+ }
+ }
+ WriteConstraintsRecursive(context, output, function, index + 1, visitedVariables, satisfiedConstraints);
+ context.WriteLine(output, "}");
+ }
+
+
private void WriteStmt(CompilationContext context, StringWriter output, Function function, IPStmt stmt)
{
switch (stmt)
@@ -1179,9 +1241,19 @@ private void WriteLValue(CompilationContext context, StringWriter output, IPExpr
break;
case NamedTupleAccessExpr namedTupleAccessExpr:
- context.Write(output, "((PrtNamedTuple)");
- WriteExpr(context, output, namedTupleAccessExpr.SubExpr);
- context.Write(output, $")[\"{namedTupleAccessExpr.FieldName}\"]");
+ if (ExprVisitor.ReservedEventFeilds.ContainsValue(namedTupleAccessExpr.Entry))
+ {
+ var type = GetCSharpType(namedTupleAccessExpr.Entry.Type);
+ context.Write(output, $"(({type}) (");
+ WriteExpr(context, output, namedTupleAccessExpr.SubExpr);
+ context.Write(output, $"_obj).{namedTupleAccessExpr.FieldName})");
+ }
+ else
+ {
+ context.Write(output, "((PrtNamedTuple)");
+ WriteExpr(context, output, namedTupleAccessExpr.SubExpr);
+ context.Write(output, $")[\"{namedTupleAccessExpr.FieldName}\"]");
+ }
break;
case SeqAccessExpr seqAccessExpr:
@@ -1225,9 +1297,9 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p
context.Write(output, $"({negate}PrtValues.SafeEquals(");
if (PLanguageType.TypeIsOfKind(binOpExpr.Lhs.Type, TypeKind.Enum))
{
- context.Write(output, "PrtValues.Box((long) ");
+ context.Write(output, "PrtValues.Box((long) ((PrtInt)");
WriteExpr(context, output, binOpExpr.Lhs);
- context.Write(output, "),");
+ context.Write(output, ")),");
}
else
{
@@ -1237,9 +1309,9 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p
if (PLanguageType.TypeIsOfKind(binOpExpr.Rhs.Type, TypeKind.Enum))
{
- context.Write(output, "PrtValues.Box((long) ");
+ context.Write(output, "PrtValues.Box((long) ((PrtInt)");
WriteExpr(context, output, binOpExpr.Rhs);
- context.Write(output, ")");
+ context.Write(output, "))");
}
else
{
@@ -1388,7 +1460,7 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p
switch (eventName)
{
case "Halt":
- context.Write(output, "new PHalt()");
+ context.Write(output, "new PHalt(" + _sendEventIndex++ + ")");
break;
case "DefaultEvent":
@@ -1397,7 +1469,7 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p
default:
var payloadExpr = GetDefaultValue(eventRefExpr.Value.PayloadType);
- context.Write(output, $"new {eventName}({payloadExpr})");
+ context.Write(output, $"new {eventName}({payloadExpr}, {_sendEventIndex++})");
break;
}
diff --git a/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs b/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs
index 943eba0df8..8e6992cf9b 100644
--- a/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs
+++ b/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs
@@ -567,6 +567,9 @@ private List SimplifyStatement(IPStmt statement)
condCheck.Concat(SimplifyStatement(whileStmt.Body)));
return new List { new WhileStmt(location, new BoolLiteralExpr(location, true), loopBody) };
+ // We do not rewrite constraint statements for now.
+ case ConstraintStmt constraintStmt:
+ return new List() { constraintStmt };
default:
throw new ArgumentOutOfRangeException(nameof(statement));
diff --git a/Src/PCompiler/CompilerCore/Parser/PLexer.g4 b/Src/PCompiler/CompilerCore/Parser/PLexer.g4
index 8f7511ac8d..e8fb715019 100644
--- a/Src/PCompiler/CompilerCore/Parser/PLexer.g4
+++ b/Src/PCompiler/CompilerCore/Parser/PLexer.g4
@@ -70,6 +70,7 @@ MODULE : 'module' ;
IMPLEMENTATION : 'implementation' ;
TEST : 'test' ;
REFINES : 'refines' ;
+SCENARIO : 'scenario' ;
// module constructors
COMPOSE : 'compose' ;
diff --git a/Src/PCompiler/CompilerCore/Parser/PParser.g4 b/Src/PCompiler/CompilerCore/Parser/PParser.g4
index dc00fca475..3140b37edb 100644
--- a/Src/PCompiler/CompilerCore/Parser/PParser.g4
+++ b/Src/PCompiler/CompilerCore/Parser/PParser.g4
@@ -60,6 +60,7 @@ topDecl : typeDefDecl
| namedModuleDecl
| testDecl
| implementationDecl
+ | scenarioDecl
;
@@ -107,6 +108,13 @@ funDecl : FUN name=iden LPAREN funParamList? RPAREN (COLON type)? (CREATES inter
| FUN name=iden LPAREN funParamList? RPAREN (COLON type)? functionBody # PFunDecl
;
+scenarioDecl : SCENARIO scenarioName=iden LPAREN scenarioParamList RPAREN scenarioBody;
+
+scenarioParamList: scenarioParam (COMMA scenarioParam)*;
+scenarioParam : name=iden COLON nonDefaultEvent;
+scenarioBody : LBRACE expr (COMMA expr)* RBRACE;
+
+
stateDecl : START? temperature=(HOT | COLD)? STATE name=iden LBRACE stateBodyItem* RBRACE ;
stateBodyItem : ENTRY anonEventHandler # StateEntry
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/Function.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/Function.cs
index c30a91299c..7ca2b40f49 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/Function.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/Function.cs
@@ -15,7 +15,8 @@ public enum FunctionRole
EventHandler = 1 << 4,
ExitHandler = 1 << 5,
ReceiveHandler = 1 << 6,
- Foreign = 1 << 7
+ Foreign = 1 << 7,
+ Scenario = 1 << 8,
}
public class Function : IPDecl, IHasScope
@@ -32,7 +33,8 @@ sourceNode is PParser.AnonEventHandlerContext ||
sourceNode is PParser.NoParamAnonEventHandlerContext ||
sourceNode is PParser.ReceiveStmtContext ||
sourceNode is PParser.WhileStmtContext ||
- sourceNode is PParser.ForeachStmtContext);
+ sourceNode is PParser.ForeachStmtContext ||
+ sourceNode is PParser.ScenarioDeclContext);
Name = name;
SourceLocation = sourceNode;
}
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/FunctionSignature.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/FunctionSignature.cs
index b711938af6..c3801faab7 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/FunctionSignature.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/FunctionSignature.cs
@@ -7,6 +7,8 @@ namespace Plang.Compiler.TypeChecker.AST.Declarations
public class FunctionSignature
{
public List Parameters { get; } = new List();
+ // This is only used by scenarios.
+ public List ParameterEvents { get; } = new();
public IEnumerable ParameterTypes => Parameters.Select(ty => ty.Type);
public PLanguageType ReturnType { get; set; } = PrimitiveType.Null;
}
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/ConstraintStmt.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/ConstraintStmt.cs
new file mode 100644
index 0000000000..163e1a5953
--- /dev/null
+++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/ConstraintStmt.cs
@@ -0,0 +1,15 @@
+using Antlr4.Runtime;
+
+namespace Plang.Compiler.TypeChecker.AST.Statements;
+
+public class ConstraintStmt : IPStmt
+{
+ public ConstraintStmt(ParserRuleContext sourceLocation, IPExpr constraint)
+ {
+ SourceLocation = sourceLocation;
+ Constraint = constraint;
+ }
+
+ public IPExpr Constraint { get; }
+ public ParserRuleContext SourceLocation { get; }
+}
\ No newline at end of file
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Analyzer.cs b/Src/PCompiler/CompilerCore/TypeChecker/Analyzer.cs
index 050be18cca..aac694afb0 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/Analyzer.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/Analyzer.cs
@@ -180,6 +180,13 @@ private static Scope BuildGlobalScope(ICompilerConfiguration config, PParser.Pro
DeclarationVisitor.PopulateDeclarations(config.Handler, globalScope, programUnit, nodesToDeclarations);
}
+ // Step 3: Assign param types for scenario events. We have do this after all events are initialized.
+ foreach (var function in globalScope.Functions)
+ {
+ ScenarioEventVisitor.PopulateEventTypes(function);
+ }
+
+
return globalScope;
}
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/ConstraintVariableCollector.cs b/Src/PCompiler/CompilerCore/TypeChecker/ConstraintVariableCollector.cs
new file mode 100644
index 0000000000..647d9c1168
--- /dev/null
+++ b/Src/PCompiler/CompilerCore/TypeChecker/ConstraintVariableCollector.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Plang.Compiler.TypeChecker.AST;
+using Plang.Compiler.TypeChecker.AST.Declarations;
+using Plang.Compiler.TypeChecker.AST.Expressions;
+
+namespace Plang.Compiler.TypeChecker;
+
+public class ConstraintVariableCollector
+{
+
+ public static HashSet FindVariablesRecursive(IPExpr expr)
+ {
+ switch (expr)
+ {
+ case BinOpExpr binOp:
+ return FindVariablesRecursive(binOp.Lhs).Union(FindVariablesRecursive(binOp.Rhs)).ToHashSet();
+ case NamedTupleAccessExpr namedTupleAccessExpr:
+ return FindVariablesRecursive(namedTupleAccessExpr.SubExpr);
+ case VariableAccessExpr variableAccessExpr:
+ return new HashSet() { variableAccessExpr.Variable };
+ case EnumElemRefExpr:
+ case StringExpr:
+ case IntLiteralExpr:
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(expr));
+ }
+
+ return new HashSet();
+ }
+}
\ No newline at end of file
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/ControlFlowChecker.cs b/Src/PCompiler/CompilerCore/TypeChecker/ControlFlowChecker.cs
index ea09002934..bddcbbf892 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/ControlFlowChecker.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/ControlFlowChecker.cs
@@ -84,6 +84,7 @@ private void CheckStmt(IPStmt stmt)
case RemoveStmt _:
case ReturnStmt _:
case SendStmt _:
+ case ConstraintStmt _:
break;
default:
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/DeclarationStubVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/DeclarationStubVisitor.cs
index 77782e7308..c2bf47b518 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/DeclarationStubVisitor.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/DeclarationStubVisitor.cs
@@ -163,6 +163,26 @@ public override object VisitStateDecl(PParser.StateDeclContext context)
#endregion Machines
+ #region Scenario
+
+ public override object VisitScenarioDecl(PParser.ScenarioDeclContext context)
+ {
+ var scenarioName = context.scenarioName.GetText();
+ var scenario = CurrentScope.Put(scenarioName, context);
+ nodesToDeclarations.Put(context, scenario);
+ return VisitChildrenWithNewScope(scenario, context);
+ }
+
+ public override object VisitScenarioParam(PParser.ScenarioParamContext context)
+ {
+ var symbolName = context.name.GetText();
+ var decl = CurrentScope.Put(symbolName, context, VariableRole.Param);
+ nodesToDeclarations.Put(context, decl);
+ return null;
+ }
+
+ #endregion
+
#region Functions
public override object VisitPFunDecl(PParser.PFunDeclContext context)
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/DeclarationVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/DeclarationVisitor.cs
index b726380da1..0c02c0a2a9 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/DeclarationVisitor.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/DeclarationVisitor.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using System.Runtime.CompilerServices;
using Antlr4.Runtime.Tree;
using Plang.Compiler.TypeChecker.AST;
using Plang.Compiler.TypeChecker.AST.Declarations;
@@ -349,6 +350,29 @@ public override object VisitSpecMachineDecl(PParser.SpecMachineDeclContext conte
return specMachine;
}
+ public override object VisitScenarioDecl(PParser.ScenarioDeclContext context)
+ {
+ var scenario = (Function)nodesToDeclarations.Get(context);
+ var result = ((Variable, PEvent)[]) Visit(context.scenarioParamList());
+ scenario.Signature.Parameters.AddRange(result.Select(it => it.Item1));
+ scenario.Signature.ParameterEvents.AddRange(result.Select(it => it.Item2));
+ scenario.Signature.ReturnType = PrimitiveType.Int;
+ scenario.Role = FunctionRole.Scenario;
+ return scenario;
+ }
+
+ public override object VisitScenarioParamList(PParser.ScenarioParamListContext context)
+ {
+ return context.scenarioParam().Select(Visit).Cast<(Variable, PEvent)>().ToArray();
+ }
+
+ public override object VisitScenarioParam(PParser.ScenarioParamContext context)
+ {
+ var param = (Variable) nodesToDeclarations.Get(context);
+ var e = (PEvent) Visit(context.nonDefaultEvent());
+ return (param, e);
+ }
+
public override object VisitMachineBody(PParser.MachineBodyContext context)
{
foreach (var machineEntryContext in context.machineEntry())
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs
index bd63b504db..6306c0659d 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs
@@ -12,6 +12,18 @@ namespace Plang.Compiler.TypeChecker
{
public class ExprVisitor : PParserBaseVisitor
{
+ public static readonly string EventFieldSender = "MSG_sender";
+ public static readonly string EventFieldReceiver = "MSG_receiver";
+ public static readonly string EventFieldState = "MSG_state";
+ public static readonly string EventFieldIndex = "MSG_index";
+
+ public static Dictionary ReservedEventFeilds = new Dictionary()
+ {
+ { EventFieldSender, new NamedTupleEntry("Sender", -1, PrimitiveType.String) },
+ { EventFieldReceiver, new NamedTupleEntry("Receiver", -1, PrimitiveType.String) },
+ { EventFieldState, new NamedTupleEntry("State", -1, PrimitiveType.String) },
+ { EventFieldIndex, new NamedTupleEntry("Index", -1, PrimitiveType.Int) },
+ };
private readonly ITranslationErrorHandler handler;
private readonly Function method;
private readonly Scope table;
@@ -46,12 +58,18 @@ public override IPExpr VisitParenExpr(PParser.ParenExprContext context)
public override IPExpr VisitNamedTupleAccessExpr(PParser.NamedTupleAccessExprContext context)
{
var subExpr = Visit(context.expr());
+ var fieldName = context.field.GetText();
+ if (subExpr is VariableAccessExpr v && method.Role == FunctionRole.Scenario && method.Signature.Parameters.Contains(v.Variable))
+ {
+ if (ReservedEventFeilds.TryGetValue(fieldName, out var reservedEntry))
+ {
+ return new NamedTupleAccessExpr(context, subExpr, reservedEntry);
+ }
+ }
if (!(subExpr.Type.Canonicalize() is NamedTupleType tuple))
{
throw handler.TypeMismatch(subExpr, TypeKind.NamedTuple);
}
-
- var fieldName = context.field.GetText();
if (!tuple.LookupEntry(fieldName, out var entry))
{
throw handler.MissingNamedTupleEntry(context.field, tuple);
@@ -605,7 +623,7 @@ public override IPExpr VisitNamedTupleBody(PParser.NamedTupleBodyContext context
}
names.Add(entryName);
- entries[i] = new NamedTupleEntry { Name = entryName, FieldNo = i, Type = fields[i].Type };
+ entries[i] = new NamedTupleEntry(name: entryName, fieldNo: i, type: fields[i].Type);
}
var type = new NamedTupleType(entries);
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/FunctionBodyVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/FunctionBodyVisitor.cs
index 2cb0b21eb3..b3572fb73f 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/FunctionBodyVisitor.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/FunctionBodyVisitor.cs
@@ -1,6 +1,9 @@
+using System.Collections.Generic;
using System.Diagnostics.Contracts;
+using Plang.Compiler.TypeChecker.AST;
using Plang.Compiler.TypeChecker.AST.Declarations;
using Plang.Compiler.TypeChecker.AST.Statements;
+using Plang.Compiler.TypeChecker.Types;
namespace Plang.Compiler.TypeChecker
{
@@ -60,6 +63,30 @@ public override object VisitFunctionBody(PParser.FunctionBodyContext context)
return null;
}
+ public override object VisitScenarioDecl(PParser.ScenarioDeclContext context)
+ {
+ return Visit(context.scenarioBody());
+ }
+
+ public override object VisitScenarioBody(PParser.ScenarioBodyContext context)
+ {
+ var exprVisitor = new ExprVisitor(method, config.Handler);
+ // var compound = new CompoundStmt(context, new IPStmt[0]);
+ var stmts = new List();
+ foreach (var exprContext in context.expr())
+ {
+ var constraint = exprVisitor.Visit(exprContext);
+ if (!Equals(constraint.Type, PrimitiveType.Bool))
+ {
+ throw config.Handler.TypeMismatch(exprContext, constraint.Type, PrimitiveType.Bool);
+ }
+ stmts.Add( new ConstraintStmt(exprContext, constraint));
+ }
+
+ method.Body = new CompoundStmt(context, stmts);
+ return null;
+ }
+
public override object VisitVarDecl(PParser.VarDeclContext context)
{
foreach (var varName in context.idenList()._names)
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/FunctionValidator.cs b/Src/PCompiler/CompilerCore/TypeChecker/FunctionValidator.cs
index 16b1204a1a..35bd8a3be4 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/FunctionValidator.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/FunctionValidator.cs
@@ -11,7 +11,7 @@ public static class FunctionValidator
{
public static void CheckAllPathsReturn(ITranslationErrorHandler handler, Function function)
{
- if (function.IsForeign)
+ if (function.IsForeign || function.Role == FunctionRole.Scenario)
{
return;
}
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/ScenarioEventVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/ScenarioEventVisitor.cs
new file mode 100644
index 0000000000..3cd4518397
--- /dev/null
+++ b/Src/PCompiler/CompilerCore/TypeChecker/ScenarioEventVisitor.cs
@@ -0,0 +1,20 @@
+using Antlr4.Runtime.Tree;
+using Plang.Compiler.TypeChecker.AST;
+using Plang.Compiler.TypeChecker.AST.Declarations;
+
+namespace Plang.Compiler.TypeChecker;
+
+public class ScenarioEventVisitor
+{
+
+ public static void PopulateEventTypes(Function function)
+ {
+ if (function.Role != FunctionRole.Scenario) return;
+ for (var i = 0; i < function.Signature.Parameters.Count; i++)
+ {
+ var v = function.Signature.Parameters[i];
+ var e = function.Signature.ParameterEvents[i];
+ v.Type = e.PayloadType;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Scope.cs b/Src/PCompiler/CompilerCore/TypeChecker/Scope.cs
index fed805c40d..70051a4c03 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/Scope.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/Scope.cs
@@ -516,6 +516,14 @@ public Interface Put(string name, PParser.InterfaceDeclContext tree)
return machineInterface;
}
+ public Function Put(string name, PParser.ScenarioDeclContext tree)
+ {
+ var scenario = new Function(name, tree);
+ CheckConflicts(scenario, Namespace(functions));
+ functions.Add(name, scenario);
+ return scenario;
+ }
+
public Machine Put(string name, PParser.ImplMachineDeclContext tree)
{
var machine = new Machine(name, tree);
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/TypeResolver.cs b/Src/PCompiler/CompilerCore/TypeChecker/TypeResolver.cs
index 39b22c3681..3fb843d8d9 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/TypeResolver.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/TypeResolver.cs
@@ -121,7 +121,7 @@ public override PLanguageType VisitNamedTupleType(PParser.NamedTupleTypeContext
}
names.Add(fieldName);
- fields[i] = new NamedTupleEntry { Name = fieldName, FieldNo = i, Type = Visit(field.type()) };
+ fields[i] = new NamedTupleEntry(name: fieldName, fieldNo: i, type: Visit(field.type()));
}
var ret = new NamedTupleType(fields);
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/NamedTupleEntry.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/NamedTupleEntry.cs
index f9223f79c4..89ad48ae17 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/Types/NamedTupleEntry.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/NamedTupleEntry.cs
@@ -2,6 +2,17 @@ namespace Plang.Compiler.TypeChecker.Types
{
public class NamedTupleEntry
{
+ public NamedTupleEntry()
+ {
+ }
+
+ public NamedTupleEntry(string name, int fieldNo, PLanguageType type)
+ {
+ Name = name;
+ FieldNo = fieldNo;
+ Type = type;
+ }
+
public string Name { get; set; }
public int FieldNo { get; set; }
public PLanguageType Type { get; set; }
diff --git a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
index 19b045004c..f50d9eefa1 100644
--- a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
+++ b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
@@ -54,9 +54,22 @@ internal PCheckerOptions()
var schedulingGroup = Parser.GetOrCreateGroup("scheduling", "Search prioritization options");
schedulingGroup.AddArgument("sch-random", null, "Choose the random scheduling strategy (this is the default)", typeof(bool));
+ schedulingGroup.AddArgument("sch-feedback", null, "Choose the random scheduling strategy with feedback mutation", typeof(bool));
+ schedulingGroup.AddArgument("sch-2stagefeedback", null, "Choose the random scheduling strategy with 2 stage feedback mutation", typeof(bool));
+
+ schedulingGroup.AddArgument("sch-feedbackpct", null, "Choose the PCT scheduling strategy with feedback mutation", typeof(uint));
+ schedulingGroup.AddArgument("sch-feedbackpctcp", null, "Choose the PCT scheduling strategy with feedback mutation", typeof(uint));
+ schedulingGroup.AddArgument("sch-feedbackpos", null,
+ "Choose the PCT scheduling strategy with feedback mutation", typeof(bool));
+ schedulingGroup.AddArgument("sch-rff", null, "Choose the RFF scheduling strategy", typeof(bool));
+ schedulingGroup.AddArgument("sch-2stagefeedbackpct", null, "Choose the PCT scheduling strategy with 2 stage feedback mutation", typeof(uint));
+
schedulingGroup.AddArgument("sch-probabilistic", "sp", "Choose the probabilistic scheduling strategy with given probability for each scheduling decision where the probability is " +
"specified as the integer N in the equation 0.5 to the power of N. So for N=1, the probability is 0.5, for N=2 the probability is 0.25, N=3 you get 0.125, etc.", typeof(uint));
schedulingGroup.AddArgument("sch-pct", null, "Choose the PCT scheduling strategy with given maximum number of priority switch points", typeof(uint));
+ schedulingGroup.AddArgument("sch-pctcp", null, "Choose the PCT scheduling strategy with given maximum number of priority switch points", typeof(uint));
+ schedulingGroup.AddArgument("sch-pos", null,
+ "Choose the PCT scheduling strategy with given maximum number of priority switch points", typeof(bool));
schedulingGroup.AddArgument("sch-fairpct", null, "Choose the fair PCT scheduling strategy with given maximum number of priority switch points", typeof(uint));
schedulingGroup.AddArgument("sch-rl", null, "Choose the reinforcement learning (RL) scheduling strategy", typeof(bool)).IsHidden = true;
var schCoverage = schedulingGroup.AddArgument("sch-coverage", null, "Choose the scheduling strategy for coverage mode (options: learn, random, dfs, stateless). (default: learn)");
@@ -74,7 +87,13 @@ internal PCheckerOptions()
advancedGroup.AddArgument("xml-trace", null, "Specify a filename for XML runtime log output to be written to", typeof(bool));
advancedGroup.AddArgument("psym-args", null, "Specify a concatenated list of additional PSym-specific arguments to pass, each starting with a colon").IsHidden = true;
advancedGroup.AddArgument("jvm-args", null, "Specify a concatenated list of PSym-specific JVM arguments to pass, each starting with a colon").IsHidden = true;
-
+ advancedGroup.AddArgument("pattern", null, "The name of the pattern matcher generator", typeof(string));
+ advancedGroup.AddArgument("no-partial-match", null, "For feedback strategy, do not save a schedule if the pattern is partially matched", typeof(bool));
+ advancedGroup.AddArgument("discard-after", null, "For feedback strategy, discard saved generators after saving N inputs", typeof(int));
+ advancedGroup.AddArgument("fixed-priority", null, "For feedback strategy, schedule generator mutations based on diversity", typeof(bool));
+ advancedGroup.AddArgument("ignore-pattern", null, "For feedback strategy, ignore the pattern feedback", typeof(bool));
+ advancedGroup.AddArgument("no-priority-based", null, "For feedback strategy, disable priority based sampling.", typeof(bool));
+ advancedGroup.AddArgument("conflict-analysis", null, "Enable POS conflict analysis.", typeof(bool));
}
///
@@ -227,11 +246,20 @@ private static void UpdateConfigurationWithParsedArgument(CheckerConfiguration c
checkerConfiguration.RandomGeneratorSeed = (uint)option.Value;
break;
case "sch-random":
+ case "sch-rff":
+ case "sch-pos":
+ case "sch-feedbackpos":
+ case "sch-feedback":
+ case "sch-2stagefeedback":
checkerConfiguration.SchedulingStrategy = option.LongName.Substring(4);
break;
case "sch-probabilistic":
case "sch-pct":
+ case "sch-pctcp":
case "sch-fairpct":
+ case "sch-feedbackpct":
+ case "sch-feedbackpctcp":
+ case "sch-2stagefeedbackpct":
checkerConfiguration.SchedulingStrategy = option.LongName.Substring(4);
checkerConfiguration.StrategyBound = (int)(uint)option.Value;
break;
@@ -311,6 +339,27 @@ private static void UpdateConfigurationWithParsedArgument(CheckerConfiguration c
case "jvm-args":
checkerConfiguration.JvmArgs = ((string)option.Value).Replace(':', ' ');
break;
+ case "pattern":
+ checkerConfiguration.PatternSource = (string) option.Value;
+ break;
+ case "no-partial-match":
+ checkerConfiguration.SavePartialMatch = false;
+ break;
+ case "discard-after":
+ checkerConfiguration.DiscardAfter = (int) option.Value;
+ break;
+ case "fixed-priority":
+ checkerConfiguration.DiversityBasedPriority = false;
+ break;
+ case "ignore-pattern":
+ checkerConfiguration.IgnorePatternFeedback = true;
+ break;
+ case "no-priority-based":
+ checkerConfiguration.PriorityBasedSampling = false;
+ break;
+ case "conflict-analysis":
+ checkerConfiguration.EnableConflictAnalysis = true;
+ break;
case "pproj":
// do nothing, since already configured through UpdateConfigurationWithPProjectFile
break;
@@ -337,15 +386,23 @@ private static void SanitizeConfiguration(CheckerConfiguration checkerConfigurat
if (checkerConfiguration.SchedulingStrategy != "portfolio" &&
checkerConfiguration.SchedulingStrategy != "random" &&
+ checkerConfiguration.SchedulingStrategy != "pctcp" &&
+ checkerConfiguration.SchedulingStrategy != "feedback" &&
+ checkerConfiguration.SchedulingStrategy != "feedbackpct" &&
+ checkerConfiguration.SchedulingStrategy != "feedbackpctcp" &&
+ checkerConfiguration.SchedulingStrategy != "feedbackpos" &&
+ checkerConfiguration.SchedulingStrategy != "2stagefeedback" &&
+ checkerConfiguration.SchedulingStrategy != "2stagefeedbackpct" &&
checkerConfiguration.SchedulingStrategy != "pct" &&
+ checkerConfiguration.SchedulingStrategy != "pos" &&
checkerConfiguration.SchedulingStrategy != "fairpct" &&
checkerConfiguration.SchedulingStrategy != "probabilistic" &&
checkerConfiguration.SchedulingStrategy != "rl" &&
checkerConfiguration.SchedulingStrategy != "replay" &&
checkerConfiguration.SchedulingStrategy != "learn" &&
checkerConfiguration.SchedulingStrategy != "dfs" &&
- checkerConfiguration.SchedulingStrategy != "stateless")
- {
+ checkerConfiguration.SchedulingStrategy != "rff" &&
+ checkerConfiguration.SchedulingStrategy != "stateless") {
Error.CheckerReportAndExit("Please provide a scheduling strategy (see --sch* options)");
}
@@ -378,7 +435,6 @@ private static void FindLocalPCompiledFile(CheckerConfiguration checkerConfigura
enumerationOptions.RecurseSubdirectories = true;
enumerationOptions.MaxRecursionDepth = 3;
-
var files =
from file in Directory.GetFiles(checkerConfiguration.PCompiledPath, filePattern, enumerationOptions)
let info = new FileInfo(file)
diff --git a/Src/PRuntimes/PCSharpRuntime/PEvent.cs b/Src/PRuntimes/PCSharpRuntime/PEvent.cs
index 78767414a5..a528315cb8 100644
--- a/Src/PRuntimes/PCSharpRuntime/PEvent.cs
+++ b/Src/PRuntimes/PCSharpRuntime/PEvent.cs
@@ -6,13 +6,15 @@ namespace Plang.CSharpRuntime
{
public class PEvent : Event, IPrtValue
{
- public PEvent() : base()
+ public PEvent(int loc) : base()
{
+ Loc = loc;
}
- public PEvent(IPrtValue payload) : base()
+ public PEvent(IPrtValue payload, int loc) : base()
{
Payload = payload;
+ Loc = loc;
}
public IPrtValue Payload { get; }
@@ -50,7 +52,7 @@ public override string ToString()
public class PHalt : PEvent
{
- public PHalt(IPrtValue payload) : base(payload)
+ public PHalt(IPrtValue payload, int loc) : base(payload, loc)
{
}
}
diff --git a/Src/PRuntimes/PCSharpRuntime/PMachine.cs b/Src/PRuntimes/PCSharpRuntime/PMachine.cs
index 3777ea5975..c8300ef401 100644
--- a/Src/PRuntimes/PCSharpRuntime/PMachine.cs
+++ b/Src/PRuntimes/PCSharpRuntime/PMachine.cs
@@ -84,7 +84,7 @@ public void TrySendEvent(PMachineValue target, Event ev, object payload = null)
Assert(target.Permissions.Contains(ev.GetType().Name),
$"Event {ev.GetType().Name} is not in the permissions set of the target machine");
var oneArgConstructor = ev.GetType().GetConstructors().First(x => x.GetParameters().Length > 0);
- ev = (Event)oneArgConstructor.Invoke(new[] { payload });
+ ev = (Event)oneArgConstructor.Invoke(new[] { payload , ev.Loc});
AnnounceInternal(ev);
SendEvent(target.Id, ev);
@@ -94,7 +94,7 @@ public void TryRaiseEvent(Event ev, object payload = null)
{
Assert(ev != null, "Machine cannot raise a null event");
var oneArgConstructor = ev.GetType().GetConstructors().First(x => x.GetParameters().Length > 0);
- ev = (Event)oneArgConstructor.Invoke(new[] { payload });
+ ev = (Event)oneArgConstructor.Invoke(new[] { payload, ev.Loc });
RaiseEvent(ev);
throw new PNonStandardReturnException { ReturnKind = NonStandardReturn.Raise };
}
@@ -182,7 +182,7 @@ public void Announce(Event ev, object payload = null)
}
var oneArgConstructor = ev.GetType().GetConstructors().First(x => x.GetParameters().Length > 0);
- var @event = (Event)oneArgConstructor.Invoke(new[] { payload });
+ var @event = (Event)oneArgConstructor.Invoke(new[] { payload, ev.Loc });
var pText = payload == null ? "" : $" with payload {((IPrtValue)payload).ToEscapedString()}";
Logger.WriteLine($" '{Id}' announced event '{ev.GetType().Name}'{pText}.");
@@ -247,7 +247,7 @@ public object ToDict()
public class InitializeParametersEvent : PEvent
{
- public InitializeParametersEvent(InitializeParameters payload) : base(payload)
+ public InitializeParametersEvent(InitializeParameters payload) : base(payload, 0)
{
}
}
diff --git a/Tutorial/2_TwoPhaseCommit/timeline.txt b/Tutorial/2_TwoPhaseCommit/timeline.txt
new file mode 100644
index 0000000000..e69de29bb2
From c6f74dcc777cf9943ba02872bcec737d05de017b Mon Sep 17 00:00:00 2001
From: Ankush Desai
Date: Mon, 15 Apr 2024 09:10:23 -0700
Subject: [PATCH 02/21] Improving the code with some cleanup. (#719)
* Disable trace logging to save disk space.
* Update feedback algorithm.
* fix feedback strategy.
* refactor.
* Remove experiment features.
---------
Co-authored-by: Ao Li
---
.../CheckerCore/Actors/ActorRuntime.cs | 2 +
.../CheckerCore/Actors/Events/Event.cs | 4 +
.../Actors/Logging/ActorRuntimeLogBase.cs | 124 ++++++
.../CheckerCore/CheckerConfiguration.cs | 23 +-
.../Coverage/ActivityCoverageReporter.cs | 0
.../Coverage/ActorRuntimeLogEventCoverage.cs | 0
.../Coverage/ActorRuntimeLogGraphBuilder.cs | 0
.../Feedback => }/Coverage/CoverageInfo.cs | 0
Src/PChecker/CheckerCore/Pattern/EventObj.cs | 22 --
.../Pattern/EventPatternObserver.cs | 188 ---------
Src/PChecker/CheckerCore/Pattern/IMatcher.cs | 10 -
.../CheckerCore/Specifications/Monitor.cs | 1 +
.../SystematicTesting/ControlledRuntime.cs | 16 -
.../{Coverage => }/ConflictOpMonitor.cs | 19 +-
.../Feedback/Coverage/AbstractSchedule.cs | 70 ----
.../Coverage/AbstractScheduleObserver.cs | 348 -----------------
.../Feedback/Coverage/EventPatternObserver.cs | 51 +++
.../Feedback/Coverage/ISendEventMonitor.cs | 7 -
.../Strategies/Feedback/Coverage/Operation.cs | 9 +
.../Feedback/Coverage/TimelineObserver.cs | 137 +------
.../Feedback/FeedbackGuidedStrategy.cs | 64 ++-
.../Generator/Mutator/PctcpScheduleMutator.cs | 19 -
.../Generator/PctcpScheduleGenerator.cs | 68 ----
.../Generator/RandomScheduleGenerator.cs | 4 +-
.../Feedback/IFeedbackGuidedStrategy.cs | 2 +-
.../Strategies/Feedback/MaxHeap.cs | 88 -----
.../Feedback/TwoStageFeedbackStrategy.cs | 36 --
.../Strategies/Probabilistic/PCTCP/Chain.cs | 33 --
.../Probabilistic/PCTCP/OperationWithId.cs | 3 -
.../Probabilistic/PCTCP/VectorClockWrapper.cs | 8 -
.../Probabilistic/PCTCPScheduler.cs | 366 ------------------
.../Strategies/Probabilistic/POSStrategy.cs | 48 ---
.../PrioritizedSchedulingStrategy.cs | 10 +-
.../Probabilistic/QLearningStrategy.cs | 6 +-
.../Strategies/Probabilistic/RFFScheduler.cs | 174 ---------
.../SystematicTesting/TestingEngine.cs | 189 ++++-----
.../Backend/CSharp/CSharpCodeGenerator.cs | 9 +-
.../PCommandLine/Options/PCheckerOptions.cs | 28 +-
Src/PRuntimes/PCSharpRuntime/PMachine.cs | 2 +
39 files changed, 334 insertions(+), 1854 deletions(-)
create mode 100644 Src/PChecker/CheckerCore/Actors/Logging/ActorRuntimeLogBase.cs
rename Src/PChecker/CheckerCore/{SystematicTesting/Strategies/Feedback => }/Coverage/ActivityCoverageReporter.cs (100%)
rename Src/PChecker/CheckerCore/{SystematicTesting/Strategies/Feedback => }/Coverage/ActorRuntimeLogEventCoverage.cs (100%)
rename Src/PChecker/CheckerCore/{SystematicTesting/Strategies/Feedback => }/Coverage/ActorRuntimeLogGraphBuilder.cs (100%)
rename Src/PChecker/CheckerCore/{SystematicTesting/Strategies/Feedback => }/Coverage/CoverageInfo.cs (100%)
delete mode 100644 Src/PChecker/CheckerCore/Pattern/EventObj.cs
delete mode 100644 Src/PChecker/CheckerCore/Pattern/EventPatternObserver.cs
delete mode 100644 Src/PChecker/CheckerCore/Pattern/IMatcher.cs
rename Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/{Coverage => }/ConflictOpMonitor.cs (84%)
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractSchedule.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractScheduleObserver.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/EventPatternObserver.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/Operation.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PctcpScheduleMutator.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PctcpScheduleGenerator.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/MaxHeap.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/TwoStageFeedbackStrategy.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/Chain.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/OperationWithId.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/VectorClockWrapper.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCPScheduler.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSStrategy.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RFFScheduler.cs
diff --git a/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs b/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs
index 1959d9c76e..690f06c901 100644
--- a/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs
+++ b/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs
@@ -264,6 +264,8 @@ private Actor CreateActor(ActorId id, Type type, string name, Actor creator, Gui
///
internal virtual void SendEvent(ActorId targetId, Event e, Actor sender, Guid opGroupId)
{
+ e.Sender = sender.ToString();
+ e.Receiver = targetId.ToString();
var enqueueStatus = EnqueueEvent(targetId, e, sender, opGroupId, out var target);
if (enqueueStatus is EnqueueStatus.EventHandlerNotRunning)
{
diff --git a/Src/PChecker/CheckerCore/Actors/Events/Event.cs b/Src/PChecker/CheckerCore/Actors/Events/Event.cs
index 132cc5c69b..ca9fe6b4d5 100644
--- a/Src/PChecker/CheckerCore/Actors/Events/Event.cs
+++ b/Src/PChecker/CheckerCore/Actors/Events/Event.cs
@@ -12,5 +12,9 @@ namespace PChecker.Actors.Events
public abstract class Event
{
public int Loc { get; set; }
+ public string? Sender;
+ public string? Receiver;
+ public string? State;
+ public int Index;
}
}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/Actors/Logging/ActorRuntimeLogBase.cs b/Src/PChecker/CheckerCore/Actors/Logging/ActorRuntimeLogBase.cs
new file mode 100644
index 0000000000..203a73464d
--- /dev/null
+++ b/Src/PChecker/CheckerCore/Actors/Logging/ActorRuntimeLogBase.cs
@@ -0,0 +1,124 @@
+using System;
+using PChecker.Actors.Events;
+
+namespace PChecker.Actors.Logging;
+
+internal abstract class ActorRuntimeLogBase : IActorRuntimeLog
+{
+ public virtual void OnCreateActor(ActorId id, string creatorName, string creatorType)
+ {
+ }
+
+ public virtual void OnCreateStateMachine(ActorId id, string creatorName, string creatorType)
+ {
+ }
+
+ public virtual void OnExecuteAction(ActorId id, string handlingStateName, string currentStateName,
+ string actionName)
+ {
+ }
+
+ public virtual void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName,
+ Event e,
+ Guid opGroupId, bool isTargetHalted)
+ {
+ }
+
+ public virtual void OnRaiseEvent(ActorId id, string stateName, Event e)
+ {
+ }
+
+ public virtual void OnEnqueueEvent(ActorId id, Event e)
+ {
+ }
+
+ public virtual void OnDequeueEvent(ActorId id, string stateName, Event e)
+ {
+ }
+
+ public virtual void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked)
+ {
+ }
+
+ public virtual void OnWaitEvent(ActorId id, string stateName, Type eventType)
+ {
+ }
+
+ public virtual void OnWaitEvent(ActorId id, string stateName, params Type[] eventTypes)
+ {
+ }
+
+ public virtual void OnStateTransition(ActorId id, string stateName, bool isEntry)
+ {
+ }
+
+ public virtual void OnGotoState(ActorId id, string currentStateName, string newStateName)
+ {
+ }
+
+ public virtual void OnDefaultEventHandler(ActorId id, string stateName)
+ {
+ }
+
+ public virtual void OnHalt(ActorId id, int inboxSize)
+ {
+ }
+
+ public virtual void OnHandleRaisedEvent(ActorId id, string stateName, Event e)
+ {
+ }
+
+ public virtual void OnPopStateUnhandledEvent(ActorId id, string stateName, Event e)
+ {
+ }
+
+ public virtual void OnExceptionThrown(ActorId id, string stateName, string actionName, Exception ex)
+ {
+ }
+
+ public virtual void OnExceptionHandled(ActorId id, string stateName, string actionName, Exception ex)
+ {
+ }
+
+ public virtual void OnCreateMonitor(string monitorType)
+ {
+ }
+
+ public virtual void OnMonitorExecuteAction(string monitorType, string stateName, string actionName)
+ {
+ }
+
+ public virtual void OnMonitorProcessEvent(string monitorType, string stateName, string senderName,
+ string senderType,
+ string senderStateName, Event e)
+ {
+ }
+
+ public virtual void OnMonitorRaiseEvent(string monitorType, string stateName, Event e)
+ {
+ }
+
+ public virtual void OnMonitorStateTransition(string monitorType, string stateName, bool isEntry, bool? isInHotState)
+ {
+ }
+
+ public virtual void OnMonitorError(string monitorType, string stateName, bool? isInHotState)
+ {
+ }
+
+ public virtual void OnRandom(object result, string callerName, string callerType)
+ {
+ }
+
+ public virtual void OnAssertionFailure(string error)
+ {
+ }
+
+ public virtual void OnStrategyDescription(string strategyName, string description)
+ {
+ }
+
+ public virtual void OnCompleted()
+ {
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/CheckerConfiguration.cs b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
index e27f18bb4c..57706a2b4f 100644
--- a/Src/PChecker/CheckerCore/CheckerConfiguration.cs
+++ b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
@@ -292,12 +292,6 @@ public int MaxSchedulingSteps
[DataMember]
public string JvmArgs;
- ///
- /// For feedback strategy, save input if the pattern are partially matched.
- ///
- [DataMember]
- public bool SavePartialMatch;
-
///
/// For feedback strategy, discard saved generators if the size of the buffer is greater than N.
///
@@ -305,23 +299,11 @@ public int MaxSchedulingSteps
public int DiscardAfter;
///
- /// For feedback strategy, schedule generator mutations based on diversity.
+ /// For QL strategy, schedule generator mutations based on diversity.
///
[DataMember]
public bool DiversityBasedPriority;
- ///
- /// For feedback strategy, ignore the pattern feedback.
- ///
- [DataMember]
- public bool IgnorePatternFeedback;
-
- ///
- /// For feedback strategy, use priority based sampling.
- ///
- [DataMember]
- public bool PriorityBasedSampling;
-
///
/// Enable conflict analysis for scheduling optimization.
///
@@ -373,11 +355,8 @@ protected CheckerConfiguration()
EnableColoredConsoleOutput = false;
DisableEnvironmentExit = true;
- SavePartialMatch = true;
DiscardAfter = 100;
DiversityBasedPriority = true;
- IgnorePatternFeedback = false;
- PriorityBasedSampling = true;
EnableConflictAnalysis = false;
PSymArgs = "";
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ActivityCoverageReporter.cs b/Src/PChecker/CheckerCore/Coverage/ActivityCoverageReporter.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ActivityCoverageReporter.cs
rename to Src/PChecker/CheckerCore/Coverage/ActivityCoverageReporter.cs
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ActorRuntimeLogEventCoverage.cs b/Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogEventCoverage.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ActorRuntimeLogEventCoverage.cs
rename to Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogEventCoverage.cs
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ActorRuntimeLogGraphBuilder.cs b/Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogGraphBuilder.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ActorRuntimeLogGraphBuilder.cs
rename to Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogGraphBuilder.cs
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/CoverageInfo.cs b/Src/PChecker/CheckerCore/Coverage/CoverageInfo.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/CoverageInfo.cs
rename to Src/PChecker/CheckerCore/Coverage/CoverageInfo.cs
diff --git a/Src/PChecker/CheckerCore/Pattern/EventObj.cs b/Src/PChecker/CheckerCore/Pattern/EventObj.cs
deleted file mode 100644
index 2accf8d86b..0000000000
--- a/Src/PChecker/CheckerCore/Pattern/EventObj.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using PChecker.Actors.Events;
-using PChecker.Specifications.Monitors;
-
-namespace PChecker.Matcher;
-
-public class EventObj
-{
- public Event Event;
- public string? Sender;
- public string? Receiver;
- public string State;
- public int Index;
-
- public EventObj(Event e, string? sender, string? receiver, string state, int index)
- {
- Event = e;
- Sender = sender;
- Receiver = receiver;
- State = state;
- Index = index;
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/Pattern/EventPatternObserver.cs b/Src/PChecker/CheckerCore/Pattern/EventPatternObserver.cs
deleted file mode 100644
index c0dfdaa26f..0000000000
--- a/Src/PChecker/CheckerCore/Pattern/EventPatternObserver.cs
+++ /dev/null
@@ -1,188 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using PChecker.Actors;
-using PChecker.Actors.Events;
-using PChecker.Actors.Logging;
-using PChecker.Matcher;
-
-namespace PChecker.Feedback;
-
-internal class EventPatternObserver : IActorRuntimeLog
-{
- private MethodInfo _matcher;
- private Dictionary _senderMap = new();
- private List _events = new();
- public EventPatternObserver(MethodInfo matcher)
- {
- _matcher = matcher;
- }
-
- public void OnCreateActor(ActorId id, string creatorName, string creatorType)
- {
-
- }
-
- public void OnCreateStateMachine(ActorId id, string creatorName, string creatorType)
- {
- }
-
- public void OnExecuteAction(ActorId id, string handlingStateName, string currentStateName, string actionName)
- {
-
- }
-
- public void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName, Event e,
- Guid opGroupId, bool isTargetHalted)
- {
- _senderMap[e] = senderName;
- }
-
- public void OnRaiseEvent(ActorId id, string stateName, Event e)
- {
-
- }
-
- public void OnEnqueueEvent(ActorId id, Event e)
- {
-
- }
-
- public void OnDequeueEvent(ActorId id, string stateName, Event e)
- {
- _events.Add(new EventObj(e, _senderMap.GetValueOrDefault(e), id.Name, stateName, _events.Count));
- }
-
-
- public void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked)
- {
-
- }
-
- public void OnWaitEvent(ActorId id, string stateName, Type eventType)
- {
-
- }
-
- public void OnWaitEvent(ActorId id, string stateName, params Type[] eventTypes)
- {
-
- }
-
- public void OnStateTransition(ActorId id, string stateName, bool isEntry)
- {
-
- }
-
- public void OnGotoState(ActorId id, string currentStateName, string newStateName)
- {
- }
-
- public void OnPushState(ActorId id, string currentStateName, string newStateName)
- {
-
- }
-
- public void OnPopState(ActorId id, string currentStateName, string restoredStateName)
- {
-
- }
-
- public void OnDefaultEventHandler(ActorId id, string stateName)
- {
-
- }
-
- public void OnHalt(ActorId id, int inboxSize)
- {
-
- }
-
- public void OnHandleRaisedEvent(ActorId id, string stateName, Event e)
- {
-
- }
-
- public void OnPopStateUnhandledEvent(ActorId id, string stateName, Event e)
- {
-
- }
-
- public void OnExceptionThrown(ActorId id, string stateName, string actionName, Exception ex)
- {
-
- }
-
- public void OnExceptionHandled(ActorId id, string stateName, string actionName, Exception ex)
- {
-
- }
-
- public void OnCreateMonitor(string monitorType)
- {
-
- }
-
- public void OnMonitorExecuteAction(string monitorType, string stateName, string actionName)
- {
-
- }
-
- public void OnMonitorProcessEvent(string monitorType, string stateName, string senderName, string senderType,
- string senderStateName, Event e)
- {
- _events.Add(new EventObj(e, senderName, null, stateName, _events.Count));
- }
-
- public void OnMonitorRaiseEvent(string monitorType, string stateName, Event e)
- {
-
- }
-
- public void OnMonitorStateTransition(string monitorType, string stateName, bool isEntry, bool? isInHotState)
- {
-
- }
-
- public void OnMonitorError(string monitorType, string stateName, bool? isInHotState)
- {
-
- }
-
- public void OnRandom(object result, string callerName, string callerType)
- {
-
- }
-
- public void OnAssertionFailure(string error)
- {
-
- }
-
- public void OnStrategyDescription(string strategyName, string description)
- {
-
- }
-
- public void OnCompleted()
- {
- }
-
- public virtual int ShouldSave()
- {
- return (int) _matcher.Invoke(null, new [] { _events });
- }
-
- public virtual bool IsMatched()
- {
- int result = (int) _matcher.Invoke(null, new [] { _events });
- return result == 1;
- }
-
-
- public void Reset()
- {
- _events.Clear();
- _senderMap.Clear();
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/Pattern/IMatcher.cs b/Src/PChecker/CheckerCore/Pattern/IMatcher.cs
deleted file mode 100644
index 2faa030882..0000000000
--- a/Src/PChecker/CheckerCore/Pattern/IMatcher.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System.Collections.Generic;
-using PChecker.Matcher;
-
-namespace PChecker.Feedback;
-
-public interface IMatcher
-{
-
- public int IsMatched(List events);
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/Specifications/Monitor.cs b/Src/PChecker/CheckerCore/Specifications/Monitor.cs
index acf62c8dc9..5314899c18 100644
--- a/Src/PChecker/CheckerCore/Specifications/Monitor.cs
+++ b/Src/PChecker/CheckerCore/Specifications/Monitor.cs
@@ -275,6 +275,7 @@ protected void Assert(bool predicate, string s, params object[] args)
///
internal void MonitorEvent(Event e, string senderName, string senderType, string senderState)
{
+ e.Sender = senderName;
Runtime.LogWriter.LogMonitorProcessEvent(GetType().FullName, CurrentStateName,
senderName, senderType, senderState, e);
HandleEvent(e);
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs b/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
index ac91696d2f..2ed17adb40 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
@@ -66,14 +66,6 @@ internal sealed class ControlledRuntime : ActorRuntime
///
internal readonly int? RootTaskId;
- ///
- /// The observer that extracts the timeline information of the scheduling.
- ///
- internal readonly TimelineObserver TimelineObserver = new();
-
- public List SendEventMonitors = new();
-
-
///
/// Returns the current hashed state of the monitors.
///
@@ -156,7 +148,6 @@ internal ControlledRuntime(CheckerConfiguration checkerConfiguration, ISchedulin
// Update the current asynchronous control flow with this runtime instance,
// allowing future retrieval in the same asynchronous call stack.
AssignAsyncControlFlowRuntime(this);
- RegisterLog(TimelineObserver);
}
///
@@ -471,10 +462,6 @@ private EnqueueStatus EnqueueEvent(ActorId targetId, Event e, Actor sender, Guid
Scheduler.ScheduledOperation.LastEvent = e;
Scheduler.ScheduledOperation.LastSentReceiver = targetId.ToString();
- foreach (var monitor in SendEventMonitors) {
- monitor.OnSendEvent(sender.Id, e.Loc, targetId, LogWriter.JsonLogger.VcGenerator);
- }
-
Scheduler.ScheduleNextEnabledOperation(AsyncOperationType.Send);
ResetProgramCounter(sender as StateMachine);
@@ -495,9 +482,6 @@ private EnqueueStatus EnqueueEvent(ActorId targetId, Event e, Actor sender, Guid
return EnqueueStatus.Dropped;
}
- foreach (var monitor in SendEventMonitors) {
- monitor.OnSendEventDone(sender.Id, e.Loc, targetId, LogWriter.JsonLogger.VcGenerator);
- }
var enqueueStatus = EnqueueEvent(target, e, sender, opGroupId);
if (enqueueStatus == EnqueueStatus.Dropped)
{
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ConflictOpMonitor.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/ConflictOpMonitor.cs
similarity index 84%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ConflictOpMonitor.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/ConflictOpMonitor.cs
index 561d7f0e86..00cef43310 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ConflictOpMonitor.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/ConflictOpMonitor.cs
@@ -1,15 +1,18 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using PChecker.Actors;
+using PChecker.Actors.Events;
using PChecker.Actors.Logging;
using PChecker.SystematicTesting.Operations;
namespace PChecker.Feedback;
-public class ConflictOpMonitor: ISendEventMonitor
+internal class ConflictOpMonitor: ActorRuntimeLogBase
{
+ public VectorClockGenerator VectorClockGenerator;
// This dictionary stores all operations received by a machine.
// Each operation is labeled with ActorId, source location, and its corresponding
@@ -18,12 +21,12 @@ public class ConflictOpMonitor: ISendEventMonitor
private Dictionary> conflictOps = new();
-
- public void OnSendEvent(ActorId sender, int loc, ActorId receiver, VectorClockGenerator currentVc)
+ public override void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName, Event e,
+ Guid opGroupId, bool isTargetHalted)
{
- var receiverKey = receiver.ToString();
- var senderKey = sender.ToString();
- var currentOp = new Operation(senderKey, receiverKey, loc);
+ var receiverKey = e.Receiver;
+ var senderKey = e.Sender;
+ var currentOp = new Operation(senderKey, receiverKey, e.Loc);
if (!incomingOps.ContainsKey(receiverKey))
{
incomingOps.Add(receiverKey, new HashSet<(Operation, Dictionary)>());
@@ -32,7 +35,7 @@ public void OnSendEvent(ActorId sender, int loc, ActorId receiver, VectorClockGe
- if (currentVc.ContextVcMap.TryGetValue(sender.Name, out var vectorClock))
+ if (VectorClockGenerator.ContextVcMap.TryGetValue(senderKey, out var vectorClock))
{
foreach (var op in opsSet)
@@ -52,8 +55,6 @@ public void OnSendEvent(ActorId sender, int loc, ActorId receiver, VectorClockGe
}
}
- public void OnSendEventDone(ActorId sender, int loc, ActorId receiver, VectorClockGenerator currentVc) {}
-
internal bool IsRacing(AsyncOperation op1, AsyncOperation op2)
{
if (op1.Type != AsyncOperationType.Send || op2.Type != AsyncOperationType.Send) {
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractSchedule.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractSchedule.cs
deleted file mode 100644
index 3d0b14d9d8..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractSchedule.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Security.Cryptography.X509Certificates;
-using PChecker.Actors;
-using PChecker.Random;
-
-
-enum State {
- PosReachR,
- PosExctdW,
- PosNoInfo,
- PosSat,
- NegExctdW,
- NegReachW,
- NegOtherW,
- NegNoInfo,
- NegUnsat,
-}
-
-public record Constraint(Operation op1, Operation op2, bool positive)
-{
- public override string ToString()
- {
- return $"({op1}, {op2}, {positive})";
- }
-}
-public record AbstractSchedule(HashSet constraints) {
-
- internal AbstractSchedule Mutate(List allConstraints, IRandomValueGenerator random)
- {
- List constraints = new(this.constraints);
-
- int op = random.Next(4);
- switch (op) {
- case 0: {
-
- int index = random.Next(allConstraints.Count);
- constraints.Add(allConstraints[index]);
- break;
- }
- case 1: {
- if (constraints.Count > 1) {
- int index = random.Next(constraints.Count);
- constraints.RemoveAt(index);
- index = random.Next(allConstraints.Count);
- constraints.Add(allConstraints[index]);
- }
- break;
- }
- case 2: {
- if (constraints.Count > 1) {
- int index = random.Next(constraints.Count);
- constraints.RemoveAt(index);
- }
- break;
- }
- case 3: {
- if (constraints.Count > 1) {
- int index = random.Next(constraints.Count);
- var c = constraints[index];
- constraints.RemoveAt(index);
- constraints.Add(new Constraint(c.op1, c.op2, !c.positive));
- }
- break;
- }
- }
- return new(constraints.ToHashSet());
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractScheduleObserver.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractScheduleObserver.cs
deleted file mode 100644
index 36723486f4..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/AbstractScheduleObserver.cs
+++ /dev/null
@@ -1,348 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using PChecker.Actors;
-using PChecker.Actors.Logging;
-using PChecker.SystematicTesting.Operations;
-
-internal class AbstractScheduleObserver : ISendEventMonitor
-{
- AbstractSchedule abstractSchedule;
- Dictionary> opQueue = new();
- Dictionary constraintState = new();
- public Dictionary> avoidSendTo = new();
- public Dictionary> avoidSchedule = new();
- public Dictionary> lookingForSchedule = new();
- public Dictionary> lookingForSendTo = new();
- public Dictionary> relevantConstraintsByReceiver = new();
- public Dictionary> relevantConstraintsByOp = new();
- public bool newConstraint = false;
-
- public Dictionary visitedConstraints = new();
- public Dictionary allVisitedConstraints = new();
-
- public void OnNewAbstractSchedule(AbstractSchedule schedule)
- {
- abstractSchedule = schedule;
- newConstraint = false;
-
- // Reset everything;
- opQueue.Clear();
- avoidSendTo.Clear();
- avoidSchedule.Clear();
- constraintState.Clear();
- lookingForSchedule.Clear();
- lookingForSendTo.Clear();
- relevantConstraintsByOp.Clear();
- relevantConstraintsByReceiver.Clear();
- visitedConstraints.Clear();
-
- foreach (var constraint in abstractSchedule.constraints) {
- if (constraint.positive) {
- constraintState[constraint] = State.PosNoInfo;
- } else {
- constraintState[constraint] = State.NegNoInfo;
- }
-
- if (!avoidSendTo.ContainsKey(constraint.op1.Receiver)) {
- avoidSendTo[constraint.op1.Receiver] = new();
- }
-
- if (!lookingForSendTo.ContainsKey(constraint.op1.Receiver)) {
- lookingForSendTo[constraint.op1.Receiver] = new();
- }
-
- if (!relevantConstraintsByReceiver.ContainsKey(constraint.op1.Receiver)) {
- relevantConstraintsByReceiver[constraint.op1.Receiver] = new();
- }
-
- if (!relevantConstraintsByOp.ContainsKey(constraint.op1)) {
- relevantConstraintsByOp[constraint.op1] = new();
- }
-
- if (!relevantConstraintsByOp.ContainsKey(constraint.op2)) {
- relevantConstraintsByOp[constraint.op2] = new();
- }
-
- if (!avoidSchedule.ContainsKey(constraint.op1)) {
- avoidSchedule[constraint.op1] = new();
- }
-
- if (!avoidSchedule.ContainsKey(constraint.op2)) {
- avoidSchedule[constraint.op2] = new();
- }
-
- if (!lookingForSchedule.ContainsKey(constraint.op1)) {
- lookingForSchedule[constraint.op1] = new();
- }
-
- if (!lookingForSchedule.ContainsKey(constraint.op2)) {
- lookingForSchedule[constraint.op2] = new();
- }
-
-
- relevantConstraintsByOp[constraint.op1].Add(constraint);
- relevantConstraintsByOp[constraint.op2].Add(constraint);
- }
- }
-
-
- public HashSet GetRelevantConstraints(Operation op)
- {
- var constraints = new HashSet();
- if (relevantConstraintsByReceiver.ContainsKey(op.Receiver)) {
- constraints.UnionWith(relevantConstraintsByReceiver[op.Receiver]);
- }
- if (relevantConstraintsByOp.ContainsKey(op)) {
- constraints.UnionWith(relevantConstraintsByOp[op]);
- }
- return constraints;
- }
-
- public void OnExecute(Operation op)
- {
- foreach (var constraint in GetRelevantConstraints(op))
- {
- var newState = constraintState[constraint];
- if (constraint.positive)
- {
- if (constraint.op1 == op)
- {
- newState = State.PosExctdW;
- }
- else if (constraintState[constraint] == State.PosReachR && constraint.op2 == op)
- {
- newState = State.PosNoInfo;
- }
- else if (constraintState[constraint] == State.PosExctdW && constraint.op2 == op)
- {
- newState = State.PosSat;
- relevantConstraintsByOp[constraint.op1].Remove(constraint);
- relevantConstraintsByOp[constraint.op2].Remove(constraint);
- }
- else if (constraintState[constraint] == State.PosExctdW && avoidSendTo[op.Receiver].Contains(constraint))
- {
- newState = State.PosNoInfo;
- }
- }
- else
- {
- if (constraint.op1 == op)
- {
- newState = State.NegExctdW;
- }
- else if (constraintState[constraint] == State.NegExctdW && constraint.op2 != op)
- {
- newState = State.NegOtherW;
- }
- else if (constraintState[constraint] == State.NegOtherW && constraint.op2 == op)
- {
- newState = State.NegOtherW;
- }
- else if (constraintState[constraint] == State.NegExctdW && constraint.op2 == op)
- {
- newState = State.NegUnsat;
- relevantConstraintsByOp[constraint.op1].Remove(constraint);
- relevantConstraintsByOp[constraint.op2].Remove(constraint);
- }
-
- }
- if (newState != constraintState[constraint])
- {
- CleanState(constraint);
- constraintState[constraint] = newState;
- UpdateLookFor(constraint);
- }
- }
-
- }
-
- public void OnNewOp(Operation op)
- {
- foreach (var constraint in GetRelevantConstraints(op))
- {
- var newState = constraintState[constraint];
- if (constraint.positive)
- {
- if (constraintState[constraint] != State.PosExctdW && constraint.op2 == op)
- {
- newState = State.PosReachR;
- }
- }
- else
- {
- if (constraint.op1 == op)
- {
- newState = State.NegReachW;
- }
- }
- if (newState != constraintState[constraint])
- {
- CleanState(constraint);
- constraintState[constraint] = newState;
- UpdateLookFor(constraint);
- }
- }
- }
-
- public void CleanState(Constraint constraint)
- {
- switch (constraintState[constraint])
- {
- case State.PosReachR:
- avoidSchedule[constraint.op2].Remove(constraint);
- lookingForSchedule[constraint.op1].Remove(constraint);
- break;
- case State.PosExctdW:
- lookingForSchedule[constraint.op2].Remove(constraint);
- avoidSendTo[constraint.op1.Receiver].Remove(constraint);
- relevantConstraintsByReceiver[constraint.op1.Receiver].Remove(constraint);
- break;
- case State.NegExctdW:
- avoidSchedule[constraint.op2].Remove(constraint);
- lookingForSendTo[constraint.op1.Receiver].Remove(constraint);
- relevantConstraintsByReceiver[constraint.op1.Receiver].Remove(constraint);
- break;
- case State.NegReachW:
- avoidSchedule[constraint.op1].Remove(constraint);
- break;
- case State.NegOtherW:
- lookingForSchedule[constraint.op2].Remove(constraint);
- break;
- }
- }
-
- public void UpdateLookFor(Constraint constraint)
- {
- switch (constraintState[constraint])
- {
- case State.PosReachR:
- avoidSchedule[constraint.op2].Add(constraint);
- lookingForSchedule[constraint.op1].Add(constraint);
- break;
- case State.PosExctdW:
- lookingForSchedule[constraint.op2].Add(constraint);
- avoidSendTo[constraint.op1.Receiver].Add(constraint);
- relevantConstraintsByReceiver[constraint.op1.Receiver].Add(constraint);
- break;
- case State.NegExctdW:
- avoidSchedule[constraint.op2].Add(constraint);
- lookingForSendTo[constraint.op1.Receiver].Add(constraint);
- relevantConstraintsByReceiver[constraint.op1.Receiver].Add(constraint);
- break;
- case State.NegReachW:
- avoidSchedule[constraint.op1].Add(constraint);
- break;
- case State.NegOtherW:
- lookingForSchedule[constraint.op2].Add(constraint);
- break;
- }
- }
-
- public void OnSendEvent(ActorId sender, int loc, ActorId receiver, VectorClockGenerator currentVc)
- {
- var receiverName = receiver.ToString();
- var senderName = sender.ToString();
-
- OnNewOp(new Operation(senderName, receiverName, loc));
- }
-
- public void OnSendEventDone(ActorId sender, int loc, ActorId receiver, VectorClockGenerator currentVc)
- {
- var receiverName = receiver.ToString();
- var senderName = sender.ToString();
-
- if (!opQueue.ContainsKey(receiverName))
- {
- opQueue[receiverName] = new();
- }
- var queue = opQueue[receiverName];
-
- queue.Add(new Operation(senderName, receiverName, loc));
- OnExecute(new Operation(senderName, receiverName, loc));
-
- if (queue.Count > 1) {
- var op1 = queue[queue.Count - 2];
- var op2 = queue[queue.Count - 1];
-
- var c = new Constraint(op1, op2, true);
-
- if (!visitedConstraints.ContainsKey(c)) {
- visitedConstraints[c] = 0;
- }
- visitedConstraints[c] += 1;
- }
- }
-
- public int GetTraceHash() {
- if (visitedConstraints.Count == 0) {
- return "".GetHashCode();
- }
- string s = visitedConstraints.ToList().Select(it => $"<{it.Key}, {it.Value}>").OrderBy(it => it).Aggregate((current, next) => current + "," + next);
- return s.GetHashCode();
- }
-
- public bool CheckNoveltyAndUpdate()
- {
- bool isNovel = false;
- foreach (var constraint in visitedConstraints) {
- if (!allVisitedConstraints.ContainsKey(constraint.Key))
- {
- allVisitedConstraints[constraint.Key] = 0;
- }
- if (constraint.Value > allVisitedConstraints[constraint.Key])
- {
- allVisitedConstraints[constraint.Key] = constraint.Value;
- isNovel = true;
- }
- }
- return isNovel;
- }
-
- public bool CheckAbstractTimelineSatisfied()
- {
- return constraintState.All(it => {
- if (it.Key.positive) {
- return it.Value == State.PosSat;
- } else {
- return it.Value != State.NegUnsat;
- }
- });
- }
-
- public bool ShouldAvoid(AsyncOperation op)
- {
- if (op.Type == AsyncOperationType.Send)
- {
- var operation = new Operation(op.Name, op.LastSentReceiver, op.LastEvent!.Loc);
- if (avoidSchedule.ContainsKey(operation))
- {
- return true;
- }
- if (avoidSendTo.ContainsKey(operation.Receiver)
- && avoidSendTo[operation.Receiver].Any(it => it.op2 != operation))
- {
- return true;
- }
- }
- return false;
- }
-
- public bool ShouldTake(AsyncOperation op)
- {
- if (op.Type == AsyncOperationType.Send)
- {
- var operation = new Operation(op.Name, op.LastSentReceiver, op.LastEvent!.Loc);
- if (lookingForSchedule.ContainsKey(operation))
- {
- return true;
- }
- if (lookingForSendTo.ContainsKey(operation.Receiver) &&
- lookingForSendTo[operation.Receiver].Any(it => it.op2 == operation))
- {
- return true;
- }
- return false;
- }
- return true;
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/EventPatternObserver.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/EventPatternObserver.cs
new file mode 100644
index 0000000000..61b74b57ea
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/EventPatternObserver.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using PChecker.Actors;
+using PChecker.Actors.Events;
+using PChecker.Actors.Logging;
+
+namespace PChecker.Feedback;
+
+internal class EventPatternObserver : ActorRuntimeLogBase
+{
+ private MethodInfo _matcher;
+ private List _events = new();
+
+ public EventPatternObserver(MethodInfo matcher)
+ {
+ _matcher = matcher;
+ }
+
+ public override void OnDequeueEvent(ActorId id, string stateName, Event e)
+ {
+ e.Index = _events.Count;
+ e.State = stateName;
+ _events.Add(e);
+ }
+
+ public override void OnMonitorProcessEvent(string monitorType, string stateName, string senderName, string senderType,
+ string senderStateName, Event e)
+ {
+ e.Index = _events.Count;
+ e.State = stateName;
+ _events.Add(e);
+ }
+
+ public virtual int ShouldSave()
+ {
+ return (int) _matcher.Invoke(null, new [] { _events });
+ }
+
+ public virtual bool IsMatched()
+ {
+ int result = (int) _matcher.Invoke(null, new [] { _events });
+ return result == 1;
+ }
+
+
+ public void Reset()
+ {
+ _events.Clear();
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ISendEventMonitor.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ISendEventMonitor.cs
index 394ddb3e9e..28014d7d24 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ISendEventMonitor.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ISendEventMonitor.cs
@@ -1,13 +1,6 @@
using PChecker.Actors;
using PChecker.Actors.Logging;
-public record Operation(string Sender, string Receiver, int Loc) {
- public override string ToString()
- {
- return $"<{Sender}, {Receiver}, {Loc}>";
- }
-
-}
public interface ISendEventMonitor {
public void OnSendEvent(ActorId sender, int loc, ActorId receiver, VectorClockGenerator currentVc);
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/Operation.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/Operation.cs
new file mode 100644
index 0000000000..4af176c918
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/Operation.cs
@@ -0,0 +1,9 @@
+namespace PChecker.Feedback;
+
+public record Operation(string Sender, string Receiver, int Loc) {
+ public override string ToString()
+ {
+ return $"<{Sender}, {Receiver}, {Loc}>";
+ }
+
+}
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/TimelineObserver.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/TimelineObserver.cs
index 0c0759e3ca..b4503e52a2 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/TimelineObserver.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/TimelineObserver.cs
@@ -7,7 +7,7 @@
namespace PChecker.Feedback;
-public class TimelineObserver: IActorRuntimeLog
+internal class TimelineObserver: ActorRuntimeLogBase
{
private HashSet<(string, string, string)> _timelines = new();
@@ -28,36 +28,7 @@ static TimelineObserver()
}
}
- public void OnCreateActor(ActorId id, string creatorName, string creatorType)
- {
-
- }
-
- public void OnCreateStateMachine(ActorId id, string creatorName, string creatorType)
- {
- }
-
- public void OnExecuteAction(ActorId id, string handlingStateName, string currentStateName, string actionName)
- {
-
- }
-
- public void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName, Event e,
- Guid opGroupId, bool isTargetHalted)
- {
- }
-
- public void OnRaiseEvent(ActorId id, string stateName, Event e)
- {
-
- }
-
- public void OnEnqueueEvent(ActorId id, Event e)
- {
-
- }
-
- public void OnDequeueEvent(ActorId id, string stateName, Event e)
+ public override void OnDequeueEvent(ActorId id, string stateName, Event e)
{
string actor = id.Type;
@@ -110,108 +81,4 @@ public List GetTimelineMinhash()
}
return minHash;
}
-
- public void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked)
- {
-
- }
-
- public void OnWaitEvent(ActorId id, string stateName, Type eventType)
- {
-
- }
-
- public void OnWaitEvent(ActorId id, string stateName, params Type[] eventTypes)
- {
-
- }
-
- public void OnStateTransition(ActorId id, string stateName, bool isEntry)
- {
-
- }
-
- public void OnGotoState(ActorId id, string currentStateName, string newStateName)
- {
- }
-
- public void OnDefaultEventHandler(ActorId id, string stateName)
- {
-
- }
-
- public void OnHalt(ActorId id, int inboxSize)
- {
-
- }
-
- public void OnHandleRaisedEvent(ActorId id, string stateName, Event e)
- {
-
- }
-
- public void OnPopStateUnhandledEvent(ActorId id, string stateName, Event e)
- {
-
- }
-
- public void OnExceptionThrown(ActorId id, string stateName, string actionName, Exception ex)
- {
-
- }
-
- public void OnExceptionHandled(ActorId id, string stateName, string actionName, Exception ex)
- {
-
- }
-
- public void OnCreateMonitor(string monitorType)
- {
-
- }
-
- public void OnMonitorExecuteAction(string monitorType, string stateName, string actionName)
- {
-
- }
-
- public void OnMonitorProcessEvent(string monitorType, string stateName, string senderName, string senderType,
- string senderStateName, Event e)
- {
-
- }
-
- public void OnMonitorRaiseEvent(string monitorType, string stateName, Event e)
- {
-
- }
-
- public void OnMonitorStateTransition(string monitorType, string stateName, bool isEntry, bool? isInHotState)
- {
-
- }
-
- public void OnMonitorError(string monitorType, string stateName, bool? isInHotState)
- {
-
- }
-
- public void OnRandom(object result, string callerName, string callerType)
- {
-
- }
-
- public void OnAssertionFailure(string error)
- {
-
- }
-
- public void OnStrategyDescription(string strategyName, string description)
- {
-
- }
-
- public void OnCompleted()
- {
- }
}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
index 7d3f4a82f7..358bfe3c9f 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
@@ -18,7 +18,7 @@ public record StrategyGenerator(TInput InputGenerator, TSchedule ScheduleGenerat
public record GeneratorRecord(int Priority, StrategyGenerator Generator, List MinHash);
- protected StrategyGenerator Generator;
+ internal StrategyGenerator Generator;
private readonly int _maxScheduledSteps;
@@ -28,14 +28,11 @@ public record GeneratorRecord(int Priority, StrategyGenerator Generator, List _savedGenerators = new ();
private int _pendingMutations = 0;
+ private bool _shouldExploreNew = false;
private HashSet _visitedGenerators = new HashSet();
private GeneratorRecord? _currentParent = null;
- private readonly bool _savePartialMatch;
- private readonly bool _diversityBasedPriority;
- private readonly bool _ignorePatternFeedback;
private readonly int _discardAfter;
- private readonly bool _priorityBasedSampling;
private System.Random _rnd = new System.Random();
@@ -54,11 +51,7 @@ public FeedbackGuidedStrategy(CheckerConfiguration checkerConfiguration, TInput
_maxScheduledSteps = checkerConfiguration.MaxFairSchedulingSteps;
}
Generator = new StrategyGenerator(input, schedule);
- _savePartialMatch = checkerConfiguration.SavePartialMatch;
- _diversityBasedPriority = checkerConfiguration.DiversityBasedPriority;
_discardAfter = checkerConfiguration.DiscardAfter;
- _ignorePatternFeedback = checkerConfiguration.IgnorePatternFeedback;
- _priorityBasedSampling = checkerConfiguration.PriorityBasedSampling;
}
///
@@ -136,12 +129,7 @@ private int ComputeDiversity(int timeline, List hash)
return 0;
}
- if (!_priorityBasedSampling)
- {
- return 20;
- }
-
- if (_savedGenerators.Count == 0 || !_diversityBasedPriority)
+ if (_savedGenerators.Count == 0)
{
return 20;
}
@@ -169,11 +157,10 @@ private int ComputeDiversity(int timeline, List hash)
///
/// This method observes the results of previous run and prepare for the next run.
///
- /// The ControlledRuntime of previous run.
- public virtual void ObserveRunningResults(EventPatternObserver patternObserver, ControlledRuntime runtime)
+ public virtual void ObserveRunningResults(EventPatternObserver patternObserver, TimelineObserver timelineObserver)
{
- var timelineHash = runtime.TimelineObserver.GetTimelineHash();
- var timelineMinhash = runtime.TimelineObserver.GetTimelineMinhash();
+ var timelineHash = timelineObserver.GetTimelineHash();
+ var timelineMinhash = timelineObserver.GetTimelineMinhash();
int diversityScore = ComputeDiversity(timelineHash, timelineMinhash);
@@ -183,18 +170,15 @@ public virtual void ObserveRunningResults(EventPatternObserver patternObserver,
}
int priority = 0;
- if (patternObserver == null || _ignorePatternFeedback || !_priorityBasedSampling)
+ if (patternObserver == null)
{
priority = diversityScore;
}
else
{
int coverageResult = patternObserver.ShouldSave();
- if (coverageResult == 1 || _savePartialMatch)
- {
- double coverageScore = 1.0 / coverageResult;
- priority = (int)(diversityScore * coverageScore);
- }
+ double coverageScore = 1.0 / coverageResult;
+ priority = (int)(diversityScore * coverageScore);
}
if (priority > 0)
@@ -221,7 +205,7 @@ public virtual void ObserveRunningResults(EventPatternObserver patternObserver,
_savedGenerators.Insert(index, record);
}
- if (_priorityBasedSampling && _savedGenerators.Count > _discardAfter)
+ if (_savedGenerators.Count > _discardAfter)
{
var last = _savedGenerators.Last();
_visitedGenerators.Remove(last);
@@ -245,44 +229,44 @@ private void PrepareNextInput()
}
else
{
- if (!_priorityBasedSampling && _pendingMutations == 0)
- {
- _currentParent = _savedGenerators[_rnd.Next(_savedGenerators.Count)];
- _pendingMutations = 50;
- }
-
- if (_currentParent == null)
+ if (_currentParent == null && !_shouldExploreNew)
{
_currentParent = _savedGenerators.First();
_visitedGenerators.Add(_currentParent);
- _pendingMutations = _currentParent.Priority;
_pendingMutations = 50;
}
if (_pendingMutations == 0)
{
+ _shouldExploreNew = false;
bool found = false;
foreach (var generator in _savedGenerators)
{
if (_visitedGenerators.Contains(generator)) continue;
_currentParent = generator;
_visitedGenerators.Add(generator);
- _pendingMutations = generator.Priority;
_pendingMutations = 50;
found = true;
}
if (!found)
{
- _visitedGenerators.Clear();
- _currentParent = _savedGenerators.First();
- _visitedGenerators.Add(_currentParent);
- _pendingMutations = _currentParent.Priority;
+ if (_rnd.NextDouble() < 0.5)
+ {
+ _visitedGenerators.Clear();
+ _currentParent = _savedGenerators.First();
+ _visitedGenerators.Add(_currentParent);
+ }
+ else
+ {
+ _shouldExploreNew = true;
+ _currentParent = null;
+ }
_pendingMutations = 50;
}
}
- Generator = MutateGenerator(_currentParent.Generator);
+ Generator = _shouldExploreNew ? NewGenerator() : MutateGenerator(_currentParent.Generator);
_pendingMutations -= 1;
}
}
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PctcpScheduleMutator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PctcpScheduleMutator.cs
deleted file mode 100644
index b057aeac5a..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PctcpScheduleMutator.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace PChecker.Generator.Mutator;
-
-internal class PctcpScheduleMutator: IMutator
-{
- private int _meanMutationCount = 5;
- private int _meanMutationSize = 5;
- private System.Random _random = new();
- public PctcpScheduleGenerator Mutate(PctcpScheduleGenerator prev)
- {
- return new PctcpScheduleGenerator(prev.Random,
- Utils.MutateRandomChoices(prev.PriorityChoices, _meanMutationCount, _meanMutationSize, _random),
- Utils.MutateRandomChoices(prev.SwitchPointChoices, _meanMutationCount, _meanMutationSize, _random),
- prev.MaxPrioritySwitchPoints,
- prev.ScheduleLength,
- prev.VcWrapper
- );
- }
-
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PctcpScheduleGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PctcpScheduleGenerator.cs
deleted file mode 100644
index 34ffe087d0..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PctcpScheduleGenerator.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using System;
-using System.Collections.Generic;
-using PChecker.Generator.Mutator;
-using PChecker.Generator.Object;
-using PChecker.SystematicTesting.Operations;
-using PChecker.SystematicTesting.Strategies.Probabilistic;
-using PChecker.SystematicTesting.Strategies.Probabilistic.pctcp;
-
-namespace PChecker.Generator;
-
-internal class PctcpScheduleGenerator: PCTCPScheduler, IScheduleGenerator
-{
-
- public System.Random Random;
- public RandomChoices PriorityChoices;
- public RandomChoices SwitchPointChoices;
-
- public PctcpScheduleGenerator(System.Random random, RandomChoices? priorityChoices, RandomChoices?
- switchPointChoices, int numSwitchPoints, int maxScheduleLength, VectorClockWrapper wrapper):
- base(numSwitchPoints, maxScheduleLength,
- new ParametricProvider(
- priorityChoices != null ? new RandomChoices(priorityChoices) : new RandomChoices(random),
- switchPointChoices != null ? new RandomChoices(switchPointChoices) : new
- RandomChoices(random)), wrapper)
- {
- Random = random;
- var provider = (ParametricProvider) Provider;
- PriorityChoices = provider.PriorityChoices;
- SwitchPointChoices = provider.SwitchPointChoices;
- }
- public PctcpScheduleGenerator(CheckerConfiguration checkerConfiguration, VectorClockWrapper wrapper):
- this(new System.Random((int?)checkerConfiguration.RandomGeneratorSeed ?? Guid.NewGuid().GetHashCode()), null,
- null, checkerConfiguration.StrategyBound, 0, wrapper)
- {
- }
-
- public PctcpScheduleGenerator Mutate()
- {
- return new PctcpScheduleMutator().Mutate(this);
- }
-
- public PctcpScheduleGenerator New()
- {
- return new PctcpScheduleGenerator(Random, null, null, MaxPrioritySwitchPoints, ScheduleLength, VcWrapper);
- }
-
- public PctcpScheduleGenerator Copy()
- {
- return new PctcpScheduleGenerator(Random, PriorityChoices, SwitchPointChoices, MaxPrioritySwitchPoints,
- ScheduleLength, VcWrapper);
- }
-
- public AsyncOperation? NextRandomOperation(List enabledOperations, AsyncOperation current)
- {
- if (GetNextOperation(current, enabledOperations, out var next)) {
- return next;
- } else {
- return null;
- }
- }
-
-
- public void PrepareForNextInput()
- {
- PrepareForNextIteration();
- }
-
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomScheduleGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomScheduleGenerator.cs
index 98f64b77a8..49d378c87c 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomScheduleGenerator.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomScheduleGenerator.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using PChecker.Generator.Mutator;
using PChecker.Generator.Object;
using PChecker.SystematicTesting.Operations;
@@ -23,8 +24,9 @@ public RandomScheduleGenerator(CheckerConfiguration checkerConfiguration):
{
}
- public AsyncOperation? NextRandomOperation(List enabledOperations, AsyncOperation current)
+ public AsyncOperation? NextRandomOperation(List ops, AsyncOperation current)
{
+ var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
if (enabledOperations.Count == 0)
{
return null;
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IFeedbackGuidedStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IFeedbackGuidedStrategy.cs
index 84f3eec289..f74b8b8b35 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IFeedbackGuidedStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IFeedbackGuidedStrategy.cs
@@ -6,7 +6,7 @@ namespace PChecker.SystematicTesting.Strategies.Feedback;
internal interface IFeedbackGuidedStrategy: ISchedulingStrategy
{
- public void ObserveRunningResults(EventPatternObserver patternObserver, ControlledRuntime runtime);
+ public void ObserveRunningResults(EventPatternObserver patternObserver, TimelineObserver timelineObserver);
public int TotalSavedInputs();
public void DumpStats(TextWriter writer);
}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/MaxHeap.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/MaxHeap.cs
deleted file mode 100644
index b04f504de4..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/MaxHeap.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace PChecker.SystematicTesting.Strategies.Feedback;
-
-public class MaxHeap
-{
- public readonly List Elements = new();
- private IComparer _comparer;
-
- public MaxHeap(IComparer cmp)
- {
- _comparer = cmp;
- }
-
- private int GetLeftChildIndex(int elementIndex) => 2 * elementIndex + 1;
- private int GetRightChildIndex(int elementIndex) => 2 * elementIndex + 2;
- private int GetParentIndex(int elementIndex) => (elementIndex - 1) / 2;
-
- private bool HasLeftChild(int elementIndex) => GetLeftChildIndex(elementIndex) < Elements.Count;
- private bool HasRightChild(int elementIndex) => GetRightChildIndex(elementIndex) < Elements.Count;
- private bool IsRoot(int elementIndex) => elementIndex == 0;
-
- private TValue GetLeftChild(int elementIndex) => Elements[GetLeftChildIndex(elementIndex)];
- private TValue GetRightChild(int elementIndex) => Elements[GetRightChildIndex(elementIndex)];
- private TValue GetParent(int elementIndex) => Elements[GetParentIndex(elementIndex)];
-
- private void Swap(int firstIndex, int secondIndex)
- {
- (Elements[firstIndex], Elements[secondIndex]) = (Elements[secondIndex], Elements[firstIndex]);
- }
-
- public TValue Peek()
- {
- return Elements[0];
- }
-
- public TValue Pop()
- {
- var result = Elements[0];
- Elements[0] = Elements[Elements.Count - 1];
- Elements.RemoveAt(Elements.Count - 1);
-
- ReCalculateDown();
-
- return result;
- }
-
- public void Add(TValue element)
- {
- Elements.Add(element);
- ReCalculateUp();
- }
-
- private void ReCalculateDown()
- {
- int index = 0;
- while (HasLeftChild(index))
- {
- var biggerIndex = GetLeftChildIndex(index);
- if (HasRightChild(index) &&
- _comparer.Compare(GetRightChild(index), GetLeftChild(index)) > 0)
- {
- biggerIndex = GetRightChildIndex(index);
- }
-
- if (_comparer.Compare(Elements[biggerIndex], Elements[index]) < 0)
- {
- break;
- }
-
- Swap(biggerIndex, index);
- index = biggerIndex;
- }
- }
-
- private void ReCalculateUp()
- {
- var index = Elements.Count - 1;
- while (!IsRoot(index) && _comparer.Compare(Elements[index], GetParent(index)) > 0)
- {
- var parentIndex = GetParentIndex(index);
- Swap(parentIndex, index);
- index = parentIndex;
- }
- }
-
-}
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/TwoStageFeedbackStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/TwoStageFeedbackStrategy.cs
deleted file mode 100644
index 3fdc1485ca..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/TwoStageFeedbackStrategy.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using PChecker.Generator;
-using PChecker.Feedback;
-
-namespace PChecker.SystematicTesting.Strategies.Feedback;
-
-
-internal class TwoStageFeedbackStrategy : FeedbackGuidedStrategy
- where TInput: IInputGenerator
- where TSchedule: IScheduleGenerator
-{
-
- private int _numScheduleMutationWithoutNewSaved = 0;
-
- // This number should be less than `FeedbackGuidedStrategy._maxMutationsWithoutNewSaved`
- private readonly int _maxScheduleMutationsWithoutNewSaved = 25;
- public TwoStageFeedbackStrategy(CheckerConfiguration checkerConfiguration, TInput input, TSchedule schedule) : base(checkerConfiguration, input, schedule)
- {
- }
-
- protected override StrategyGenerator MutateGenerator(StrategyGenerator prev)
- {
- if (_numScheduleMutationWithoutNewSaved > _maxScheduleMutationsWithoutNewSaved)
- {
- _numScheduleMutationWithoutNewSaved = 0;
- return new StrategyGenerator(
- Generator.InputGenerator.Mutate(),
- // do not mutate schedule to save time?
- Generator.ScheduleGenerator.Copy()
- );
- }
- return new StrategyGenerator(
- Generator.InputGenerator.Copy(),
- Generator.ScheduleGenerator.Mutate()
- );
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/Chain.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/Chain.cs
deleted file mode 100644
index add66d209d..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/Chain.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System.Collections.Generic;
-
-namespace PChecker.SystematicTesting.Strategies.Probabilistic.pctcp;
-
-public class Chain
-{
- public List Ops = new();
- public int CurrentIndex = 0;
-
- public OperationWithId CurrentOp() {
- if (CurrentIndex < Ops.Count)
- {
- return Ops[CurrentIndex];
- }
- return null;
- }
-
- public List SliceSuccessors(int op)
- {
- var index = Ops.FindIndex(it => it.Id == op);
- return Ops.GetRange(index, Ops.Count - index - 1);
- }
-
- public void AppendAll(List ops)
- {
- Ops.AddRange(ops);
- }
-
- public void RemoveAll(List ops)
- {
- Ops.RemoveAll(it => ops.Contains(it));
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/OperationWithId.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/OperationWithId.cs
deleted file mode 100644
index 343f83979c..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/OperationWithId.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace PChecker.SystematicTesting.Strategies.Probabilistic.pctcp;
-
-public record OperationWithId(string Sender, string Receiver, int Loc, int Id);
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/VectorClockWrapper.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/VectorClockWrapper.cs
deleted file mode 100644
index 46982c4d69..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCP/VectorClockWrapper.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using PChecker.Actors.Logging;
-
-namespace PChecker.SystematicTesting.Strategies.Probabilistic.pctcp;
-
-public class VectorClockWrapper
-{
- public VectorClockGenerator CurrentVC;
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCPScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCPScheduler.cs
deleted file mode 100644
index dd6c0fd540..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTCPScheduler.cs
+++ /dev/null
@@ -1,366 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using PChecker.Actors.Logging;
-using PChecker.IO.Debugging;
-using PChecker.SystematicTesting.Operations;
-using PChecker.SystematicTesting.Strategies.Probabilistic.pctcp;
-
-namespace PChecker.SystematicTesting.Strategies.Probabilistic;
-
-
-internal class PCTCPScheduler: PrioritizedScheduler
-{
- public readonly PriorizationProvider Provider;
-
- private int ScheduledSteps;
- public readonly int MaxPrioritySwitchPoints;
- public int ScheduleLength;
- private int _nextPriorityChangePoint;
- private int _numSwitchPointsLeft;
- private int _nextOperationId = 0;
- private Dictionary _chainedOperations = new();
- private List _chains = new();
- private Dictionary> _vectorClockMap = new();
- private Dictionary> _predMap = new();
- private Dictionary _operationMap = new();
- private Dictionary _chainMap = new();
- private Dictionary _nextOperationMap = new();
- internal VectorClockWrapper VcWrapper;
-
- public PCTCPScheduler(int maxPrioritySwitchPoints, int scheduleLength, PriorizationProvider provider,
- VectorClockWrapper vcWrapper)
- {
- Provider = provider;
- ScheduledSteps = 0;
- ScheduleLength = scheduleLength;
- MaxPrioritySwitchPoints = maxPrioritySwitchPoints;
- _numSwitchPointsLeft = maxPrioritySwitchPoints;
- VcWrapper = vcWrapper;
-
- double switchPointProbability = 0.1;
- if (ScheduleLength != 0)
- {
- switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
- }
- _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice());
- }
-
- public virtual bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
- {
- next = null;
- var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
- if (enabledOperations.Count == 0)
- {
- if (_nextPriorityChangePoint == ScheduledSteps)
- {
- MovePriorityChangePointForward();
- }
- return false;
- }
-
- var highestEnabledOp = GetPrioritizedOperation(enabledOperations, current);
- if (next is null)
- {
- next = highestEnabledOp;
- }
-
- ScheduledSteps++;
- return true;
- }
-
- private void OnNewOperation(AsyncOperation operation)
- {
- Dictionary vc;
- if (VcWrapper.CurrentVC.ContextVcMap.ContainsKey(operation.Name))
- {
- vc = VcWrapper.CurrentVC
- .ContextVcMap[operation.Name]
- .ToDictionary(entry => entry.Key, entry => entry.Value);
- }
- else
- {
- vc = new();
- }
-
- OperationWithId op;
- if (operation.Type == AsyncOperationType.Send)
- {
- op = new OperationWithId(operation.Name, operation.LastSentReceiver, operation
- .LastEvent!.Loc, _nextOperationId++);
- }
- else
- {
- op = new OperationWithId(operation.Name, "", 0, _nextOperationId++);
- }
-
- _vectorClockMap[op.Id] = vc;
- _chainedOperations[operation.Name] = op.Id;
- _operationMap[op.Id] = op;
- _predMap[op.Id] = new();
-
- for (int i = 0; i < op.Id - 1; i++)
- {
- if (IsLT(_vectorClockMap[i], _vectorClockMap[op.Id]))
- {
- _predMap[op.Id].Add(i);
- }
- }
-
- if (!PlaceInChains(op))
- {
- Chain newChain = new();
- newChain.Ops.Add(op);
- _chainMap[op.Id] = newChain;
- if (_chains.Count == 0)
- {
- _chains.Add(newChain);
- }
- else
- {
- var index = Provider.AssignPriority(_chains.Count);
- _chains.Insert(index, newChain);
- }
- }
- }
-
- private bool PlaceInChains(OperationWithId op)
- {
- // var currentQ = _chains.
- for (int i = 0; i < _chains.Count; i++)
- {
- var chain = _chains[i];
- if (chain.Ops.Count > 0)
- {
- var tail = chain.Ops.Last();
- if (IsLT(_vectorClockMap[tail.Id], _vectorClockMap[op.Id]))
- {
- chain.Ops.Add(op);
- _nextOperationMap[tail.Id] = op.Id;
- _chainMap[op.Id] = chain;
- return true;
- }
- }
- }
- return false;
- }
-
- bool IsLT(Dictionary vc1, Dictionary vc2)
- {
- bool hasLess = false;
- foreach (var key in vc1.Keys.Union(vc2.Keys))
- {
- var op1 = vc1.GetValueOrDefault(key, 0);
- var op2 = vc2.GetValueOrDefault(key, 0);
- if (op1 >= op2)
- {
- return false;
- }
-
- if (op1 < op2)
- {
- hasLess = true;
- }
- }
- return hasLess;
- }
-
- private void MovePriorityChangePointForward()
- {
- _nextPriorityChangePoint += 1;
- Debug.WriteLine(" Moving priority change to '{0}'.", _nextPriorityChangePoint);
- }
- private OperationWithId GetHighestPriorityEnabledOperation(IEnumerable choices)
- {
- OperationWithId highestPriorityOp = null;
- int currentPriority = Int32.MaxValue;
- int currentChainIndex = Int32.MaxValue;
- foreach (var op in choices)
- {
- var id = _chainedOperations[op.Name];
- var chain = _chainMap[id];
- var priotiy = _chains.IndexOf(chain);
- if (priotiy < currentPriority)
- {
- highestPriorityOp = _operationMap[id];
- currentPriority = priotiy;
- currentChainIndex = chain.Ops.IndexOf(highestPriorityOp);
- }
-
- if (priotiy == currentPriority)
- {
- var index = chain.Ops.IndexOf(_operationMap[id]);
- if (index < currentChainIndex)
- {
- highestPriorityOp = _operationMap[id];
- currentChainIndex = index;
- }
- }
- }
- return highestPriorityOp;
- }
-
- private (int, int, Dictionary) FindReducingSequence()
- {
- var queue = new Queue();
- foreach (var chain in _chains)
- {
- if (chain.Ops.Count > 0)
- {
- queue.Enqueue(chain.Ops.First().Id);
- }
- }
-
- var pairs = new Dictionary();
-
- while (queue.Count > 0)
- {
- var opId = queue.Dequeue();
- foreach (var chain in _chains)
- {
- if (chain == _chainMap[opId]) continue;
- if (chain.Ops.Count <= 0) continue;
- if (IsLT(_vectorClockMap[chain.Ops.Last().Id], _vectorClockMap[opId]))
- {
- return (chain.Ops.Last().Id, opId, pairs);
- }
- }
- var temp = _predMap[opId].Where(it => _nextOperationMap.ContainsKey(it)
- && !pairs.ContainsKey(_nextOperationMap[it]))
- .ToList();
- foreach (var predOp in temp)
- {
- queue.Enqueue(_nextOperationMap[predOp]);
- pairs[_nextOperationMap[predOp]] = (predOp, opId);
- }
-
- }
- return (-1, -1, pairs);
- }
-
- private void ReduceChains()
- {
- var (pred, op, pairs) = FindReducingSequence();
-
- if (pred == -1) return;
-
- do
- {
- var predChain = _chainMap[pred];
- var opChain = _chainMap[op];
- var ids = opChain.SliceSuccessors(op);
- predChain.Ops.AddRange(ids);
- opChain.Ops.RemoveAll(it => ids.Contains(it));
- foreach (var id in ids)
- {
- _chainMap[id.Id] = predChain;
- }
-
- _nextOperationMap[pred] = op;
-
- if (opChain.Ops.Count > 0)
- {
- _nextOperationMap.Remove(opChain.Ops.Last().Id);
- }
-
- if (!pairs.ContainsKey(op))
- {
- _chains.Remove(opChain);
- break;
- }
- pred = pairs[op].Item1;
- op = pairs[op].Item2;
- } while (true);
-
- }
-
- ///
- /// Returns the prioritized operation.
- ///
- private AsyncOperation GetPrioritizedOperation(List ops, AsyncOperation current)
- {
- bool newOpAdded = false;
- foreach (var op in ops.Where(op => !_chainedOperations.ContainsKey(op.Name)))
- {
- OnNewOperation(op);
- newOpAdded = true;
- }
-
- if (newOpAdded)
- {
- ReduceChains();
- }
-
-
- var prioritizedSchedulable = GetHighestPriorityEnabledOperation(ops);
- if (_nextPriorityChangePoint == ScheduledSteps)
- {
- if (ops.Count == 1)
- {
- MovePriorityChangePointForward();
- }
- else
- {
- var chain = _chainMap[prioritizedSchedulable.Id];
- _chains.Remove(chain);
- _chains.Add(chain);
-
- _numSwitchPointsLeft -= 1;
- // Update the next priority change point.
- if (_numSwitchPointsLeft > 0)
- {
- double switchPointProbability = 0.1;
- if (ScheduleLength != 0)
- {
- switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
- }
- _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice()) + ScheduledSteps;
- }
- }
- }
-
- AsyncOperation scheduledOperation = null;
- if (prioritizedSchedulable != null)
- {
- scheduledOperation = ops.First(it => it.Name == prioritizedSchedulable.Sender);
- _chainedOperations.Remove(scheduledOperation.Name);
- Debug.WriteLine(" scheduled operation: " + scheduledOperation.Name);
- }
-
- return scheduledOperation;
- }
-
- public void Reset()
- {
- ScheduleLength = 0;
- ScheduledSteps = 0;
- _chainedOperations.Clear();
- _vectorClockMap.Clear();
- _chains.Clear();
- _nextOperationMap.Clear();
- _nextOperationId = 0;
- }
-
- ///
- public virtual bool PrepareForNextIteration()
- {
- ScheduleLength = Math.Max(ScheduleLength, ScheduledSteps);
- ScheduledSteps = 0;
- _nextOperationId = 0;
- _numSwitchPointsLeft = MaxPrioritySwitchPoints;
- _chainedOperations.Clear();
- _vectorClockMap.Clear();
- _chains.Clear();
- _nextOperationMap.Clear();
- _chainMap.Clear();
-
- double switchPointProbability = 0.1;
- if (ScheduleLength != 0)
- {
- switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
- }
- _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice());
- return true;
- }
-
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSStrategy.cs
deleted file mode 100644
index 6968e1c6ee..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSStrategy.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using PChecker.Feedback;
-using PChecker.Random;
-using PChecker.SystematicTesting.Operations;
-
-namespace PChecker.SystematicTesting.Strategies.Probabilistic;
-
-internal class POSStrategy: POSScheduler, ISchedulingStrategy
-{
- ///
- /// Random value generator.
- ///
- private readonly IRandomValueGenerator RandomValueGenerator;
-
- public POSStrategy(int maxSteps, ConflictOpMonitor? monitor, IRandomValueGenerator random)
- : base(new RandomPriorizationProvider(random), monitor)
- {
- }
-
- public bool GetNextBooleanChoice(AsyncOperation current, int maxValue, out bool next)
- {
- throw new System.NotImplementedException();
- }
-
- public bool GetNextIntegerChoice(AsyncOperation current, int maxValue, out int next)
- {
- throw new System.NotImplementedException();
- }
-
- public int GetScheduledSteps()
- {
- throw new System.NotImplementedException();
- }
-
- public bool HasReachedMaxSchedulingSteps()
- {
- throw new System.NotImplementedException();
- }
-
- public bool IsFair()
- {
- throw new System.NotImplementedException();
- }
-
- public string GetDescription()
- {
- throw new System.NotImplementedException();
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedSchedulingStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedSchedulingStrategy.cs
index 72660d7f97..6f50c24677 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedSchedulingStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedSchedulingStrategy.cs
@@ -33,7 +33,7 @@ internal class PrioritizedSchedulingStrategy: ISchedulingStrategy
private int _scheduledSteps;
- private PrioritizedScheduler _scheduler;
+ internal readonly PrioritizedScheduler Scheduler;
///
/// Initializes a new instance of the class.
@@ -42,14 +42,14 @@ public PrioritizedSchedulingStrategy(int maxSteps, IRandomValueGenerator random,
{
RandomValueGenerator = random;
MaxScheduledSteps = maxSteps;
- _scheduler = scheduler;
+ Scheduler = scheduler;
}
///
public bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
{
_scheduledSteps++;
- return _scheduler.GetNextOperation(current, ops, out next);
+ return Scheduler.GetNextOperation(current, ops, out next);
}
///
@@ -100,7 +100,7 @@ public string GetDescription()
public bool PrepareForNextIteration() {
_scheduledSteps = 0;
- return _scheduler.PrepareForNextIteration();
+ return Scheduler.PrepareForNextIteration();
}
@@ -108,7 +108,7 @@ public bool PrepareForNextIteration() {
public void Reset()
{
_scheduledSteps = 0;
- _scheduler.Reset();
+ Scheduler.Reset();
}
}
}
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
index 4b23127301..64ed1674c0 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
@@ -396,10 +396,10 @@ private int ComputeDiversity(int timeline, List hash)
return (hash.Count - maxSim) * 10 + 20;
}
- public void ObserveRunningResults(EventPatternObserver patternObserver, ControlledRuntime runtime)
+ public void ObserveRunningResults(EventPatternObserver patternObserver, TimelineObserver timelineObserver)
{
- var timelineHash = runtime.TimelineObserver.GetTimelineHash();
- var timelineMinhash = runtime.TimelineObserver.GetTimelineMinhash();
+ var timelineHash = timelineObserver.GetTimelineHash();
+ var timelineMinhash = timelineObserver.GetTimelineMinhash();
int priority = 1;
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RFFScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RFFScheduler.cs
deleted file mode 100644
index 11d27c2e26..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RFFScheduler.cs
+++ /dev/null
@@ -1,174 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using PChecker.Feedback;
-using PChecker.Random;
-using PChecker.SystematicTesting.Operations;
-using PChecker.SystematicTesting.Strategies.Probabilistic;
-
-internal class ScheduleRecord
-{
- public int NumVisit {get; set; }
- public int FuzzLevel {get; set; }
- public int Priority {get; set;}
- public AbstractSchedule Schedule;
-
- public ScheduleRecord(int numVisit, int fuzzLevel, AbstractSchedule schedule) {
- NumVisit = numVisit;
- FuzzLevel = fuzzLevel;
- Schedule = schedule;
- }
-
-}
-internal class RFFScheduler: PrioritizedScheduler
-{
- // public List<(AbstractSchedule, )> savedSchedules = new();
- public Dictionary TraceRecords = new();
- public int SavedTraces = 0;
- public int TotalExec = 1;
- int Skip = 0;
- int Adj = 1;
- int SchedNonDets = 0;
- int parentIndex = 0;
- int count = 0;
- internal AbstractSchedule currentSchedule;
- internal AbstractScheduleObserver observer;
- internal List savedSchedules = new();
- public IRandomValueGenerator random;
- private POSScheduler _posScheduler;
-
- public RFFScheduler(IRandomValueGenerator random, ConflictOpMonitor monitor, AbstractScheduleObserver observer)
- {
- this.observer = observer;
- this.random = random;
- currentSchedule = new AbstractSchedule(new HashSet());
- observer.OnNewAbstractSchedule(currentSchedule);
- _posScheduler = new POSScheduler(new RandomPriorizationProvider(random), monitor);
- }
-
- public bool PrepareForNextIteration()
- {
- _posScheduler.PrepareForNextIteration();
- // We should always check novelty to update global states.
- if (observer.CheckNoveltyAndUpdate() || observer.CheckAbstractTimelineSatisfied())
- {
- int traceHash = observer.GetTraceHash();
-
- if (!TraceRecords.ContainsKey(traceHash))
- {
- TraceRecords[traceHash] = new ScheduleRecord(0, 0, currentSchedule);
- savedSchedules.Add(TraceRecords[traceHash]);
- }
- var record = TraceRecords[traceHash];
- record.NumVisit += 1;
-
- int u = TotalExec / (SavedTraces + Adj);
-
- int factor;
- if (record.NumVisit <= u)
- {
- if (record.FuzzLevel < 31)
- {
- record.FuzzLevel += 1;
- }
-
- factor = (1 << record.FuzzLevel) / u;
- Skip = 0;
- }
- else
- {
- factor = 0;
- Skip += 1;
- if (Skip >= SchedNonDets)
- {
- Skip = 0;
- Adj += 1;
- }
- }
- int PerfScore = Math.Min(factor * 1, 50);
- record.Priority = PerfScore;
- SavedTraces += 1;
- }
- TotalExec += 1;
-
-
- if (parentIndex == -1 && savedSchedules.Count > 0)
- {
- parentIndex = 0;
- }
-
- if (parentIndex == -1)
- {
- currentSchedule = currentSchedule.Mutate(observer.allVisitedConstraints.Keys.ToList(), random);
- return true;
- }
-
- if (count < savedSchedules[parentIndex].Priority)
- {
- currentSchedule = savedSchedules[parentIndex].Schedule.Mutate(observer.allVisitedConstraints.Keys.ToList(), random);
- count += 1;
- } else {
- parentIndex += 1;
- if (parentIndex >= savedSchedules.Count) {
- parentIndex = 0;
- }
- count = 0;
- }
-
- observer.OnNewAbstractSchedule(currentSchedule);
- return true;
- }
-
- public void Reset()
- {
- _posScheduler.Reset();
- }
-
- public bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
- {
- var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
- if (enabledOperations.Count == 0)
- {
- next = null;
- return false;
- }
- if (enabledOperations.Count == 1)
- {
- next = enabledOperations[0];
- return true;
- }
-
- var highPrioOps = new List();
- var normalPrioOps = new List();
- var lowPrioOps = new List();
- foreach (var op in enabledOperations)
- {
- var avoid = observer.ShouldAvoid(op);
- var take = observer.ShouldTake(op);
-
- if (avoid && !take)
- {
- lowPrioOps.Add(op);
- }
- else if (!avoid && take)
- {
- highPrioOps.Add(op);
- }
- else
- {
- normalPrioOps.Add(op);
- }
-
- }
-
- if (highPrioOps.Count > 0)
- {
- return _posScheduler.GetNextOperation(current, highPrioOps, out next);
- }
- if (normalPrioOps.Count > 0)
- {
- return _posScheduler.GetNextOperation(current, normalPrioOps, out next);
- }
- return _posScheduler.GetNextOperation(current, lowPrioOps, out next);
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
index ed668c03ea..876873d3e3 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
@@ -20,6 +20,7 @@
using PChecker.Coverage;
using PChecker.Feedback;
using PChecker.Generator;
+using PChecker.Generator.Mutator;
using PChecker.IO;
using PChecker.IO.Debugging;
using PChecker.IO.Logging;
@@ -29,7 +30,6 @@
using PChecker.SystematicTesting.Strategies.Exhaustive;
using PChecker.SystematicTesting.Strategies.Feedback;
using PChecker.SystematicTesting.Strategies.Probabilistic;
-using PChecker.SystematicTesting.Strategies.Probabilistic.pctcp;
using PChecker.SystematicTesting.Strategies.Special;
using PChecker.SystematicTesting.Traces;
using PChecker.Utilities;
@@ -65,13 +65,15 @@ public class TestingEngine
///
internal readonly ISchedulingStrategy Strategy;
+ ///
+ /// Pattern coverage observer if pattern is provided
+ ///
private EventPatternObserver? _eventPatternObserver;
- private ConflictOpMonitor? _conflictOpMonitor;
-
- private VectorClockWrapper? _vcWrapper;
-
- private AbstractScheduleObserver? _abstractScheduleObserver;
+ ///
+ /// Monitors conflict operations used by the POS Strategy.
+ ///
+ private ConflictOpMonitor? _conflictOpObserver;
///
/// Random value generator used by the scheduling strategies.
@@ -209,13 +211,14 @@ public static TestingEngine Create(CheckerConfiguration checkerConfiguration, As
if (checkerConfiguration.PatternSource.Length > 0)
{
var result = t.GetMethod(checkerConfiguration.PatternSource,
- BindingFlags.Public | BindingFlags.Static)!;
+ BindingFlags.Public | BindingFlags.Static)!;
eventMatcher = new EventPatternObserver(result);
}
}
catch
{
- Error.ReportAndExit($"Failed to get test method '{checkerConfiguration.TestCaseName}' from assembly '{assembly.FullName}'");
+ Error.ReportAndExit(
+ $"Failed to get test method '{checkerConfiguration.TestCaseName}' from assembly '{assembly.FullName}'");
}
return new TestingEngine(checkerConfiguration, testMethodInfo, eventMatcher);
@@ -248,7 +251,8 @@ public static TestingEngine Create(CheckerConfiguration checkerConfiguration, Fu
///
/// Creates a new systematic testing engine.
///
- public static TestingEngine Create(CheckerConfiguration checkerConfiguration, Func test) =>
+ public static TestingEngine Create(CheckerConfiguration checkerConfiguration,
+ Func test) =>
new TestingEngine(checkerConfiguration, test);
///
@@ -273,7 +277,8 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
///
/// Initializes a new instance of the class.
///
- private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo testMethodInfo, EventPatternObserver observer)
+ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo testMethodInfo,
+ EventPatternObserver observer)
{
_checkerConfiguration = checkerConfiguration;
TestMethodInfo = testMethodInfo;
@@ -300,9 +305,10 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
{
JsonVerboseLogs = new List>();
}
- if (checkerConfiguration.EnableConflictAnalysis || checkerConfiguration.SchedulingStrategy == "rff")
+
+ if (checkerConfiguration.EnableConflictAnalysis)
{
- _conflictOpMonitor = new ConflictOpMonitor();
+ _conflictOpObserver = new ConflictOpMonitor();
}
if (checkerConfiguration.SchedulingStrategy is "replay")
@@ -322,24 +328,10 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
Strategy = new PrioritizedSchedulingStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
RandomValueGenerator, scheduler);
}
- else if (checkerConfiguration.SchedulingStrategy is "pctcp")
- {
- _vcWrapper = new VectorClockWrapper();
- var scheduler = new PCTCPScheduler(checkerConfiguration.StrategyBound, 0,
- new RandomPriorizationProvider(RandomValueGenerator), _vcWrapper);
- Strategy = new PrioritizedSchedulingStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
- RandomValueGenerator, scheduler);
- }
else if (checkerConfiguration.SchedulingStrategy is "pos")
{
- var scheduler = new POSScheduler(new RandomPriorizationProvider(RandomValueGenerator), _conflictOpMonitor);
- Strategy = new PrioritizedSchedulingStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
- RandomValueGenerator, scheduler);
- }
- else if (checkerConfiguration.SchedulingStrategy is "rff")
- {
- _abstractScheduleObserver = new AbstractScheduleObserver();
- var scheduler = new RFFScheduler(RandomValueGenerator, _conflictOpMonitor, _abstractScheduleObserver);
+ var scheduler = new POSScheduler(new RandomPriorizationProvider(RandomValueGenerator),
+ _conflictOpObserver);
Strategy = new PrioritizedSchedulingStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
RandomValueGenerator, scheduler);
}
@@ -349,7 +341,8 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
var scheduler = new PCTScheduler(checkerConfiguration.StrategyBound, 0,
new RandomPriorizationProvider(RandomValueGenerator));
var prefixStrategy = new PrioritizedSchedulingStrategy(prefixLength, RandomValueGenerator, scheduler);
- var suffixStrategy = new RandomStrategy(checkerConfiguration.MaxFairSchedulingSteps, RandomValueGenerator);
+ var suffixStrategy =
+ new RandomStrategy(checkerConfiguration.MaxFairSchedulingSteps, RandomValueGenerator);
Strategy = new ComboStrategy(prefixStrategy, suffixStrategy);
}
else if (checkerConfiguration.SchedulingStrategy is "probabilistic")
@@ -369,32 +362,20 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
else if (checkerConfiguration.SchedulingStrategy is "feedback")
{
Strategy = new FeedbackGuidedStrategy(
- _checkerConfiguration, new RandomInputGenerator(checkerConfiguration), new RandomScheduleGenerator(checkerConfiguration));
- }
- else if (checkerConfiguration.SchedulingStrategy is "2stagefeedback")
- {
- Strategy = new TwoStageFeedbackStrategy(_checkerConfiguration, new RandomInputGenerator(checkerConfiguration), new RandomScheduleGenerator(checkerConfiguration));
+ _checkerConfiguration, new RandomInputGenerator(checkerConfiguration),
+ new RandomScheduleGenerator(checkerConfiguration));
}
else if (checkerConfiguration.SchedulingStrategy is "feedbackpct")
{
- Strategy = new FeedbackGuidedStrategy(_checkerConfiguration, new RandomInputGenerator(checkerConfiguration), new PctScheduleGenerator(checkerConfiguration));
- }
- else if (checkerConfiguration.SchedulingStrategy is "feedbackpctcp")
- {
- _vcWrapper = new VectorClockWrapper();
- Strategy = new FeedbackGuidedStrategy(_checkerConfiguration, new
- RandomInputGenerator(checkerConfiguration), new PctcpScheduleGenerator(checkerConfiguration, _vcWrapper));
+ Strategy = new FeedbackGuidedStrategy(_checkerConfiguration,
+ new RandomInputGenerator(checkerConfiguration), new PctScheduleGenerator(checkerConfiguration));
}
else if (checkerConfiguration.SchedulingStrategy is "feedbackpos")
{
Strategy = new FeedbackGuidedStrategy(
_checkerConfiguration,
new RandomInputGenerator(checkerConfiguration),
- new POSScheduleGenerator(_checkerConfiguration, _conflictOpMonitor));
- }
- else if (checkerConfiguration.SchedulingStrategy is "2stagefeedbackpct")
- {
- Strategy = new TwoStageFeedbackStrategy(_checkerConfiguration, new RandomInputGenerator(checkerConfiguration), new PctScheduleGenerator(checkerConfiguration));
+ new POSScheduleGenerator(_checkerConfiguration, _conflictOpObserver));
}
else if (checkerConfiguration.SchedulingStrategy is "portfolio")
{
@@ -493,7 +474,6 @@ _checkerConfiguration.SchedulingStrategy is "probabilistic" ||
{
try
{
-
// Invokes the user-specified initialization method.
TestMethodInfo.InitializeAllIterations();
watch = Stopwatch.StartNew();
@@ -510,7 +490,8 @@ _checkerConfiguration.SchedulingStrategy is "probabilistic" ||
RunNextIteration(i);
if (IsReplayModeEnabled || (!_checkerConfiguration.PerformFullExploration &&
- TestReport.NumOfFoundBugs > 0) || !Strategy.PrepareForNextIteration())
+ TestReport.NumOfFoundBugs > 0) ||
+ !Strategy.PrepareForNextIteration())
{
break;
}
@@ -554,7 +535,7 @@ _checkerConfiguration.SchedulingStrategy is "probabilistic" ||
var directory = _checkerConfiguration.OutputDirectory;
var file = Path.GetFileNameWithoutExtension(_checkerConfiguration.AssemblyToBeAnalyzed);
file += "_" + _checkerConfiguration.TestingProcessId;
- var jsonVerbosePath = directory + file + "_verbose.trace.json";
+ var jsonVerbosePath = directory + file + "_verbose.trace.json";
Logger.WriteLine("... Emitting verbose logs:");
Logger.WriteLine($"..... Writing {jsonVerbosePath}");
@@ -563,10 +544,29 @@ _checkerConfiguration.SchedulingStrategy is "probabilistic" ||
using var jsonStreamFile = File.Create(jsonVerbosePath);
JsonSerializer.Serialize(jsonStreamFile, JsonVerboseLogs, jsonSerializerConfig);
}
-
}, CancellationTokenSource.Token);
}
+ ///
+ /// Register required observers.
+ ///
+ private void RegisterObservers(ControlledRuntime runtime)
+ {
+ // Always output a json log of the error
+ JsonLogger = new JsonWriter();
+ runtime.SetJsonLogger(JsonLogger);
+ if (_eventPatternObserver != null)
+ {
+ runtime.RegisterLog(_eventPatternObserver);
+ }
+
+ if (_conflictOpObserver != null)
+ {
+ _conflictOpObserver.VectorClockGenerator = JsonLogger.VcGenerator;
+ runtime.RegisterLog(_conflictOpObserver);
+ }
+ }
+
///
/// Runs the next testing schedule.
///
@@ -586,6 +586,8 @@ private void RunNextIteration(int schedule)
// Runtime used to serialize and test the program in this schedule.
ControlledRuntime runtime = null;
+ TimelineObserver timelineObserver = new TimelineObserver();
+
// Logger used to intercept the program output if no custom logger
// is installed and if verbosity is turned off.
InMemoryLogger runtimeLogger = null;
@@ -599,27 +601,10 @@ private void RunNextIteration(int schedule)
ShouldEmitTrace = false;
// Creates a new instance of the controlled runtime.
runtime = new ControlledRuntime(_checkerConfiguration, Strategy, RandomValueGenerator);
- if (_conflictOpMonitor != null)
- {
- runtime.SendEventMonitors.Add(_conflictOpMonitor);
- }
- if (_abstractScheduleObserver != null)
- {
- runtime.SendEventMonitors.Add(_abstractScheduleObserver);
- }
- if (_eventPatternObserver != null)
- {
- runtime.RegisterLog(_eventPatternObserver);
- }
- // Always output a json log of the error
- JsonLogger = new JsonWriter();
- runtime.SetJsonLogger(JsonLogger);
+ runtime.RegisterLog(timelineObserver);
+ RegisterObservers(runtime);
- if (_vcWrapper != null)
- {
- _vcWrapper.CurrentVC = JsonLogger.VcGenerator;
- }
// If verbosity is turned off, then intercept the program log, and also redirect
// the standard output and error streams to a nul logger.
@@ -650,7 +635,7 @@ private void RunNextIteration(int schedule)
if (Strategy is IFeedbackGuidedStrategy strategy)
{
- strategy.ObserveRunningResults(_eventPatternObserver, runtime);
+ strategy.ObserveRunningResults(_eventPatternObserver, timelineObserver);
}
// Checks that no monitor is in a hot state at termination. Only
@@ -673,7 +658,7 @@ private void RunNextIteration(int schedule)
runtime.LogWriter.LogCompletion();
- GatherTestingStatistics(runtime);
+ GatherTestingStatistics(runtime, timelineObserver);
if (ShouldEmitTrace || (!IsReplayModeEnabled && TestReport.NumOfFoundBugs > 0))
{
@@ -689,7 +674,6 @@ private void RunNextIteration(int schedule)
TryEmitTraces(_checkerConfiguration.OutputDirectory, "trace_0");
}
}
-
}
finally
{
@@ -724,10 +708,11 @@ private void RunNextIteration(int schedule)
{
runtime.RemoveLog(_eventPatternObserver);
}
+
runtimeLogger?.Dispose();
runtime?.Dispose();
_eventPatternObserver?.Reset();
- _conflictOpMonitor?.Reset();
+ _conflictOpObserver?.Reset();
}
}
@@ -757,37 +742,42 @@ public string GetReport()
return TestReport.GetText(_checkerConfiguration, "...");
}
- public void TryEmitTimeline(TimelineObserver observer)
- {
- TimelineFileStream.WriteLine(observer.GetTimeline());
- }
-
///
/// Returns an object where the value null is replaced with "null"
///
- public object RecursivelyReplaceNullWithString(object obj) {
- if (obj == null) {
+ public object RecursivelyReplaceNullWithString(object obj)
+ {
+ if (obj == null)
+ {
return "null";
}
- if (obj is Dictionary dictionary) {
+
+ if (obj is Dictionary dictionary)
+ {
var newDictionary = new Dictionary();
- foreach (var item in dictionary) {
+ foreach (var item in dictionary)
+ {
var newVal = RecursivelyReplaceNullWithString(item.Value);
if (newVal != null)
newDictionary[item.Key] = newVal;
}
+
return newDictionary;
}
- else if (obj is List
- private void GatherTestingStatistics(ControlledRuntime runtime)
+ private void GatherTestingStatistics(ControlledRuntime runtime, TimelineObserver timelineObserver)
{
var report = runtime.Scheduler.GetReport();
if (_checkerConfiguration.ReportActivityCoverage)
@@ -1017,7 +1009,6 @@ private void GatherTestingStatistics(ControlledRuntime runtime)
shouldSave = _eventPatternObserver.ShouldSave();
TestReport.ValidScheduling.TryAdd(shouldSave, 0);
TestReport.ValidScheduling[shouldSave] += 1;
-
}
if (shouldSave == 1)
@@ -1026,15 +1017,7 @@ private void GatherTestingStatistics(ControlledRuntime runtime)
report.CoverageInfo.Merge(coverageInfo);
TestReport.Merge(report);
- if (TestReport.ExploredTimelines.Add(runtime.TimelineObserver.GetTimelineHash()))
- {
- // if (_checkerConfiguration.IsVerbose)
- // {
- // Logger.WriteLine($"... New timeline observed: {runtime.TimelineObserver.GetTimeline()}");
- // }
- TryEmitTimeline(runtime.TimelineObserver);
- ShouldEmitTrace = true;
- }
+ TestReport.ExploredTimelines.Add(timelineObserver.GetTimelineHash());
// Also save the graph snapshot of the last iteration, if there is one.
Graph = coverageInfo.CoverageGraph;
// Also save the graph snapshot of the last schedule, if there is one.
@@ -1057,15 +1040,13 @@ private void ConstructReproducableTrace(ControlledRuntime runtime)
if (_checkerConfiguration.IsLivenessCheckingEnabled)
{
stringBuilder.Append("--liveness-temperature-threshold:" +
- _checkerConfiguration.LivenessTemperatureThreshold).
- Append(Environment.NewLine);
+ _checkerConfiguration.LivenessTemperatureThreshold).Append(Environment.NewLine);
}
if (!string.IsNullOrEmpty(_checkerConfiguration.TestCaseName))
{
stringBuilder.Append("--test-method:" +
- _checkerConfiguration.TestCaseName).
- Append(Environment.NewLine);
+ _checkerConfiguration.TestCaseName).Append(Environment.NewLine);
}
for (var idx = 0; idx < runtime.Scheduler.ScheduleTrace.Count; idx++)
@@ -1101,7 +1082,9 @@ private string[] GetScheduleForReplay(out bool isFair)
string[] scheduleDump;
if (_checkerConfiguration.ScheduleTrace.Length > 0)
{
- scheduleDump = _checkerConfiguration.ScheduleTrace.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
+ scheduleDump =
+ _checkerConfiguration.ScheduleTrace.Split(new string[] { Environment.NewLine },
+ StringSplitOptions.None);
}
else
{
diff --git a/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs b/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs
index fa2bd5fb1a..398bee9cfc 100644
--- a/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs
+++ b/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs
@@ -153,7 +153,6 @@ private void WriteSourcePrologue(CompilationContext context, StringWriter output
{
context.WriteLine(output, "using PChecker;");
context.WriteLine(output, "using PChecker.Actors;");
- context.WriteLine(output, "using PChecker.Matcher;");
context.WriteLine(output, "using PChecker.Actors.Events;");
context.WriteLine(output, "using PChecker.Runtime;");
context.WriteLine(output, "using PChecker.Specifications;");
@@ -724,7 +723,7 @@ private void WriteFunction(CompilationContext context, StringWriter output, Func
}
else if (function.Role == FunctionRole.Scenario)
{
- functionParameters = "List events";
+ functionParameters = "List events";
}
else
{
@@ -811,7 +810,7 @@ private void WriteScenario(CompilationContext context, StringWriter output, Func
int numOfStmt = function.Body.Statements.Count + 1;
context.WriteLine(output, $"int state = {numOfStmt};");
var eventPredicates = string.Join(" or ", function.Signature.ParameterEvents.Select(it => it.Name));
- context.WriteLine(output, $"events = events.Where(it => it.Event is {eventPredicates}).ToList();");
+ context.WriteLine(output, $"events = events.Where(it => it is {eventPredicates}).ToList();");
WriteConstraintsRecursive(context, output, function, 0, new HashSet(), 0);
context.WriteLine(output, "return state;");
}
@@ -830,8 +829,8 @@ private void WriteConstraintsRecursive(CompilationContext context, StringWriter
var paramName = context.Names.GetNameForDecl(param);
context.WriteLine(output, $"for (var i{index} = {start} ; i{index} < events.Count; i{index} ++) " + "{");
context.WriteLine(output, $"var {paramName}_obj = events[i{index}];");
- context.WriteLine(output, $"if ({paramName}_obj.Event is not {e.Name}) continue;");
- context.WriteLine(output, $"var {paramName} = ((PEvent) {paramName}_obj.Event).Payload;");
+ context.WriteLine(output, $"if ({paramName}_obj is not {e.Name}) continue;");
+ context.WriteLine(output, $"var {paramName} = ((PEvent) {paramName}_obj).Payload;");
foreach (var bodyStatement in function.Body.Statements)
{
diff --git a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
index f50d9eefa1..22eb088be1 100644
--- a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
+++ b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
@@ -55,21 +55,15 @@ internal PCheckerOptions()
var schedulingGroup = Parser.GetOrCreateGroup("scheduling", "Search prioritization options");
schedulingGroup.AddArgument("sch-random", null, "Choose the random scheduling strategy (this is the default)", typeof(bool));
schedulingGroup.AddArgument("sch-feedback", null, "Choose the random scheduling strategy with feedback mutation", typeof(bool));
- schedulingGroup.AddArgument("sch-2stagefeedback", null, "Choose the random scheduling strategy with 2 stage feedback mutation", typeof(bool));
schedulingGroup.AddArgument("sch-feedbackpct", null, "Choose the PCT scheduling strategy with feedback mutation", typeof(uint));
- schedulingGroup.AddArgument("sch-feedbackpctcp", null, "Choose the PCT scheduling strategy with feedback mutation", typeof(uint));
schedulingGroup.AddArgument("sch-feedbackpos", null,
- "Choose the PCT scheduling strategy with feedback mutation", typeof(bool));
- schedulingGroup.AddArgument("sch-rff", null, "Choose the RFF scheduling strategy", typeof(bool));
- schedulingGroup.AddArgument("sch-2stagefeedbackpct", null, "Choose the PCT scheduling strategy with 2 stage feedback mutation", typeof(uint));
+ "Choose the POS scheduling strategy with feedback mutation", typeof(bool));
schedulingGroup.AddArgument("sch-probabilistic", "sp", "Choose the probabilistic scheduling strategy with given probability for each scheduling decision where the probability is " +
"specified as the integer N in the equation 0.5 to the power of N. So for N=1, the probability is 0.5, for N=2 the probability is 0.25, N=3 you get 0.125, etc.", typeof(uint));
schedulingGroup.AddArgument("sch-pct", null, "Choose the PCT scheduling strategy with given maximum number of priority switch points", typeof(uint));
- schedulingGroup.AddArgument("sch-pctcp", null, "Choose the PCT scheduling strategy with given maximum number of priority switch points", typeof(uint));
- schedulingGroup.AddArgument("sch-pos", null,
- "Choose the PCT scheduling strategy with given maximum number of priority switch points", typeof(bool));
+ schedulingGroup.AddArgument("sch-pos", null, "Choose the POS scheduling strategy", typeof(bool));
schedulingGroup.AddArgument("sch-fairpct", null, "Choose the fair PCT scheduling strategy with given maximum number of priority switch points", typeof(uint));
schedulingGroup.AddArgument("sch-rl", null, "Choose the reinforcement learning (RL) scheduling strategy", typeof(bool)).IsHidden = true;
var schCoverage = schedulingGroup.AddArgument("sch-coverage", null, "Choose the scheduling strategy for coverage mode (options: learn, random, dfs, stateless). (default: learn)");
@@ -88,11 +82,7 @@ internal PCheckerOptions()
advancedGroup.AddArgument("psym-args", null, "Specify a concatenated list of additional PSym-specific arguments to pass, each starting with a colon").IsHidden = true;
advancedGroup.AddArgument("jvm-args", null, "Specify a concatenated list of PSym-specific JVM arguments to pass, each starting with a colon").IsHidden = true;
advancedGroup.AddArgument("pattern", null, "The name of the pattern matcher generator", typeof(string));
- advancedGroup.AddArgument("no-partial-match", null, "For feedback strategy, do not save a schedule if the pattern is partially matched", typeof(bool));
advancedGroup.AddArgument("discard-after", null, "For feedback strategy, discard saved generators after saving N inputs", typeof(int));
- advancedGroup.AddArgument("fixed-priority", null, "For feedback strategy, schedule generator mutations based on diversity", typeof(bool));
- advancedGroup.AddArgument("ignore-pattern", null, "For feedback strategy, ignore the pattern feedback", typeof(bool));
- advancedGroup.AddArgument("no-priority-based", null, "For feedback strategy, disable priority based sampling.", typeof(bool));
advancedGroup.AddArgument("conflict-analysis", null, "Enable POS conflict analysis.", typeof(bool));
}
@@ -342,21 +332,12 @@ private static void UpdateConfigurationWithParsedArgument(CheckerConfiguration c
case "pattern":
checkerConfiguration.PatternSource = (string) option.Value;
break;
- case "no-partial-match":
- checkerConfiguration.SavePartialMatch = false;
- break;
case "discard-after":
checkerConfiguration.DiscardAfter = (int) option.Value;
break;
case "fixed-priority":
checkerConfiguration.DiversityBasedPriority = false;
break;
- case "ignore-pattern":
- checkerConfiguration.IgnorePatternFeedback = true;
- break;
- case "no-priority-based":
- checkerConfiguration.PriorityBasedSampling = false;
- break;
case "conflict-analysis":
checkerConfiguration.EnableConflictAnalysis = true;
break;
@@ -386,13 +367,9 @@ private static void SanitizeConfiguration(CheckerConfiguration checkerConfigurat
if (checkerConfiguration.SchedulingStrategy != "portfolio" &&
checkerConfiguration.SchedulingStrategy != "random" &&
- checkerConfiguration.SchedulingStrategy != "pctcp" &&
checkerConfiguration.SchedulingStrategy != "feedback" &&
checkerConfiguration.SchedulingStrategy != "feedbackpct" &&
- checkerConfiguration.SchedulingStrategy != "feedbackpctcp" &&
checkerConfiguration.SchedulingStrategy != "feedbackpos" &&
- checkerConfiguration.SchedulingStrategy != "2stagefeedback" &&
- checkerConfiguration.SchedulingStrategy != "2stagefeedbackpct" &&
checkerConfiguration.SchedulingStrategy != "pct" &&
checkerConfiguration.SchedulingStrategy != "pos" &&
checkerConfiguration.SchedulingStrategy != "fairpct" &&
@@ -401,7 +378,6 @@ private static void SanitizeConfiguration(CheckerConfiguration checkerConfigurat
checkerConfiguration.SchedulingStrategy != "replay" &&
checkerConfiguration.SchedulingStrategy != "learn" &&
checkerConfiguration.SchedulingStrategy != "dfs" &&
- checkerConfiguration.SchedulingStrategy != "rff" &&
checkerConfiguration.SchedulingStrategy != "stateless") {
Error.CheckerReportAndExit("Please provide a scheduling strategy (see --sch* options)");
}
diff --git a/Src/PRuntimes/PCSharpRuntime/PMachine.cs b/Src/PRuntimes/PCSharpRuntime/PMachine.cs
index c8300ef401..2816a97d01 100644
--- a/Src/PRuntimes/PCSharpRuntime/PMachine.cs
+++ b/Src/PRuntimes/PCSharpRuntime/PMachine.cs
@@ -86,6 +86,8 @@ public void TrySendEvent(PMachineValue target, Event ev, object payload = null)
var oneArgConstructor = ev.GetType().GetConstructors().First(x => x.GetParameters().Length > 0);
ev = (Event)oneArgConstructor.Invoke(new[] { payload , ev.Loc});
+ ev.Sender = Id.ToString();
+ ev.Receiver = target.Id.ToString();
AnnounceInternal(ev);
SendEvent(target.Id, ev);
}
From 3f4781a29a524833be808a1901fe6800aa323e65 Mon Sep 17 00:00:00 2001
From: Ao Li <5557706+aoli-al@users.noreply.github.com>
Date: Thu, 25 Apr 2024 14:05:34 -0400
Subject: [PATCH 03/21] PR cleanup (#723)
* Added support for generating a warning when spec handles an event but does not add it in its observes list (#716)
* Create custom converter for JSON serialization in .NET8 (#717)
* Create custom converter for JSON serialization in .NET8
* Add check for different dictionary type for null replacement
---------
Co-authored-by: Eric Hua
---------
Co-authored-by: Ankush Desai
Co-authored-by: Eric Hua
Co-authored-by: Eric Hua
---
.../SystematicTesting/TestingEngine.cs | 36 +++++++++++++++----
.../DefaultTranslationErrorHandler.cs | 5 +++
.../CompilerCore/ITranslationErrorHandler.cs | 2 ++
.../CompilerCore/TypeChecker/Analyzer.cs | 2 +-
.../TypeChecker/MachineChecker.cs | 23 +++++++++++-
.../Correct/monitorobserves/observes.p | 14 ++++++++
6 files changed, 73 insertions(+), 9 deletions(-)
create mode 100644 Tst/RegressionTests/Feature1SMLevelDecls/Correct/monitorobserves/observes.p
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
index 876873d3e3..18042472c6 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
@@ -113,9 +113,25 @@ public class TestingEngine
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
- WriteIndented = true
+ WriteIndented = true,
+ Converters = { new EncodingConverter() }
};
+ internal class EncodingConverter : JsonConverter
+ {
+ public override Encoding Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ var name = reader.GetString();
+ if (name == null)
+ return null;
+ return Encoding.GetEncoding(name);
+ }
+ public override void Write(Utf8JsonWriter writer, Encoding value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value.WebName);
+ }
+ }
+
///
/// The profiler.
///
@@ -751,12 +767,18 @@ public object RecursivelyReplaceNullWithString(object obj)
{
return "null";
}
-
- if (obj is Dictionary dictionary)
- {
+ if (obj is Dictionary dictionaryStr) {
var newDictionary = new Dictionary();
- foreach (var item in dictionary)
- {
+ foreach (var item in dictionaryStr) {
+ var newVal = RecursivelyReplaceNullWithString(item.Value);
+ if (newVal != null)
+ newDictionary[item.Key] = newVal;
+ }
+ return newDictionary;
+ }
+ else if (obj is Dictionary dictionaryInt) {
+ var newDictionary = new Dictionary();
+ foreach (var item in dictionaryInt) {
var newVal = RecursivelyReplaceNullWithString(item.Value);
if (newVal != null)
newDictionary[item.Key] = newVal;
@@ -1156,4 +1178,4 @@ public void SetLogger(TextWriter logger)
ErrorReporter.Logger = logger;
}
}
-}
\ No newline at end of file
+}
diff --git a/Src/PCompiler/CompilerCore/DefaultTranslationErrorHandler.cs b/Src/PCompiler/CompilerCore/DefaultTranslationErrorHandler.cs
index ccacf6fcfd..4aef965ae9 100644
--- a/Src/PCompiler/CompilerCore/DefaultTranslationErrorHandler.cs
+++ b/Src/PCompiler/CompilerCore/DefaultTranslationErrorHandler.cs
@@ -334,5 +334,10 @@ private string DeclarationName(IPDecl method)
{
return method.Name.Length > 0 ? method.Name : $"at {locationResolver.GetLocation(method.SourceLocation)}";
}
+
+ public string SpecObservesSetIncompleteWarning(ParserRuleContext ctx, PEvent ev, Machine machine)
+ {
+ return $"[!Warning!]\n[{locationResolver.GetLocation(ctx, ctx.start)}] Event {ev.Name} is not in the observes list of the spec machine {machine.Name}. The event-handler is never triggered as the event is not observed by the spec.\n[!Warning!]";
+ }
}
}
\ No newline at end of file
diff --git a/Src/PCompiler/CompilerCore/ITranslationErrorHandler.cs b/Src/PCompiler/CompilerCore/ITranslationErrorHandler.cs
index 00e12c244f..402a5fc5d6 100644
--- a/Src/PCompiler/CompilerCore/ITranslationErrorHandler.cs
+++ b/Src/PCompiler/CompilerCore/ITranslationErrorHandler.cs
@@ -117,5 +117,7 @@ Exception DuplicateStartState(
Exception IllegalChooseSubExprType(PParser.ChooseExprContext context, PLanguageType subExprType);
Exception IllegalFunctionUsedInSpecMachine(Function function, Machine callerOwner);
+
+ String SpecObservesSetIncompleteWarning(ParserRuleContext loc, PEvent ev, Machine machine);
}
}
\ No newline at end of file
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Analyzer.cs b/Src/PCompiler/CompilerCore/TypeChecker/Analyzer.cs
index aac694afb0..2257d5a6a9 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/Analyzer.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/Analyzer.cs
@@ -20,7 +20,7 @@ public static Scope AnalyzeCompilationUnit(ICompilerConfiguration config,
// Step 2: Validate machine specifications
foreach (var machine in globalScope.Machines)
{
- MachineChecker.Validate(handler, machine);
+ MachineChecker.Validate(handler, machine, config);
}
// Step 3: Fill function bodies
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/MachineChecker.cs b/Src/PCompiler/CompilerCore/TypeChecker/MachineChecker.cs
index 628d9cac50..b8f0a5cddf 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/MachineChecker.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/MachineChecker.cs
@@ -11,13 +11,34 @@ namespace Plang.Compiler.TypeChecker
{
public static class MachineChecker
{
- public static void Validate(ITranslationErrorHandler handler, Machine machine)
+ public static void Validate(ITranslationErrorHandler handler, Machine machine, ICompilerConfiguration job)
{
var startState = FindStartState(machine, handler);
var startStatePayloadType = GetStatePayload(startState);
Debug.Assert(startStatePayloadType.IsSameTypeAs(machine.PayloadType));
ValidateHandlers(handler, machine);
ValidateTransitions(handler, machine);
+ // special validation for monitors:
+ // ensure that each eventhandler is in the observe set.
+ ValidateSpecObservesList(handler, machine, job);
+ }
+
+ private static void ValidateSpecObservesList(ITranslationErrorHandler handler, Machine machine, ICompilerConfiguration job)
+ {
+ if (machine.IsSpec)
+ {
+ foreach (var state in machine.AllStates())
+ {
+ foreach (var pair in state.AllEventHandlers)
+ {
+ if (!machine.Observes.Events.Contains(pair.Key))
+ {
+ job.Output.WriteWarning(
+ handler.SpecObservesSetIncompleteWarning(pair.Value.SourceLocation, pair.Key, machine));
+ }
+ }
+ }
+ }
}
private static void ValidateHandlers(ITranslationErrorHandler handler, Machine machine)
diff --git a/Tst/RegressionTests/Feature1SMLevelDecls/Correct/monitorobserves/observes.p b/Tst/RegressionTests/Feature1SMLevelDecls/Correct/monitorobserves/observes.p
new file mode 100644
index 0000000000..03855f7148
--- /dev/null
+++ b/Tst/RegressionTests/Feature1SMLevelDecls/Correct/monitorobserves/observes.p
@@ -0,0 +1,14 @@
+event e1;
+event e2;
+
+spec Invariant1 observes e1 {
+ start state Init {
+ on e2 goto Init;
+ }
+}
+
+machine Main {
+ start state Init {
+
+ }
+}
\ No newline at end of file
From 9241ed4c6cff8f11985d3c009df9474237b6e115 Mon Sep 17 00:00:00 2001
From: Ankush Desai
Date: Mon, 30 Sep 2024 17:08:29 -0700
Subject: [PATCH 04/21] Merge Recent Bug Fixes (#778)
* Added support for generating a warning when spec handles an event but does not add it in its observes list (#716)
* Create custom converter for JSON serialization in .NET8 (#717)
* Create custom converter for JSON serialization in .NET8
* Add check for different dictionary type for null replacement
---------
Co-authored-by: Eric Hua
* udpate.
* update.
* update.
---------
Co-authored-by: Eric Hua
Co-authored-by: Eric Hua
Co-authored-by: Ao Li
---
Src/PChecker/CheckerCore/CheckerConfiguration.cs | 2 +-
Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs | 2 +-
Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs | 5 +++--
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/Src/PChecker/CheckerCore/CheckerConfiguration.cs b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
index 57706a2b4f..b1f1831800 100644
--- a/Src/PChecker/CheckerCore/CheckerConfiguration.cs
+++ b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
@@ -229,7 +229,7 @@ public int MaxSchedulingSteps
/// Defaults to true.
///
[DataMember]
- public bool IsJsonLogEnabled { get; set; } = true;
+ public bool IsJsonLogEnabled { get; set; } = false;
///
/// If specified, requests a custom runtime log to be used instead of the default.
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs
index 24fd70057b..36b59c3052 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs
@@ -105,7 +105,7 @@ public class TestReport
/// Set of hashes of timelines discovered by the scheduler.
///
[DataMember]
- public HashSet ExploredTimelines = new();
+ public Dictionary ExploredTimelines = new();
///
/// Number of schedulings that satisfies the pattern.
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
index 18042472c6..5d8088d730 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
@@ -1038,8 +1038,9 @@ private void GatherTestingStatistics(ControlledRuntime runtime, TimelineObserver
var coverageInfo = runtime.GetCoverageInfo();
report.CoverageInfo.Merge(coverageInfo);
TestReport.Merge(report);
-
- TestReport.ExploredTimelines.Add(timelineObserver.GetTimelineHash());
+ var timelineHash = timelineObserver.GetTimelineHash();
+ TestReport.ExploredTimelines[timelineHash] =
+ TestReport.ExploredTimelines.GetValueOrDefault(timelineHash, 0) + 1;
// Also save the graph snapshot of the last iteration, if there is one.
Graph = coverageInfo.CoverageGraph;
// Also save the graph snapshot of the last schedule, if there is one.
From 944687422887dd4f5aaa692b54cb206128d3ffde Mon Sep 17 00:00:00 2001
From: Ao Li
Date: Thu, 3 Oct 2024 08:37:47 +0800
Subject: [PATCH 05/21] Fix feedback strategy and remove experiment features.
---
.../CheckerCore/CheckerConfiguration.cs | 14 -----------
.../Feedback/FeedbackGuidedStrategy.cs | 17 ++++----------
.../Probabilistic/QLearningStrategy.cs | 23 +------------------
.../SystematicTesting/TestingEngine.cs | 3 +--
.../PCommandLine/Options/PCheckerOptions.cs | 7 ------
5 files changed, 7 insertions(+), 57 deletions(-)
diff --git a/Src/PChecker/CheckerCore/CheckerConfiguration.cs b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
index b1f1831800..1107cafff4 100644
--- a/Src/PChecker/CheckerCore/CheckerConfiguration.cs
+++ b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
@@ -292,18 +292,6 @@ public int MaxSchedulingSteps
[DataMember]
public string JvmArgs;
- ///
- /// For feedback strategy, discard saved generators if the size of the buffer is greater than N.
- ///
- [DataMember]
- public int DiscardAfter;
-
- ///
- /// For QL strategy, schedule generator mutations based on diversity.
- ///
- [DataMember]
- public bool DiversityBasedPriority;
-
///
/// Enable conflict analysis for scheduling optimization.
///
@@ -355,8 +343,6 @@ protected CheckerConfiguration()
EnableColoredConsoleOutput = false;
DisableEnvironmentExit = true;
- DiscardAfter = 100;
- DiversityBasedPriority = true;
EnableConflictAnalysis = false;
PSymArgs = "";
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
index 358bfe3c9f..bb53639daf 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
@@ -32,7 +32,6 @@ public record GeneratorRecord(int Priority, StrategyGenerator Generator, List _visitedGenerators = new HashSet();
private GeneratorRecord? _currentParent = null;
- private readonly int _discardAfter;
private System.Random _rnd = new System.Random();
@@ -51,7 +50,6 @@ public FeedbackGuidedStrategy(CheckerConfiguration checkerConfiguration, TInput
_maxScheduledSteps = checkerConfiguration.MaxFairSchedulingSteps;
}
Generator = new StrategyGenerator(input, schedule);
- _discardAfter = checkerConfiguration.DiscardAfter;
}
///
@@ -151,7 +149,7 @@ private int ComputeDiversity(int timeline, List hash)
}
- return (hash.Count - maxSim) * 10 + 20;
+ return (hash.Count - maxSim) + 20;
}
///
@@ -204,13 +202,6 @@ public virtual void ObserveRunningResults(EventPatternObserver patternObserver,
{
_savedGenerators.Insert(index, record);
}
-
- if (_savedGenerators.Count > _discardAfter)
- {
- var last = _savedGenerators.Last();
- _visitedGenerators.Remove(last);
- _savedGenerators.RemoveAt(_savedGenerators.Count - 1);
- }
}
}
@@ -245,8 +236,9 @@ private void PrepareNextInput()
if (_visitedGenerators.Contains(generator)) continue;
_currentParent = generator;
_visitedGenerators.Add(generator);
- _pendingMutations = 50;
+ _pendingMutations = generator.Priority;
found = true;
+ break;
}
if (!found)
@@ -256,13 +248,14 @@ private void PrepareNextInput()
_visitedGenerators.Clear();
_currentParent = _savedGenerators.First();
_visitedGenerators.Add(_currentParent);
+ _pendingMutations = _currentParent.Priority;
}
else
{
_shouldExploreNew = true;
_currentParent = null;
+ _pendingMutations = 50;
}
- _pendingMutations = 50;
}
}
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
index 64ed1674c0..c6943ff3a8 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
@@ -81,13 +81,12 @@ internal class QLearningStrategy : RandomStrategy, IFeedbackGuidedStrategy
///
private int Epochs;
- private bool _diversityFeedback;
///
/// Initializes a new instance of the class.
/// It uses the specified random number generator.
///
- public QLearningStrategy(int maxSteps, IRandomValueGenerator random, bool diversityFeedback)
+ public QLearningStrategy(int maxSteps, IRandomValueGenerator random)
: base(maxSteps, random)
{
this.OperationQTable = new Dictionary>();
@@ -102,7 +101,6 @@ public QLearningStrategy(int maxSteps, IRandomValueGenerator random, bool divers
this.FailureInjectionReward = -1000;
this.BasicActionReward = -1;
this.Epochs = 0;
- _diversityFeedback = diversityFeedback;
}
///
@@ -403,25 +401,6 @@ public void ObserveRunningResults(EventPatternObserver patternObserver, Timeline
int priority = 1;
- if (_diversityFeedback)
- {
- int diversityScore = ComputeDiversity(timelineHash, timelineMinhash);
- if (patternObserver == null)
- {
- priority = diversityScore;
- }
- else
- {
- int coverageResult = patternObserver.ShouldSave();
- priority = diversityScore / coverageResult;
- }
-
- if (priority != 0)
- {
- _savedTimelines.Add(timelineMinhash);
- }
- priority += 1;
- }
var node = this.ExecutionPath.First;
while (node != null && node.Next != null)
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
index 5d8088d730..7d260ec8e9 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
@@ -368,8 +368,7 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
}
else if (checkerConfiguration.SchedulingStrategy is "rl")
{
- Strategy = new QLearningStrategy(checkerConfiguration.MaxUnfairSchedulingSteps, RandomValueGenerator,
- checkerConfiguration.DiversityBasedPriority);
+ Strategy = new QLearningStrategy(checkerConfiguration.MaxUnfairSchedulingSteps, RandomValueGenerator);
}
else if (checkerConfiguration.SchedulingStrategy is "dfs")
{
diff --git a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
index 22eb088be1..b98bd89831 100644
--- a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
+++ b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
@@ -82,7 +82,6 @@ internal PCheckerOptions()
advancedGroup.AddArgument("psym-args", null, "Specify a concatenated list of additional PSym-specific arguments to pass, each starting with a colon").IsHidden = true;
advancedGroup.AddArgument("jvm-args", null, "Specify a concatenated list of PSym-specific JVM arguments to pass, each starting with a colon").IsHidden = true;
advancedGroup.AddArgument("pattern", null, "The name of the pattern matcher generator", typeof(string));
- advancedGroup.AddArgument("discard-after", null, "For feedback strategy, discard saved generators after saving N inputs", typeof(int));
advancedGroup.AddArgument("conflict-analysis", null, "Enable POS conflict analysis.", typeof(bool));
}
@@ -332,12 +331,6 @@ private static void UpdateConfigurationWithParsedArgument(CheckerConfiguration c
case "pattern":
checkerConfiguration.PatternSource = (string) option.Value;
break;
- case "discard-after":
- checkerConfiguration.DiscardAfter = (int) option.Value;
- break;
- case "fixed-priority":
- checkerConfiguration.DiversityBasedPriority = false;
- break;
case "conflict-analysis":
checkerConfiguration.EnableConflictAnalysis = true;
break;
From 9d91a5459291ea50d954fe00c728a10d10a19311 Mon Sep 17 00:00:00 2001
From: ChristineZh0u <48167738+ChristineZh0u@users.noreply.github.com>
Date: Tue, 8 Oct 2024 12:32:57 -0700
Subject: [PATCH 06/21] Removing Pattern (#786)
Co-authored-by: Christine Zhou
---
.../CheckerCore/CheckerConfiguration.cs | 7 --
.../Feedback/Coverage/EventPatternObserver.cs | 51 --------------
.../Feedback/FeedbackGuidedStrategy.cs | 16 +----
.../Feedback/IFeedbackGuidedStrategy.cs | 2 +-
.../Probabilistic/QLearningStrategy.cs | 2 +-
.../SystematicTesting/TestReport.cs | 9 +--
.../SystematicTesting/TestingEngine.cs | 69 ++++---------------
.../PCommandLine/Options/PCheckerOptions.cs | 4 --
8 files changed, 21 insertions(+), 139 deletions(-)
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/EventPatternObserver.cs
diff --git a/Src/PChecker/CheckerCore/CheckerConfiguration.cs b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
index 1107cafff4..bcb09e5977 100644
--- a/Src/PChecker/CheckerCore/CheckerConfiguration.cs
+++ b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
@@ -257,12 +257,6 @@ public int MaxSchedulingSteps
[DataMember]
public uint TestingProcessId;
- ///
- /// The source of the pattern generator.
- ///
- [DataMember]
- public string PatternSource;
-
///
/// Additional assembly specifications to instrument for code coverage, besides those in the
/// dependency graph between and the Microsoft.Coyote DLLs.
@@ -347,7 +341,6 @@ protected CheckerConfiguration()
PSymArgs = "";
JvmArgs = "";
- PatternSource = "";
}
///
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/EventPatternObserver.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/EventPatternObserver.cs
deleted file mode 100644
index 61b74b57ea..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/EventPatternObserver.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using PChecker.Actors;
-using PChecker.Actors.Events;
-using PChecker.Actors.Logging;
-
-namespace PChecker.Feedback;
-
-internal class EventPatternObserver : ActorRuntimeLogBase
-{
- private MethodInfo _matcher;
- private List _events = new();
-
- public EventPatternObserver(MethodInfo matcher)
- {
- _matcher = matcher;
- }
-
- public override void OnDequeueEvent(ActorId id, string stateName, Event e)
- {
- e.Index = _events.Count;
- e.State = stateName;
- _events.Add(e);
- }
-
- public override void OnMonitorProcessEvent(string monitorType, string stateName, string senderName, string senderType,
- string senderStateName, Event e)
- {
- e.Index = _events.Count;
- e.State = stateName;
- _events.Add(e);
- }
-
- public virtual int ShouldSave()
- {
- return (int) _matcher.Invoke(null, new [] { _events });
- }
-
- public virtual bool IsMatched()
- {
- int result = (int) _matcher.Invoke(null, new [] { _events });
- return result == 1;
- }
-
-
- public void Reset()
- {
- _events.Clear();
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
index bb53639daf..8567bc6539 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
@@ -155,7 +155,7 @@ private int ComputeDiversity(int timeline, List hash)
///
/// This method observes the results of previous run and prepare for the next run.
///
- public virtual void ObserveRunningResults(EventPatternObserver patternObserver, TimelineObserver timelineObserver)
+ public virtual void ObserveRunningResults(TimelineObserver timelineObserver)
{
var timelineHash = timelineObserver.GetTimelineHash();
var timelineMinhash = timelineObserver.GetTimelineMinhash();
@@ -167,18 +167,8 @@ public virtual void ObserveRunningResults(EventPatternObserver patternObserver,
return;
}
- int priority = 0;
- if (patternObserver == null)
- {
- priority = diversityScore;
- }
- else
- {
- int coverageResult = patternObserver.ShouldSave();
- double coverageScore = 1.0 / coverageResult;
- priority = (int)(diversityScore * coverageScore);
- }
-
+ int priority = diversityScore;
+
if (priority > 0)
{
var record = new GeneratorRecord(priority, Generator, timelineMinhash);
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IFeedbackGuidedStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IFeedbackGuidedStrategy.cs
index f74b8b8b35..ad3c3c8242 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IFeedbackGuidedStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IFeedbackGuidedStrategy.cs
@@ -6,7 +6,7 @@ namespace PChecker.SystematicTesting.Strategies.Feedback;
internal interface IFeedbackGuidedStrategy: ISchedulingStrategy
{
- public void ObserveRunningResults(EventPatternObserver patternObserver, TimelineObserver timelineObserver);
+ public void ObserveRunningResults(TimelineObserver timelineObserver);
public int TotalSavedInputs();
public void DumpStats(TextWriter writer);
}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
index c6943ff3a8..79b29448c4 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
@@ -394,7 +394,7 @@ private int ComputeDiversity(int timeline, List hash)
return (hash.Count - maxSim) * 10 + 20;
}
- public void ObserveRunningResults(EventPatternObserver patternObserver, TimelineObserver timelineObserver)
+ public void ObserveRunningResults(TimelineObserver timelineObserver)
{
var timelineHash = timelineObserver.GetTimelineHash();
var timelineMinhash = timelineObserver.GetTimelineMinhash();
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs
index 20e66679c4..0ad3f3d046 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs
@@ -100,20 +100,13 @@ public class TestReport
///
[DataMember]
public HashSet InternalErrors { get; internal set; }
-
-
+
///
/// Set of hashes of timelines discovered by the scheduler.
///
[DataMember]
public Dictionary ExploredTimelines = new();
- ///
- /// Number of schedulings that satisfies the pattern.
- ///
- [DataMember]
- public Dictionary ValidScheduling = new();
-
///
/// Lock for the test report.
///
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
index e42a83d2d4..d226141c10 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
@@ -65,11 +65,6 @@ public class TestingEngine
///
internal readonly ISchedulingStrategy Strategy;
- ///
- /// Pattern coverage observer if pattern is provided
- ///
- private EventPatternObserver? _eventPatternObserver;
-
///
/// Monitors conflict operations used by the POS Strategy.
///
@@ -217,19 +212,12 @@ public static TestingEngine Create(CheckerConfiguration checkerConfiguration, As
}
TestMethodInfo testMethodInfo = null;
- EventPatternObserver eventMatcher = null;
try
{
testMethodInfo = TestMethodInfo.GetFromAssembly(assembly, checkerConfiguration.TestCaseName);
Console.Out.WriteLine($".. Test case :: {testMethodInfo.Name}");
Type t = assembly.GetType("PImplementation.GlobalFunctions");
- if (checkerConfiguration.PatternSource.Length > 0)
- {
- var result = t.GetMethod(checkerConfiguration.PatternSource,
- BindingFlags.Public | BindingFlags.Static)!;
- eventMatcher = new EventPatternObserver(result);
- }
}
catch
{
@@ -237,7 +225,7 @@ public static TestingEngine Create(CheckerConfiguration checkerConfiguration, As
$"Failed to get test method '{checkerConfiguration.TestCaseName}' from assembly '{assembly.FullName}'");
}
- return new TestingEngine(checkerConfiguration, testMethodInfo, eventMatcher);
+ return new TestingEngine(checkerConfiguration, testMethodInfo);
}
///
@@ -284,21 +272,15 @@ internal TestingEngine(CheckerConfiguration checkerConfiguration, Delegate test)
: this(checkerConfiguration, new TestMethodInfo(test))
{
}
-
- private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo testMethodInfo)
- : this(checkerConfiguration, testMethodInfo, null)
- {
- }
+
///
/// Initializes a new instance of the class.
///
- private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo testMethodInfo,
- EventPatternObserver observer)
+ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo testMethodInfo)
{
_checkerConfiguration = checkerConfiguration;
TestMethodInfo = testMethodInfo;
- _eventPatternObserver = observer;
Logger = new ConsoleLogger();
ErrorReporter = new ErrorReporter(checkerConfiguration, Logger);
@@ -586,10 +568,6 @@ private void RegisterObservers(ControlledRuntime runtime)
// Always output a json log of the error
JsonLogger = new JsonWriter();
runtime.SetJsonLogger(JsonLogger);
- if (_eventPatternObserver != null)
- {
- runtime.RegisterLog(_eventPatternObserver);
- }
if (_conflictOpObserver != null)
{
@@ -666,7 +644,7 @@ private void RunNextIteration(int schedule)
if (Strategy is IFeedbackGuidedStrategy strategy)
{
- strategy.ObserveRunningResults(_eventPatternObserver, timelineObserver);
+ strategy.ObserveRunningResults(timelineObserver);
}
// Checks that no monitor is in a hot state at termination. Only
@@ -735,14 +713,9 @@ private void RunNextIteration(int schedule)
}
// Cleans up the runtime before the next iteration starts.
- if (_eventPatternObserver != null)
- {
- runtime.RemoveLog(_eventPatternObserver);
- }
runtimeLogger?.Dispose();
runtime?.Dispose();
- _eventPatternObserver?.Reset();
_conflictOpObserver?.Reset();
}
}
@@ -1037,29 +1010,17 @@ private void GatherTestingStatistics(ControlledRuntime runtime, TimelineObserver
{
report.CoverageInfo.CoverageGraph = Graph;
}
-
- int shouldSave = 1;
-
- if (_eventPatternObserver != null)
- {
- shouldSave = _eventPatternObserver.ShouldSave();
- TestReport.ValidScheduling.TryAdd(shouldSave, 0);
- TestReport.ValidScheduling[shouldSave] += 1;
- }
-
- if (shouldSave == 1)
- {
- var coverageInfo = runtime.GetCoverageInfo();
- report.CoverageInfo.Merge(coverageInfo);
- TestReport.Merge(report);
- var timelineHash = timelineObserver.GetTimelineHash();
- TestReport.ExploredTimelines[timelineHash] =
- TestReport.ExploredTimelines.GetValueOrDefault(timelineHash, 0) + 1;
- // Also save the graph snapshot of the last iteration, if there is one.
- Graph = coverageInfo.CoverageGraph;
- // Also save the graph snapshot of the last schedule, if there is one.
- Graph = coverageInfo.CoverageGraph;
- }
+
+ var coverageInfo = runtime.GetCoverageInfo();
+ report.CoverageInfo.Merge(coverageInfo);
+ TestReport.Merge(report);
+ var timelineHash = timelineObserver.GetTimelineHash();
+ TestReport.ExploredTimelines[timelineHash] =
+ TestReport.ExploredTimelines.GetValueOrDefault(timelineHash, 0) + 1;
+ // Also save the graph snapshot of the last iteration, if there is one.
+ Graph = coverageInfo.CoverageGraph;
+ // Also save the graph snapshot of the last schedule, if there is one.
+ Graph = coverageInfo.CoverageGraph;
}
///
diff --git a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
index 80c601c616..407321454d 100644
--- a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
+++ b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
@@ -81,7 +81,6 @@ internal PCheckerOptions()
advancedGroup.AddArgument("xml-trace", null, "Specify a filename for XML runtime log output to be written to", typeof(bool));
advancedGroup.AddArgument("psym-args", null, "Specify a concatenated list of additional PSym-specific arguments to pass, each starting with a colon").IsHidden = true;
advancedGroup.AddArgument("jvm-args", null, "Specify a concatenated list of PSym-specific JVM arguments to pass, each starting with a colon").IsHidden = true;
- advancedGroup.AddArgument("pattern", null, "The name of the pattern matcher generator", typeof(string));
advancedGroup.AddArgument("conflict-analysis", null, "Enable POS conflict analysis.", typeof(bool));
}
@@ -328,9 +327,6 @@ private static void UpdateConfigurationWithParsedArgument(CheckerConfiguration c
case "jvm-args":
checkerConfiguration.JvmArgs = ((string)option.Value).Replace(':', ' ');
break;
- case "pattern":
- checkerConfiguration.PatternSource = (string) option.Value;
- break;
case "conflict-analysis":
checkerConfiguration.EnableConflictAnalysis = true;
break;
From 5f65c5ca41cf94de4fe601ff358a11b3d230002f Mon Sep 17 00:00:00 2001
From: Christine Zhou
Date: Tue, 8 Oct 2024 13:33:16 -0700
Subject: [PATCH 07/21] Remove conflict analysis
---
.../CheckerCore/CheckerConfiguration.cs | 6 -
.../Strategies/Feedback/ConflictOpMonitor.cs | 115 ------------------
.../Generator/Mutator/POSScheduleMutator.cs | 4 +-
.../Generator/POSScheduleGenerator.cs | 16 +--
.../Strategies/Probabilistic/POSScheduler.cs | 12 +-
.../PriorizationSchedulingBase.cs | 55 +--------
.../SystematicTesting/TestingEngine.cs | 23 +---
.../PCommandLine/Options/PCheckerOptions.cs | 4 -
8 files changed, 14 insertions(+), 221 deletions(-)
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/ConflictOpMonitor.cs
diff --git a/Src/PChecker/CheckerCore/CheckerConfiguration.cs b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
index bcb09e5977..bc296da11c 100644
--- a/Src/PChecker/CheckerCore/CheckerConfiguration.cs
+++ b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
@@ -286,11 +286,6 @@ public int MaxSchedulingSteps
[DataMember]
public string JvmArgs;
- ///
- /// Enable conflict analysis for scheduling optimization.
- ///
- [DataMember]
- public bool EnableConflictAnalysis;
///
/// Initializes a new instance of the class.
@@ -337,7 +332,6 @@ protected CheckerConfiguration()
EnableColoredConsoleOutput = false;
DisableEnvironmentExit = true;
- EnableConflictAnalysis = false;
PSymArgs = "";
JvmArgs = "";
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/ConflictOpMonitor.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/ConflictOpMonitor.cs
deleted file mode 100644
index 00cef43310..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/ConflictOpMonitor.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using PChecker.Actors;
-using PChecker.Actors.Events;
-using PChecker.Actors.Logging;
-using PChecker.SystematicTesting.Operations;
-
-namespace PChecker.Feedback;
-
-
-internal class ConflictOpMonitor: ActorRuntimeLogBase
-{
-
- public VectorClockGenerator VectorClockGenerator;
-
- // This dictionary stores all operations received by a machine.
- // Each operation is labeled with ActorId, source location, and its corresponding
- // vector clock timestamp.
- private Dictionary)>> incomingOps = new();
-
- private Dictionary> conflictOps = new();
-
- public override void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName, Event e,
- Guid opGroupId, bool isTargetHalted)
- {
- var receiverKey = e.Receiver;
- var senderKey = e.Sender;
- var currentOp = new Operation(senderKey, receiverKey, e.Loc);
- if (!incomingOps.ContainsKey(receiverKey))
- {
- incomingOps.Add(receiverKey, new HashSet<(Operation, Dictionary)>());
- }
- var opsSet = incomingOps[receiverKey];
-
-
-
- if (VectorClockGenerator.ContextVcMap.TryGetValue(senderKey, out var vectorClock))
- {
-
- foreach (var op in opsSet)
- {
- if (op.Item1.Sender == currentOp.Sender)
- {
- continue;
- }
-
- if (!IsLEQ(op.Item2, vectorClock) && !IsLEQ(vectorClock, op.Item2))
- {
- AddConflictOp(op.Item1, currentOp);
- }
- }
- opsSet.Add((currentOp, vectorClock
- .ToDictionary(entry => entry.Key, entry => entry.Value)));
- }
- }
-
- internal bool IsRacing(AsyncOperation op1, AsyncOperation op2)
- {
- if (op1.Type != AsyncOperationType.Send || op2.Type != AsyncOperationType.Send) {
- return false;
- }
-
- var operation1 = new Operation(op1.Name, op1.LastSentReceiver, op1.LastEvent!.Loc);
- var operation2 = new Operation(op2.Name, op2.LastSentReceiver, op2.LastEvent!.Loc);
-
- if (conflictOps.TryGetValue(operation1, out var ops)) {
- return ops.Contains(operation2);
- }
- return false;
- }
-
- public void Reset() {
- incomingOps.Clear();
- }
-
- bool IsLEQ(Dictionary vc1, Dictionary vc2)
- {
- foreach (var key in vc1.Keys.Union(vc2.Keys))
- {
- var op1 = vc1.GetValueOrDefault(key, 0);
- var op2 = vc2.GetValueOrDefault(key, 0);
- if (op1 > op2)
- {
- return false;
- }
- }
- return true;
- }
-
- void AddConflictOp(Operation op1, Operation op2)
- {
- if (!conflictOps.ContainsKey(op1)) {
- conflictOps[op1] = new HashSet();
- }
- if (!conflictOps.ContainsKey(op2)) {
- conflictOps[op2] = new HashSet();
- }
- conflictOps[op1].Add(op2);
- conflictOps[op2].Add(op1);
- }
- internal bool IsConflictingOp(AsyncOperation op)
- {
- if (op.Type != AsyncOperationType.Send) {
- return false;
- }
-
- var operation = new Operation(op.Name, op.LastSentReceiver, op.LastEvent!.Loc);
- if (conflictOps.TryGetValue(operation, out var ops ))
- {
- return ops.Count != 0;
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/POSScheduleMutator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/POSScheduleMutator.cs
index d94b042661..b375093a0f 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/POSScheduleMutator.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/POSScheduleMutator.cs
@@ -9,8 +9,6 @@ public POSScheduleGenerator Mutate(POSScheduleGenerator prev)
{
return new POSScheduleGenerator(prev.Random,
Utils.MutateRandomChoices(prev.PriorityChoices, _meanMutationCount, _meanMutationSize, _random),
- Utils.MutateRandomChoices(prev.SwitchPointChoices, _meanMutationCount, _meanMutationSize, _random),
- prev.Monitor
- );
+ Utils.MutateRandomChoices(prev.SwitchPointChoices, _meanMutationCount, _meanMutationSize, _random));
}
}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/POSScheduleGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/POSScheduleGenerator.cs
index fffc0ba15d..b3de2b2db1 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/POSScheduleGenerator.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/POSScheduleGenerator.cs
@@ -13,25 +13,21 @@ internal class POSScheduleGenerator: POSScheduler, IScheduleGenerator PriorityChoices;
public RandomChoices SwitchPointChoices;
- public ConflictOpMonitor? Monitor;
- public POSScheduleGenerator(System.Random random, RandomChoices? priorityChoices, RandomChoices? switchPointChoices,
- ConflictOpMonitor? monitor):
+ public POSScheduleGenerator(System.Random random, RandomChoices? priorityChoices, RandomChoices? switchPointChoices):
base(new ParametricProvider(
priorityChoices != null ? new RandomChoices(priorityChoices) : new RandomChoices(random),
- switchPointChoices != null ? new RandomChoices(switchPointChoices) : new RandomChoices(random)),
- monitor)
+ switchPointChoices != null ? new RandomChoices(switchPointChoices) : new RandomChoices(random)))
{
Random = random;
var provider = (ParametricProvider) Provider;
PriorityChoices = provider.PriorityChoices;
SwitchPointChoices = provider.SwitchPointChoices;
- Monitor = monitor;
}
- public POSScheduleGenerator(CheckerConfiguration checkerConfiguration, ConflictOpMonitor? monitor):
+ public POSScheduleGenerator(CheckerConfiguration checkerConfiguration):
this(new System.Random((int?)checkerConfiguration.RandomGeneratorSeed ?? Guid.NewGuid().GetHashCode()), null,
- null, monitor)
+ null)
{
}
@@ -42,12 +38,12 @@ public POSScheduleGenerator Mutate()
public POSScheduleGenerator New()
{
- return new POSScheduleGenerator(Random, null, null, Monitor);
+ return new POSScheduleGenerator(Random, null, null);
}
public POSScheduleGenerator Copy()
{
- return new POSScheduleGenerator(Random, PriorityChoices, SwitchPointChoices, Monitor);
+ return new POSScheduleGenerator(Random, PriorityChoices, SwitchPointChoices);
}
public AsyncOperation? NextRandomOperation(List enabledOperations, AsyncOperation current)
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs
index 589ae13099..ae44bbec13 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs
@@ -15,17 +15,14 @@ internal class POSScheduler: PrioritizedScheduler
/// List of prioritized operations.
///
private readonly List PrioritizedOperations;
-
- public ConflictOpMonitor? ConflictOpMonitor;
-
+
///
/// Initializes a new instance of the class.
///
- public POSScheduler(PriorizationProvider provider, ConflictOpMonitor? monitor)
+ public POSScheduler(PriorizationProvider provider)
{
Provider = provider;
PrioritizedOperations = new List();
- ConflictOpMonitor = monitor;
}
public bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
@@ -123,11 +120,6 @@ private AsyncOperation GetPrioritizedOperation(List ops, AsyncOp
private bool FindNonRacingOperation(IEnumerable ops, out AsyncOperation next)
{
var nonRacingOps = ops.Where(op => op.Type != AsyncOperationType.Send);
- if (!nonRacingOps.Any() && ConflictOpMonitor != null)
- {
- nonRacingOps = ops.Where(op => !ConflictOpMonitor.IsConflictingOp(op));
- }
-
if (!nonRacingOps.Any())
{
next = null;
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationSchedulingBase.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationSchedulingBase.cs
index 3894b96fc8..ae4eee7531 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationSchedulingBase.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationSchedulingBase.cs
@@ -34,21 +34,19 @@ internal class PriorizationSchedulingBase
///
private readonly List PrioritizedOperations;
- public ConflictOpMonitor? ConflictOpMonitor;
private int _nextPriorityChangePoint;
private int _numSwitchPointsLeft;
///
/// Initializes a new instance of the class.
///
- public PriorizationSchedulingBase(int maxPrioritySwitchPoints, int scheduleLength, PriorizationProvider provider, ConflictOpMonitor? monitor)
+ public PriorizationSchedulingBase(int maxPrioritySwitchPoints, int scheduleLength, PriorizationProvider provider)
{
Provider = provider;
ScheduledSteps = 0;
ScheduleLength = scheduleLength;
MaxPrioritySwitchPoints = maxPrioritySwitchPoints;
PrioritizedOperations = new List();
- ConflictOpMonitor = monitor;
_numSwitchPointsLeft = maxPrioritySwitchPoints;
double switchPointProbability = 0.1;
@@ -66,7 +64,7 @@ public virtual bool GetNextOperation(AsyncOperation current, IEnumerable op.Status is AsyncOperationStatus.Enabled).ToList();
if (enabledOperations.Count == 0)
{
- if (ConflictOpMonitor == null && _nextPriorityChangePoint == ScheduledSteps)
+ if (_nextPriorityChangePoint == ScheduledSteps)
{
MovePriorityChangePointForward();
}
@@ -78,25 +76,9 @@ public virtual bool GetNextOperation(AsyncOperation current, IEnumerable ops)
- {
- foreach (var op in ops)
- {
- if (op != next && ConflictOpMonitor.IsRacing(next, op))
- {
- PrioritizedOperations.Remove(op);
- }
- }
- PrioritizedOperations.Remove(next);
- }
private void MovePriorityChangePointForward()
{
@@ -137,13 +119,8 @@ private AsyncOperation GetPrioritizedOperation(List ops, AsyncOp
Debug.WriteLine(" Detected new operation '{0}' at index '{1}'.", op.Id, mIndex);
}
- if (ConflictOpMonitor != null && FindNonRacingOperation(ops, out var next))
- {
- return next;
- }
-
var prioritizedSchedulable = GetHighestPriorityEnabledOperation(ops);
- if (ConflictOpMonitor == null && _nextPriorityChangePoint == ScheduledSteps)
+ if (_nextPriorityChangePoint == ScheduledSteps)
{
if (ops.Count == 1)
{
@@ -190,32 +167,6 @@ private AsyncOperation GetPrioritizedOperation(List ops, AsyncOp
return ops.First(op => op.Equals(prioritizedSchedulable));
}
- private bool FindNonRacingOperation(IEnumerable ops, out AsyncOperation next)
- {
- var nonRacingOps = ops.Where(op => op.Type != AsyncOperationType.Send);
- if (!nonRacingOps.Any())
- {
- var sendOps = ops.Where(op => op.Type == AsyncOperationType.Send);
- nonRacingOps = ops.Where(op => !ConflictOpMonitor.IsConflictingOp(op));
- }
-
- if (!nonRacingOps.Any())
- {
- next = null;
- return false;
- }
- else if (!nonRacingOps.Skip(1).Any())
- {
- next = nonRacingOps.First();
- return true;
- }
- else
- {
- next = GetHighestPriorityEnabledOperation(nonRacingOps);
- return true;
- }
-
- }
public void Reset()
{
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
index d226141c10..d15d8316d4 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
@@ -65,11 +65,6 @@ public class TestingEngine
///
internal readonly ISchedulingStrategy Strategy;
- ///
- /// Monitors conflict operations used by the POS Strategy.
- ///
- private ConflictOpMonitor? _conflictOpObserver;
-
///
/// Random value generator used by the scheduling strategies.
///
@@ -303,12 +298,6 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
{
JsonVerboseLogs = new List>();
}
-
- if (checkerConfiguration.EnableConflictAnalysis)
- {
- _conflictOpObserver = new ConflictOpMonitor();
- }
-
if (checkerConfiguration.SchedulingStrategy is "replay")
{
var scheduleDump = GetScheduleForReplay(out var isFair);
@@ -328,8 +317,7 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
}
else if (checkerConfiguration.SchedulingStrategy is "pos")
{
- var scheduler = new POSScheduler(new RandomPriorizationProvider(RandomValueGenerator),
- _conflictOpObserver);
+ var scheduler = new POSScheduler(new RandomPriorizationProvider(RandomValueGenerator));
Strategy = new PrioritizedSchedulingStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
RandomValueGenerator, scheduler);
}
@@ -372,7 +360,7 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
Strategy = new FeedbackGuidedStrategy(
_checkerConfiguration,
new RandomInputGenerator(checkerConfiguration),
- new POSScheduleGenerator(_checkerConfiguration, _conflictOpObserver));
+ new POSScheduleGenerator(_checkerConfiguration));
}
else if (checkerConfiguration.SchedulingStrategy is "portfolio")
{
@@ -568,12 +556,6 @@ private void RegisterObservers(ControlledRuntime runtime)
// Always output a json log of the error
JsonLogger = new JsonWriter();
runtime.SetJsonLogger(JsonLogger);
-
- if (_conflictOpObserver != null)
- {
- _conflictOpObserver.VectorClockGenerator = JsonLogger.VcGenerator;
- runtime.RegisterLog(_conflictOpObserver);
- }
}
///
@@ -716,7 +698,6 @@ private void RunNextIteration(int schedule)
runtimeLogger?.Dispose();
runtime?.Dispose();
- _conflictOpObserver?.Reset();
}
}
diff --git a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
index 407321454d..6b62e9f69d 100644
--- a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
+++ b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
@@ -81,7 +81,6 @@ internal PCheckerOptions()
advancedGroup.AddArgument("xml-trace", null, "Specify a filename for XML runtime log output to be written to", typeof(bool));
advancedGroup.AddArgument("psym-args", null, "Specify a concatenated list of additional PSym-specific arguments to pass, each starting with a colon").IsHidden = true;
advancedGroup.AddArgument("jvm-args", null, "Specify a concatenated list of PSym-specific JVM arguments to pass, each starting with a colon").IsHidden = true;
- advancedGroup.AddArgument("conflict-analysis", null, "Enable POS conflict analysis.", typeof(bool));
}
///
@@ -327,9 +326,6 @@ private static void UpdateConfigurationWithParsedArgument(CheckerConfiguration c
case "jvm-args":
checkerConfiguration.JvmArgs = ((string)option.Value).Replace(':', ' ');
break;
- case "conflict-analysis":
- checkerConfiguration.EnableConflictAnalysis = true;
- break;
case "pproj":
// do nothing, since already configured through UpdateConfigurationWithPProjectFile
break;
From ccaa27674abf5d44d1e07ea55d6a96be8438ccd2 Mon Sep 17 00:00:00 2001
From: ChristineZh0u <48167738+ChristineZh0u@users.noreply.github.com>
Date: Wed, 9 Oct 2024 09:08:59 -0700
Subject: [PATCH 08/21] Removing compiler changes (#789)
Co-authored-by: Christine Zhou
---
.../CheckerCore/Actors/Events/Event.cs | 1 -
Src/PChecker/CheckerCore/PRuntime/PEvent.cs | 8 +-
Src/PChecker/CheckerCore/PRuntime/PMachine.cs | 8 +-
.../Backend/CSharp/CSharpCodeGenerator.cs | 105 +++---------------
.../CompilerCore/Backend/IRTransformer.cs | 3 -
Src/PCompiler/CompilerCore/Parser/PLexer.g4 | 1 -
Src/PCompiler/CompilerCore/Parser/PParser.g4 | 8 --
.../TypeChecker/AST/Declarations/Function.cs | 6 +-
.../AST/Declarations/FunctionSignature.cs | 2 -
.../AST/Statements/ConstraintStmt.cs | 15 ---
.../CompilerCore/TypeChecker/Analyzer.cs | 9 +-
.../ConstraintVariableCollector.cs | 33 ------
.../TypeChecker/ControlFlowChecker.cs | 1 -
.../TypeChecker/DeclarationStubVisitor.cs | 20 ----
.../TypeChecker/DeclarationVisitor.cs | 26 +----
.../CompilerCore/TypeChecker/ExprVisitor.cs | 23 +---
.../TypeChecker/FunctionBodyVisitor.cs | 27 -----
.../TypeChecker/FunctionValidator.cs | 2 +-
.../TypeChecker/ScenarioEventVisitor.cs | 20 ----
.../CompilerCore/TypeChecker/Scope.cs | 8 --
.../CompilerCore/TypeChecker/TypeResolver.cs | 2 +-
.../TypeChecker/Types/NamedTupleEntry.cs | 11 --
22 files changed, 32 insertions(+), 307 deletions(-)
delete mode 100644 Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/ConstraintStmt.cs
delete mode 100644 Src/PCompiler/CompilerCore/TypeChecker/ConstraintVariableCollector.cs
delete mode 100644 Src/PCompiler/CompilerCore/TypeChecker/ScenarioEventVisitor.cs
diff --git a/Src/PChecker/CheckerCore/Actors/Events/Event.cs b/Src/PChecker/CheckerCore/Actors/Events/Event.cs
index ca9fe6b4d5..57917c052b 100644
--- a/Src/PChecker/CheckerCore/Actors/Events/Event.cs
+++ b/Src/PChecker/CheckerCore/Actors/Events/Event.cs
@@ -11,7 +11,6 @@ namespace PChecker.Actors.Events
[DataContract]
public abstract class Event
{
- public int Loc { get; set; }
public string? Sender;
public string? Receiver;
public string? State;
diff --git a/Src/PChecker/CheckerCore/PRuntime/PEvent.cs b/Src/PChecker/CheckerCore/PRuntime/PEvent.cs
index 8059cd490d..33af7d6790 100644
--- a/Src/PChecker/CheckerCore/PRuntime/PEvent.cs
+++ b/Src/PChecker/CheckerCore/PRuntime/PEvent.cs
@@ -6,15 +6,13 @@ namespace PChecker.PRuntime
{
public class PEvent : Event, IPrtValue
{
- public PEvent(int loc) : base()
+ public PEvent() : base()
{
- Loc = loc;
}
- public PEvent(IPrtValue payload, int loc) : base()
+ public PEvent(IPrtValue payload) : base()
{
Payload = payload;
- Loc = loc;
}
public IPrtValue Payload { get; }
@@ -52,7 +50,7 @@ public override string ToString()
public class PHalt : PEvent
{
- public PHalt(IPrtValue payload, int loc) : base(payload, loc)
+ public PHalt(IPrtValue payload) : base(payload)
{
}
}
diff --git a/Src/PChecker/CheckerCore/PRuntime/PMachine.cs b/Src/PChecker/CheckerCore/PRuntime/PMachine.cs
index d23ef2c457..d95b2e38de 100644
--- a/Src/PChecker/CheckerCore/PRuntime/PMachine.cs
+++ b/Src/PChecker/CheckerCore/PRuntime/PMachine.cs
@@ -84,7 +84,7 @@ public void TrySendEvent(PMachineValue target, Event ev, object payload = null)
Assert(target.Permissions.Contains(ev.GetType().Name),
$"Event {ev.GetType().Name} is not in the permissions set of the target machine");
var oneArgConstructor = ev.GetType().GetConstructors().First(x => x.GetParameters().Length > 0);
- ev = (Event)oneArgConstructor.Invoke(new[] { payload , ev.Loc});
+ ev = (Event)oneArgConstructor.Invoke(new[] { payload });
ev.Sender = Id.ToString();
ev.Receiver = target.Id.ToString();
@@ -96,7 +96,7 @@ public void TryRaiseEvent(Event ev, object payload = null)
{
Assert(ev != null, "Machine cannot raise a null event");
var oneArgConstructor = ev.GetType().GetConstructors().First(x => x.GetParameters().Length > 0);
- ev = (Event)oneArgConstructor.Invoke(new[] { payload, ev.Loc });
+ ev = (Event)oneArgConstructor.Invoke(new[] { payload });
RaiseEvent(ev);
throw new PNonStandardReturnException { ReturnKind = NonStandardReturn.Raise };
}
@@ -190,7 +190,7 @@ public void Announce(Event ev, object payload = null)
}
var oneArgConstructor = ev.GetType().GetConstructors().First(x => x.GetParameters().Length > 0);
- var @event = (Event)oneArgConstructor.Invoke(new[] { payload, ev.Loc });
+ var @event = (Event)oneArgConstructor.Invoke(new[] { payload });
var pText = payload == null ? "" : $" with payload {((IPrtValue)payload).ToEscapedString()}";
Logger.WriteLine($" '{Id}' announced event '{ev.GetType().Name}'{pText}.");
@@ -255,7 +255,7 @@ public object ToDict()
public class InitializeParametersEvent : PEvent
{
- public InitializeParametersEvent(InitializeParameters payload) : base(payload, 0)
+ public InitializeParametersEvent(InitializeParameters payload) : base(payload)
{
}
}
diff --git a/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs b/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs
index 07a7d17d74..c7a2223bc3 100644
--- a/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs
+++ b/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs
@@ -22,8 +22,6 @@ public class CSharpCodeGenerator : ICodeGenerator
///
public bool HasCompilationStage => true;
- private int _sendEventIndex = 0;
-
public void Compile(ICompilerConfiguration job)
{
var csprojName = $"{job.ProjectName}.csproj";
@@ -486,8 +484,8 @@ private void WriteEvent(CompilationContext context, StringWriter output, PEvent
var payloadType = GetCSharpType(pEvent.PayloadType, true);
context.WriteLine(output, $"internal partial class {declName} : PEvent");
context.WriteLine(output, "{");
- context.WriteLine(output, $"public {declName}() : base(-1) {{}}");
- context.WriteLine(output, $"public {declName}({payloadType} payload, int loc): base(payload, loc)" + "{ }");
+ context.WriteLine(output, $"public {declName}() : base() {{}}");
+ context.WriteLine(output, $"public {declName} ({payloadType} payload): base(payload)" + "{ }");
context.WriteLine(output, $"public override IPrtValue Clone() {{ return new {declName}();}}");
context.WriteLine(output, "}");
@@ -512,12 +510,12 @@ private void WriteMachine(CompilationContext context, StringWriter output, Machi
var cTorType = GetCSharpType(machine.PayloadType, true);
context.Write(output, "public class ConstructorEvent : PEvent");
context.Write(output, "{");
- context.Write(output, $"public ConstructorEvent({cTorType} val, int loc) : base(val, loc) {{ }}");
+ context.Write(output, $"public ConstructorEvent({cTorType} val) : base(val) {{ }}");
context.WriteLine(output, "}");
context.WriteLine(output);
context.WriteLine(output,
- $"protected override Event GetConstructorEvent(IPrtValue value) {{ return new ConstructorEvent(({cTorType})value, {_sendEventIndex++}); }}");
+ $"protected override Event GetConstructorEvent(IPrtValue value) {{ return new ConstructorEvent(({cTorType})value); }}");
// create the constructor to initialize the sends, creates and receives list
WriteMachineConstructor(context, output, machine);
@@ -708,7 +706,7 @@ private void WriteFunction(CompilationContext context, StringWriter output, Func
var staticKeyword = isStatic ? "static " : "";
var asyncKeyword = isAsync ? "async " : "";
- var returnType = function.Role != FunctionRole.Scenario ? GetCSharpType(signature.ReturnType) : "int";
+ var returnType = GetCSharpType(signature.ReturnType);
if (isAsync)
{
@@ -721,10 +719,6 @@ private void WriteFunction(CompilationContext context, StringWriter output, Func
{
functionParameters = "Event currentMachine_dequeuedEvent";
}
- else if (function.Role == FunctionRole.Scenario)
- {
- functionParameters = "List events";
- }
else
{
functionParameters = string.Join(
@@ -733,7 +727,7 @@ private void WriteFunction(CompilationContext context, StringWriter output, Func
$"{GetCSharpType(param.Type)} {context.Names.GetNameForDecl(param)}"));
}
- if (isStatic && function.Role != FunctionRole.Scenario) // then we need to generate two versions of the function
+ if (isStatic) // then we need to generate two versions of the function
{
// for machine
var seperator = functionParameters == "" ? "" : ", ";
@@ -789,69 +783,14 @@ private void WriteFunctionBody(CompilationContext context, StringWriter output,
$"{GetCSharpType(type, true)} {context.Names.GetNameForDecl(local)} = {GetDefaultValue(type)};");
}
- if (function.Role != FunctionRole.Scenario)
- {
- foreach (var bodyStatement in function.Body.Statements)
- {
- WriteStmt(context: context, output: output, function: function, stmt: bodyStatement);
- }
- }
- else
- {
- WriteScenario(context, output, function);
- }
-
-
- context.WriteLine(output, "}");
- }
-
- private void WriteScenario(CompilationContext context, StringWriter output, Function function)
- {
- int numOfStmt = function.Body.Statements.Count + 1;
- context.WriteLine(output, $"int state = {numOfStmt};");
- var eventPredicates = string.Join(" or ", function.Signature.ParameterEvents.Select(it => it.Name));
- context.WriteLine(output, $"events = events.Where(it => it is {eventPredicates}).ToList();");
- WriteConstraintsRecursive(context, output, function, 0, new HashSet(), 0);
- context.WriteLine(output, "return state;");
- }
-
- private void WriteConstraintsRecursive(CompilationContext context, StringWriter output, Function function, int index, HashSet visitedVariables, int satisfiedConstraints)
- {
- if (index >= function.Signature.Parameters.Count)
- {
- context.WriteLine(output, "return 1;");
- return;
- }
- var param = function.Signature.Parameters[index];
- var e = function.Signature.ParameterEvents[index];
- visitedVariables.Add(param);
- var start = index == 0 ? "0" : $"i{index - 1} + 1";
- var paramName = context.Names.GetNameForDecl(param);
- context.WriteLine(output, $"for (var i{index} = {start} ; i{index} < events.Count; i{index} ++) " + "{");
- context.WriteLine(output, $"var {paramName}_obj = events[i{index}];");
- context.WriteLine(output, $"if ({paramName}_obj is not {e.Name}) continue;");
- context.WriteLine(output, $"var {paramName} = ((PEvent) {paramName}_obj).Payload;");
-
foreach (var bodyStatement in function.Body.Statements)
{
- if (bodyStatement is ConstraintStmt stmt)
- {
- var variables = ConstraintVariableCollector.FindVariablesRecursive(stmt.Constraint);
- if (variables.Contains(param) && visitedVariables.IsSupersetOf(variables))
- {
- context.Write(output, $"if (!(");
- WriteExpr(context, output, stmt.Constraint);
- context.WriteLine(output, $")) continue;");
- satisfiedConstraints += 1;
- context.WriteLine(output, $"state = Math.Min({function.Body.Statements.Count - satisfiedConstraints + 1}, state);");
- }
- }
+ WriteStmt(context: context, output: output, function: function, stmt: bodyStatement);
}
- WriteConstraintsRecursive(context, output, function, index + 1, visitedVariables, satisfiedConstraints);
+
context.WriteLine(output, "}");
}
-
private void WriteStmt(CompilationContext context, StringWriter output, Function function, IPStmt stmt)
{
switch (stmt)
@@ -1240,19 +1179,9 @@ private void WriteLValue(CompilationContext context, StringWriter output, IPExpr
break;
case NamedTupleAccessExpr namedTupleAccessExpr:
- if (ExprVisitor.ReservedEventFeilds.ContainsValue(namedTupleAccessExpr.Entry))
- {
- var type = GetCSharpType(namedTupleAccessExpr.Entry.Type);
- context.Write(output, $"(({type}) (");
- WriteExpr(context, output, namedTupleAccessExpr.SubExpr);
- context.Write(output, $"_obj).{namedTupleAccessExpr.FieldName})");
- }
- else
- {
- context.Write(output, "((PrtNamedTuple)");
- WriteExpr(context, output, namedTupleAccessExpr.SubExpr);
- context.Write(output, $")[\"{namedTupleAccessExpr.FieldName}\"]");
- }
+ context.Write(output, "((PrtNamedTuple)");
+ WriteExpr(context, output, namedTupleAccessExpr.SubExpr);
+ context.Write(output, $")[\"{namedTupleAccessExpr.FieldName}\"]");
break;
case SeqAccessExpr seqAccessExpr:
@@ -1296,9 +1225,9 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p
context.Write(output, $"({negate}PrtValues.SafeEquals(");
if (PLanguageType.TypeIsOfKind(binOpExpr.Lhs.Type, TypeKind.Enum))
{
- context.Write(output, "PrtValues.Box((long) ((PrtInt)");
+ context.Write(output, "PrtValues.Box((long) ");
WriteExpr(context, output, binOpExpr.Lhs);
- context.Write(output, ")),");
+ context.Write(output, "),");
}
else
{
@@ -1308,9 +1237,9 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p
if (PLanguageType.TypeIsOfKind(binOpExpr.Rhs.Type, TypeKind.Enum))
{
- context.Write(output, "PrtValues.Box((long) ((PrtInt)");
+ context.Write(output, "PrtValues.Box((long) ");
WriteExpr(context, output, binOpExpr.Rhs);
- context.Write(output, "))");
+ context.Write(output, ")");
}
else
{
@@ -1459,7 +1388,7 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p
switch (eventName)
{
case "Halt":
- context.Write(output, "new PHalt(" + _sendEventIndex++ + ")");
+ context.Write(output, "new PHalt()");
break;
case "DefaultEvent":
@@ -1468,7 +1397,7 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p
default:
var payloadExpr = GetDefaultValue(eventRefExpr.Value.PayloadType);
- context.Write(output, $"new {eventName}({payloadExpr}, {_sendEventIndex++})");
+ context.Write(output, $"new {eventName}({payloadExpr})");
break;
}
diff --git a/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs b/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs
index 8e6992cf9b..943eba0df8 100644
--- a/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs
+++ b/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs
@@ -567,9 +567,6 @@ private List SimplifyStatement(IPStmt statement)
condCheck.Concat(SimplifyStatement(whileStmt.Body)));
return new List { new WhileStmt(location, new BoolLiteralExpr(location, true), loopBody) };
- // We do not rewrite constraint statements for now.
- case ConstraintStmt constraintStmt:
- return new List() { constraintStmt };
default:
throw new ArgumentOutOfRangeException(nameof(statement));
diff --git a/Src/PCompiler/CompilerCore/Parser/PLexer.g4 b/Src/PCompiler/CompilerCore/Parser/PLexer.g4
index e8fb715019..8f7511ac8d 100644
--- a/Src/PCompiler/CompilerCore/Parser/PLexer.g4
+++ b/Src/PCompiler/CompilerCore/Parser/PLexer.g4
@@ -70,7 +70,6 @@ MODULE : 'module' ;
IMPLEMENTATION : 'implementation' ;
TEST : 'test' ;
REFINES : 'refines' ;
-SCENARIO : 'scenario' ;
// module constructors
COMPOSE : 'compose' ;
diff --git a/Src/PCompiler/CompilerCore/Parser/PParser.g4 b/Src/PCompiler/CompilerCore/Parser/PParser.g4
index 3140b37edb..dc00fca475 100644
--- a/Src/PCompiler/CompilerCore/Parser/PParser.g4
+++ b/Src/PCompiler/CompilerCore/Parser/PParser.g4
@@ -60,7 +60,6 @@ topDecl : typeDefDecl
| namedModuleDecl
| testDecl
| implementationDecl
- | scenarioDecl
;
@@ -108,13 +107,6 @@ funDecl : FUN name=iden LPAREN funParamList? RPAREN (COLON type)? (CREATES inter
| FUN name=iden LPAREN funParamList? RPAREN (COLON type)? functionBody # PFunDecl
;
-scenarioDecl : SCENARIO scenarioName=iden LPAREN scenarioParamList RPAREN scenarioBody;
-
-scenarioParamList: scenarioParam (COMMA scenarioParam)*;
-scenarioParam : name=iden COLON nonDefaultEvent;
-scenarioBody : LBRACE expr (COMMA expr)* RBRACE;
-
-
stateDecl : START? temperature=(HOT | COLD)? STATE name=iden LBRACE stateBodyItem* RBRACE ;
stateBodyItem : ENTRY anonEventHandler # StateEntry
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/Function.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/Function.cs
index c5001cbca9..69ed97c4ad 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/Function.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/Function.cs
@@ -15,8 +15,7 @@ public enum FunctionRole
EventHandler = 1 << 4,
ExitHandler = 1 << 5,
ReceiveHandler = 1 << 6,
- Foreign = 1 << 7,
- Scenario = 1 << 8,
+ Foreign = 1 << 7
}
public class Function : IPDecl, IHasScope
@@ -33,8 +32,7 @@ sourceNode is PParser.AnonEventHandlerContext ||
sourceNode is PParser.NoParamAnonEventHandlerContext ||
sourceNode is PParser.ReceiveStmtContext ||
sourceNode is PParser.WhileStmtContext ||
- sourceNode is PParser.ForeachStmtContext ||
- sourceNode is PParser.ScenarioDeclContext);
+ sourceNode is PParser.ForeachStmtContext);
Name = name;
SourceLocation = sourceNode;
CanCreate = false;
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/FunctionSignature.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/FunctionSignature.cs
index c3801faab7..b711938af6 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/FunctionSignature.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/FunctionSignature.cs
@@ -7,8 +7,6 @@ namespace Plang.Compiler.TypeChecker.AST.Declarations
public class FunctionSignature
{
public List Parameters { get; } = new List();
- // This is only used by scenarios.
- public List ParameterEvents { get; } = new();
public IEnumerable ParameterTypes => Parameters.Select(ty => ty.Type);
public PLanguageType ReturnType { get; set; } = PrimitiveType.Null;
}
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/ConstraintStmt.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/ConstraintStmt.cs
deleted file mode 100644
index 163e1a5953..0000000000
--- a/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/ConstraintStmt.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Antlr4.Runtime;
-
-namespace Plang.Compiler.TypeChecker.AST.Statements;
-
-public class ConstraintStmt : IPStmt
-{
- public ConstraintStmt(ParserRuleContext sourceLocation, IPExpr constraint)
- {
- SourceLocation = sourceLocation;
- Constraint = constraint;
- }
-
- public IPExpr Constraint { get; }
- public ParserRuleContext SourceLocation { get; }
-}
\ No newline at end of file
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Analyzer.cs b/Src/PCompiler/CompilerCore/TypeChecker/Analyzer.cs
index b395a56024..3139ff3f93 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/Analyzer.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/Analyzer.cs
@@ -179,14 +179,7 @@ private static Scope BuildGlobalScope(ICompilerConfiguration config, PParser.Pro
{
DeclarationVisitor.PopulateDeclarations(config.Handler, globalScope, programUnit, nodesToDeclarations);
}
-
- // Step 3: Assign param types for scenario events. We have do this after all events are initialized.
- foreach (var function in globalScope.Functions)
- {
- ScenarioEventVisitor.PopulateEventTypes(function);
- }
-
-
+
return globalScope;
}
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/ConstraintVariableCollector.cs b/Src/PCompiler/CompilerCore/TypeChecker/ConstraintVariableCollector.cs
deleted file mode 100644
index 647d9c1168..0000000000
--- a/Src/PCompiler/CompilerCore/TypeChecker/ConstraintVariableCollector.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Plang.Compiler.TypeChecker.AST;
-using Plang.Compiler.TypeChecker.AST.Declarations;
-using Plang.Compiler.TypeChecker.AST.Expressions;
-
-namespace Plang.Compiler.TypeChecker;
-
-public class ConstraintVariableCollector
-{
-
- public static HashSet FindVariablesRecursive(IPExpr expr)
- {
- switch (expr)
- {
- case BinOpExpr binOp:
- return FindVariablesRecursive(binOp.Lhs).Union(FindVariablesRecursive(binOp.Rhs)).ToHashSet();
- case NamedTupleAccessExpr namedTupleAccessExpr:
- return FindVariablesRecursive(namedTupleAccessExpr.SubExpr);
- case VariableAccessExpr variableAccessExpr:
- return new HashSet() { variableAccessExpr.Variable };
- case EnumElemRefExpr:
- case StringExpr:
- case IntLiteralExpr:
- break;
- default:
- throw new ArgumentOutOfRangeException(nameof(expr));
- }
-
- return new HashSet();
- }
-}
\ No newline at end of file
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/ControlFlowChecker.cs b/Src/PCompiler/CompilerCore/TypeChecker/ControlFlowChecker.cs
index bddcbbf892..ea09002934 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/ControlFlowChecker.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/ControlFlowChecker.cs
@@ -84,7 +84,6 @@ private void CheckStmt(IPStmt stmt)
case RemoveStmt _:
case ReturnStmt _:
case SendStmt _:
- case ConstraintStmt _:
break;
default:
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/DeclarationStubVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/DeclarationStubVisitor.cs
index c2bf47b518..77782e7308 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/DeclarationStubVisitor.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/DeclarationStubVisitor.cs
@@ -163,26 +163,6 @@ public override object VisitStateDecl(PParser.StateDeclContext context)
#endregion Machines
- #region Scenario
-
- public override object VisitScenarioDecl(PParser.ScenarioDeclContext context)
- {
- var scenarioName = context.scenarioName.GetText();
- var scenario = CurrentScope.Put(scenarioName, context);
- nodesToDeclarations.Put(context, scenario);
- return VisitChildrenWithNewScope(scenario, context);
- }
-
- public override object VisitScenarioParam(PParser.ScenarioParamContext context)
- {
- var symbolName = context.name.GetText();
- var decl = CurrentScope.Put(symbolName, context, VariableRole.Param);
- nodesToDeclarations.Put(context, decl);
- return null;
- }
-
- #endregion
-
#region Functions
public override object VisitPFunDecl(PParser.PFunDeclContext context)
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/DeclarationVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/DeclarationVisitor.cs
index 0c02c0a2a9..82faffc717 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/DeclarationVisitor.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/DeclarationVisitor.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
-using System.Runtime.CompilerServices;
using Antlr4.Runtime.Tree;
using Plang.Compiler.TypeChecker.AST;
using Plang.Compiler.TypeChecker.AST.Declarations;
@@ -349,30 +348,7 @@ public override object VisitSpecMachineDecl(PParser.SpecMachineDeclContext conte
return specMachine;
}
-
- public override object VisitScenarioDecl(PParser.ScenarioDeclContext context)
- {
- var scenario = (Function)nodesToDeclarations.Get(context);
- var result = ((Variable, PEvent)[]) Visit(context.scenarioParamList());
- scenario.Signature.Parameters.AddRange(result.Select(it => it.Item1));
- scenario.Signature.ParameterEvents.AddRange(result.Select(it => it.Item2));
- scenario.Signature.ReturnType = PrimitiveType.Int;
- scenario.Role = FunctionRole.Scenario;
- return scenario;
- }
-
- public override object VisitScenarioParamList(PParser.ScenarioParamListContext context)
- {
- return context.scenarioParam().Select(Visit).Cast<(Variable, PEvent)>().ToArray();
- }
-
- public override object VisitScenarioParam(PParser.ScenarioParamContext context)
- {
- var param = (Variable) nodesToDeclarations.Get(context);
- var e = (PEvent) Visit(context.nonDefaultEvent());
- return (param, e);
- }
-
+
public override object VisitMachineBody(PParser.MachineBodyContext context)
{
foreach (var machineEntryContext in context.machineEntry())
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs
index 3b5c325c78..7a85bf6e84 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs
@@ -12,18 +12,6 @@ namespace Plang.Compiler.TypeChecker
{
public class ExprVisitor : PParserBaseVisitor
{
- public static readonly string EventFieldSender = "MSG_sender";
- public static readonly string EventFieldReceiver = "MSG_receiver";
- public static readonly string EventFieldState = "MSG_state";
- public static readonly string EventFieldIndex = "MSG_index";
-
- public static Dictionary ReservedEventFeilds = new Dictionary()
- {
- { EventFieldSender, new NamedTupleEntry("Sender", -1, PrimitiveType.String) },
- { EventFieldReceiver, new NamedTupleEntry("Receiver", -1, PrimitiveType.String) },
- { EventFieldState, new NamedTupleEntry("State", -1, PrimitiveType.String) },
- { EventFieldIndex, new NamedTupleEntry("Index", -1, PrimitiveType.Int) },
- };
private readonly ITranslationErrorHandler handler;
private readonly Function method;
private readonly Scope table;
@@ -58,18 +46,11 @@ public override IPExpr VisitParenExpr(PParser.ParenExprContext context)
public override IPExpr VisitNamedTupleAccessExpr(PParser.NamedTupleAccessExprContext context)
{
var subExpr = Visit(context.expr());
- var fieldName = context.field.GetText();
- if (subExpr is VariableAccessExpr v && method.Role == FunctionRole.Scenario && method.Signature.Parameters.Contains(v.Variable))
- {
- if (ReservedEventFeilds.TryGetValue(fieldName, out var reservedEntry))
- {
- return new NamedTupleAccessExpr(context, subExpr, reservedEntry);
- }
- }
if (!(subExpr.Type.Canonicalize() is NamedTupleType tuple))
{
throw handler.TypeMismatch(subExpr, TypeKind.NamedTuple);
}
+ var fieldName = context.field.GetText();
if (!tuple.LookupEntry(fieldName, out var entry))
{
throw handler.MissingNamedTupleEntry(context.field, tuple);
@@ -627,7 +608,7 @@ public override IPExpr VisitNamedTupleBody(PParser.NamedTupleBodyContext context
}
names.Add(entryName);
- entries[i] = new NamedTupleEntry(name: entryName, fieldNo: i, type: fields[i].Type);
+ entries[i] = new NamedTupleEntry { Name = entryName, FieldNo = i, Type = fields[i].Type };
}
var type = new NamedTupleType(entries);
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/FunctionBodyVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/FunctionBodyVisitor.cs
index b3572fb73f..2cb0b21eb3 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/FunctionBodyVisitor.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/FunctionBodyVisitor.cs
@@ -1,9 +1,6 @@
-using System.Collections.Generic;
using System.Diagnostics.Contracts;
-using Plang.Compiler.TypeChecker.AST;
using Plang.Compiler.TypeChecker.AST.Declarations;
using Plang.Compiler.TypeChecker.AST.Statements;
-using Plang.Compiler.TypeChecker.Types;
namespace Plang.Compiler.TypeChecker
{
@@ -63,30 +60,6 @@ public override object VisitFunctionBody(PParser.FunctionBodyContext context)
return null;
}
- public override object VisitScenarioDecl(PParser.ScenarioDeclContext context)
- {
- return Visit(context.scenarioBody());
- }
-
- public override object VisitScenarioBody(PParser.ScenarioBodyContext context)
- {
- var exprVisitor = new ExprVisitor(method, config.Handler);
- // var compound = new CompoundStmt(context, new IPStmt[0]);
- var stmts = new List();
- foreach (var exprContext in context.expr())
- {
- var constraint = exprVisitor.Visit(exprContext);
- if (!Equals(constraint.Type, PrimitiveType.Bool))
- {
- throw config.Handler.TypeMismatch(exprContext, constraint.Type, PrimitiveType.Bool);
- }
- stmts.Add( new ConstraintStmt(exprContext, constraint));
- }
-
- method.Body = new CompoundStmt(context, stmts);
- return null;
- }
-
public override object VisitVarDecl(PParser.VarDeclContext context)
{
foreach (var varName in context.idenList()._names)
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/FunctionValidator.cs b/Src/PCompiler/CompilerCore/TypeChecker/FunctionValidator.cs
index 35bd8a3be4..16b1204a1a 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/FunctionValidator.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/FunctionValidator.cs
@@ -11,7 +11,7 @@ public static class FunctionValidator
{
public static void CheckAllPathsReturn(ITranslationErrorHandler handler, Function function)
{
- if (function.IsForeign || function.Role == FunctionRole.Scenario)
+ if (function.IsForeign)
{
return;
}
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/ScenarioEventVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/ScenarioEventVisitor.cs
deleted file mode 100644
index 3cd4518397..0000000000
--- a/Src/PCompiler/CompilerCore/TypeChecker/ScenarioEventVisitor.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using Antlr4.Runtime.Tree;
-using Plang.Compiler.TypeChecker.AST;
-using Plang.Compiler.TypeChecker.AST.Declarations;
-
-namespace Plang.Compiler.TypeChecker;
-
-public class ScenarioEventVisitor
-{
-
- public static void PopulateEventTypes(Function function)
- {
- if (function.Role != FunctionRole.Scenario) return;
- for (var i = 0; i < function.Signature.Parameters.Count; i++)
- {
- var v = function.Signature.Parameters[i];
- var e = function.Signature.ParameterEvents[i];
- v.Type = e.PayloadType;
- }
- }
-}
\ No newline at end of file
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Scope.cs b/Src/PCompiler/CompilerCore/TypeChecker/Scope.cs
index 22dc0b4bc8..9eff2b90ce 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/Scope.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/Scope.cs
@@ -518,14 +518,6 @@ public Interface Put(string name, PParser.InterfaceDeclContext tree)
return machineInterface;
}
- public Function Put(string name, PParser.ScenarioDeclContext tree)
- {
- var scenario = new Function(name, tree);
- CheckConflicts(scenario, Namespace(functions));
- functions.Add(name, scenario);
- return scenario;
- }
-
public Machine Put(string name, PParser.ImplMachineDeclContext tree)
{
var machine = new Machine(name, tree);
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/TypeResolver.cs b/Src/PCompiler/CompilerCore/TypeChecker/TypeResolver.cs
index 3fb843d8d9..39b22c3681 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/TypeResolver.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/TypeResolver.cs
@@ -121,7 +121,7 @@ public override PLanguageType VisitNamedTupleType(PParser.NamedTupleTypeContext
}
names.Add(fieldName);
- fields[i] = new NamedTupleEntry(name: fieldName, fieldNo: i, type: Visit(field.type()));
+ fields[i] = new NamedTupleEntry { Name = fieldName, FieldNo = i, Type = Visit(field.type()) };
}
var ret = new NamedTupleType(fields);
diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/NamedTupleEntry.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/NamedTupleEntry.cs
index 89ad48ae17..f9223f79c4 100644
--- a/Src/PCompiler/CompilerCore/TypeChecker/Types/NamedTupleEntry.cs
+++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/NamedTupleEntry.cs
@@ -2,17 +2,6 @@ namespace Plang.Compiler.TypeChecker.Types
{
public class NamedTupleEntry
{
- public NamedTupleEntry()
- {
- }
-
- public NamedTupleEntry(string name, int fieldNo, PLanguageType type)
- {
- Name = name;
- FieldNo = fieldNo;
- Type = type;
- }
-
public string Name { get; set; }
public int FieldNo { get; set; }
public PLanguageType Type { get; set; }
From 61fa8d325213b93234fca577c886411636e9dead Mon Sep 17 00:00:00 2001
From: Ao Li
Date: Thu, 10 Oct 2024 16:00:52 +0800
Subject: [PATCH 09/21] Cleanup.
---
.../SystematicTesting/ControlledRuntime.cs | 1 -
.../SystematicTesting/OperationScheduler.cs | 4 +-
.../Operations/AsyncOperation.cs | 5 ++-
.../SystematicTesting/Strategies/Utils.cs | 44 -------------------
.../SystematicTesting/TestingEngine.cs | 13 ++----
.../PCommandLine/Options/PCheckerOptions.cs | 5 ---
6 files changed, 9 insertions(+), 63 deletions(-)
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Utils.cs
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs b/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
index 2ed17adb40..ee4f21507e 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
@@ -459,7 +459,6 @@ private EnqueueStatus EnqueueEvent(ActorId targetId, Event e, Actor sender, Guid
"Cannot send event '{0}' to actor id '{1}' that is not bound to an actor instance.",
e.GetType().FullName, targetId.Value);
- Scheduler.ScheduledOperation.LastEvent = e;
Scheduler.ScheduledOperation.LastSentReceiver = targetId.ToString();
Scheduler.ScheduleNextEnabledOperation(AsyncOperationType.Send);
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/OperationScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/OperationScheduler.cs
index a148bd4586..e21e6770e2 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/OperationScheduler.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/OperationScheduler.cs
@@ -150,7 +150,7 @@ internal void ScheduleNextEnabledOperation(AsyncOperationType type)
}
// Get and order the operations by their id.
- var ops = OperationMap.Values.OrderBy(op => op.Id).ToList();
+ var ops = OperationMap.Values.OrderBy(op => op.Id);
// Try enable any operation that is currently waiting, but has its dependencies already satisfied.
foreach (var op in ops)
@@ -162,8 +162,6 @@ internal void ScheduleNextEnabledOperation(AsyncOperationType type)
}
}
- // ops = Utils.FindHighPriorityOperations(ops, CheckerConfiguration.InterestingEvents);
-
if (!Strategy.GetNextOperation(current, ops, out var next))
{
// Checks if the program has deadlocked.
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs b/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs
index a94337e3a8..46d7112852 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs
@@ -50,7 +50,10 @@ internal abstract class AsyncOperation : IAsyncOperation
/// True if the next awaiter is controlled, else false.
///
internal bool IsAwaiterControlled;
- public Event? LastEvent = null;
+
+ ///
+ /// The receiver if the operation is Send.
+ ///
public string LastSentReceiver = "";
///
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Utils.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Utils.cs
deleted file mode 100644
index d4b3a8a0c1..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Utils.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using PChecker.SystematicTesting.Operations;
-
-namespace PChecker.SystematicTesting.Strategies;
-
-public class Utils
-{
- internal static List FindHighPriorityOperations(IEnumerable ops, HashSet interestingEvents)
- {
- var highOps = ops.Where(it =>
-
- {
- if (it.Status == AsyncOperationStatus.Enabled)
- {
- if (it is ActorOperation act)
- {
- if (act.Type == AsyncOperationType.Send)
- {
- if (act.LastEvent != null)
- {
- return !interestingEvents.Contains(act.LastEvent.GetType());
- }
- return false;
- }
- }
- return true;
- }
- return false;
- }
- ).ToList();
- if (highOps.Count != 0)
- {
- return highOps;
- }
- return ops.Where(
- op =>
- {
- return op.Status is AsyncOperationStatus.Enabled;
- }
- ).ToList();
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
index d15d8316d4..4ada617a5a 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
@@ -179,7 +179,6 @@ public static TestingEngine Create(CheckerConfiguration checkerConfiguration) =>
Create(checkerConfiguration, LoadAssembly(checkerConfiguration.AssemblyToBeAnalyzed));
private Stopwatch watch;
- private bool ShouldEmitTrace;
///
/// Creates a new systematic testing engine.
@@ -211,13 +210,10 @@ public static TestingEngine Create(CheckerConfiguration checkerConfiguration, As
{
testMethodInfo = TestMethodInfo.GetFromAssembly(assembly, checkerConfiguration.TestCaseName);
Console.Out.WriteLine($".. Test case :: {testMethodInfo.Name}");
-
- Type t = assembly.GetType("PImplementation.GlobalFunctions");
}
catch
{
- Error.ReportAndExit(
- $"Failed to get test method '{checkerConfiguration.TestCaseName}' from assembly '{assembly.FullName}'");
+ Error.ReportAndExit($"Failed to get test method '{checkerConfiguration.TestCaseName}' from assembly '{assembly.FullName}'");
}
return new TestingEngine(checkerConfiguration, testMethodInfo);
@@ -449,7 +445,7 @@ private System.Threading.Tasks.Task CreateTestingTask()
var options = string.Empty;
if (_checkerConfiguration.SchedulingStrategy is "random" ||
_checkerConfiguration.SchedulingStrategy is "pct" ||
- _checkerConfiguration.SchedulingStrategy is "poc" ||
+ _checkerConfiguration.SchedulingStrategy is "pos" ||
_checkerConfiguration.SchedulingStrategy is "feedbackpct" ||
_checkerConfiguration.SchedulingStrategy is "feedbackpctcp" ||
_checkerConfiguration.SchedulingStrategy is "feedbackpos" ||
@@ -589,7 +585,6 @@ private void RunNextIteration(int schedule)
try
{
- ShouldEmitTrace = false;
// Creates a new instance of the controlled runtime.
runtime = new ControlledRuntime(_checkerConfiguration, Strategy, RandomValueGenerator);
@@ -651,7 +646,7 @@ private void RunNextIteration(int schedule)
GatherTestingStatistics(runtime, timelineObserver);
- if (ShouldEmitTrace || (!IsReplayModeEnabled && TestReport.NumOfFoundBugs > 0))
+ if (!IsReplayModeEnabled && TestReport.NumOfFoundBugs > 0)
{
if (runtimeLogger != null)
{
@@ -840,7 +835,7 @@ public void TryEmitTraces(string directory, string file)
Logger.WriteLine($"..... Writing {graphPath}");
}
- if (!_checkerConfiguration.PerformFullExploration || ShouldEmitTrace)
+ if (!_checkerConfiguration.PerformFullExploration)
{
// Emits the reproducable trace, if it exists.
if (!string.IsNullOrEmpty(ReproducableTrace))
diff --git a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
index 6b62e9f69d..5e73759ffb 100644
--- a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
+++ b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
@@ -233,20 +233,15 @@ private static void UpdateConfigurationWithParsedArgument(CheckerConfiguration c
checkerConfiguration.RandomGeneratorSeed = (uint)option.Value;
break;
case "sch-random":
- case "sch-rff":
case "sch-pos":
case "sch-feedbackpos":
case "sch-feedback":
- case "sch-2stagefeedback":
checkerConfiguration.SchedulingStrategy = option.LongName.Substring(4);
break;
case "sch-probabilistic":
case "sch-pct":
- case "sch-pctcp":
case "sch-fairpct":
case "sch-feedbackpct":
- case "sch-feedbackpctcp":
- case "sch-2stagefeedbackpct":
checkerConfiguration.SchedulingStrategy = option.LongName.Substring(4);
checkerConfiguration.StrategyBound = (int)(uint)option.Value;
break;
From 548f0f6b8246c0374bdfc37cd4a7fb3b03df1b72 Mon Sep 17 00:00:00 2001
From: Ao Li
Date: Thu, 10 Oct 2024 16:13:41 +0800
Subject: [PATCH 10/21] Revert changes to Event.
---
Src/PChecker/CheckerCore/Actors/ActorRuntime.cs | 2 --
Src/PChecker/CheckerCore/Actors/Events/Event.cs | 4 ----
Src/PChecker/CheckerCore/PRuntime/PMachine.cs | 2 --
Src/PChecker/CheckerCore/Specifications/Monitor.cs | 1 -
.../Strategies/Feedback/Coverage/ISendEventMonitor.cs | 8 --------
.../Strategies/Feedback/Coverage/Operation.cs | 9 ---------
6 files changed, 26 deletions(-)
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ISendEventMonitor.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/Operation.cs
diff --git a/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs b/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs
index 690f06c901..1959d9c76e 100644
--- a/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs
+++ b/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs
@@ -264,8 +264,6 @@ private Actor CreateActor(ActorId id, Type type, string name, Actor creator, Gui
///
internal virtual void SendEvent(ActorId targetId, Event e, Actor sender, Guid opGroupId)
{
- e.Sender = sender.ToString();
- e.Receiver = targetId.ToString();
var enqueueStatus = EnqueueEvent(targetId, e, sender, opGroupId, out var target);
if (enqueueStatus is EnqueueStatus.EventHandlerNotRunning)
{
diff --git a/Src/PChecker/CheckerCore/Actors/Events/Event.cs b/Src/PChecker/CheckerCore/Actors/Events/Event.cs
index 57917c052b..a33f298172 100644
--- a/Src/PChecker/CheckerCore/Actors/Events/Event.cs
+++ b/Src/PChecker/CheckerCore/Actors/Events/Event.cs
@@ -11,9 +11,5 @@ namespace PChecker.Actors.Events
[DataContract]
public abstract class Event
{
- public string? Sender;
- public string? Receiver;
- public string? State;
- public int Index;
}
}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/PRuntime/PMachine.cs b/Src/PChecker/CheckerCore/PRuntime/PMachine.cs
index d95b2e38de..92014533ab 100644
--- a/Src/PChecker/CheckerCore/PRuntime/PMachine.cs
+++ b/Src/PChecker/CheckerCore/PRuntime/PMachine.cs
@@ -86,8 +86,6 @@ public void TrySendEvent(PMachineValue target, Event ev, object payload = null)
var oneArgConstructor = ev.GetType().GetConstructors().First(x => x.GetParameters().Length > 0);
ev = (Event)oneArgConstructor.Invoke(new[] { payload });
- ev.Sender = Id.ToString();
- ev.Receiver = target.Id.ToString();
AnnounceInternal(ev);
SendEvent(target.Id, ev);
}
diff --git a/Src/PChecker/CheckerCore/Specifications/Monitor.cs b/Src/PChecker/CheckerCore/Specifications/Monitor.cs
index 5314899c18..acf62c8dc9 100644
--- a/Src/PChecker/CheckerCore/Specifications/Monitor.cs
+++ b/Src/PChecker/CheckerCore/Specifications/Monitor.cs
@@ -275,7 +275,6 @@ protected void Assert(bool predicate, string s, params object[] args)
///
internal void MonitorEvent(Event e, string senderName, string senderType, string senderState)
{
- e.Sender = senderName;
Runtime.LogWriter.LogMonitorProcessEvent(GetType().FullName, CurrentStateName,
senderName, senderType, senderState, e);
HandleEvent(e);
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ISendEventMonitor.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ISendEventMonitor.cs
deleted file mode 100644
index 28014d7d24..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/ISendEventMonitor.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using PChecker.Actors;
-using PChecker.Actors.Logging;
-
-public interface ISendEventMonitor {
- public void OnSendEvent(ActorId sender, int loc, ActorId receiver, VectorClockGenerator currentVc);
-
- public void OnSendEventDone(ActorId sender, int loc, ActorId receiver, VectorClockGenerator currentVc);
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/Operation.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/Operation.cs
deleted file mode 100644
index 4af176c918..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/Operation.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace PChecker.Feedback;
-
-public record Operation(string Sender, string Receiver, int Loc) {
- public override string ToString()
- {
- return $"<{Sender}, {Receiver}, {Loc}>";
- }
-
-}
From 52dc10a01348ae105ffd103792c286c5fb19bdc2 Mon Sep 17 00:00:00 2001
From: Ao Li
Date: Fri, 11 Oct 2024 09:38:35 +0800
Subject: [PATCH 11/21] Revert changes.
---
.../CheckerCore/Actors/ActorRuntime.cs | 1 +
.../CheckerCore/Actors/Logging/JsonWriter.cs | 73 +++++++++----------
.../CheckerCore/Actors/Logging/LogWriter.cs | 1 +
.../CheckerCore/CheckerConfiguration.cs | 4 +-
.../SystematicTesting/TestingEngine.cs | 5 +-
5 files changed, 39 insertions(+), 45 deletions(-)
diff --git a/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs b/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs
index 1959d9c76e..021067e972 100644
--- a/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs
+++ b/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs
@@ -16,6 +16,7 @@
using PChecker.Actors.Managers;
using PChecker.Random;
using PChecker.Runtime;
+using PChecker.Runtime.Logging;
using PChecker.Specifications.Monitors;
using EventInfo = PChecker.Actors.Events.EventInfo;
diff --git a/Src/PChecker/CheckerCore/Actors/Logging/JsonWriter.cs b/Src/PChecker/CheckerCore/Actors/Logging/JsonWriter.cs
index acc6adc74f..a546bae0f2 100644
--- a/Src/PChecker/CheckerCore/Actors/Logging/JsonWriter.cs
+++ b/Src/PChecker/CheckerCore/Actors/Logging/JsonWriter.cs
@@ -6,16 +6,16 @@
using System.Security.Cryptography;
using System.Text;
-namespace PChecker.Actors.Logging
+namespace PChecker.Runtime.Logging
{
///
/// Class for handling generating the vector clock for a log entry
///
- public class VectorClockGenerator
+ internal class VectorClockGenerator
{
///
/// Nested class for handling FIFO send receive requests.
- /// NOTE: In the case of sending to a the same machine with the same event and same payload.
+ /// NOTE: In the case of sending to the same machine with the same event and same payload.
///
private class FifoSendReceiveMapping
{
@@ -61,7 +61,7 @@ internal FifoSendReceiveMapping()
///
/// Field declaration that keeps track of a global vector clock map of all the machines.
///
- public readonly Dictionary> ContextVcMap;
+ private readonly Dictionary> _contextVcMap;
///
/// Field declaration that keeps track of unprocessed send requests. I.e., when a send request happened
@@ -85,7 +85,7 @@ internal FifoSendReceiveMapping()
///
public VectorClockGenerator()
{
- ContextVcMap = new Dictionary>();
+ _contextVcMap = new Dictionary>();
_unhandledSendRequests = new Dictionary>();
_machines = new HashSet();
_sendRequestsCount = new Dictionary();
@@ -205,7 +205,7 @@ private void updateMachineVcMap(string machine, Dictionary senderVc
{
// Get a set of all machine names to update between the sender vc map and the current machine vc map (minus the current machine)
var machinesToUpdateInVc =
- new HashSet(ContextVcMap[machine].Keys.Union(senderVcMap.Keys).Except(new[] { machine }));
+ new HashSet(_contextVcMap[machine].Keys.Union(senderVcMap.Keys).Except(new[] { machine }));
// Update local machine's vector clock in _contextVcMap, outside of itself, since it was already updated (incremented) from above
// right before the switch case.
@@ -213,17 +213,17 @@ private void updateMachineVcMap(string machine, Dictionary senderVc
// the current machine's vector clock. Details can be found here: https://en.wikipedia.org/wiki/Vector_clock
foreach (var machineToUpdate in machinesToUpdateInVc)
{
- if (ContextVcMap[machine].TryGetValue(machineToUpdate, out var localMachineToUpdateValue))
+ if (_contextVcMap[machine].TryGetValue(machineToUpdate, out var localMachineToUpdateValue))
{
if (senderVcMap.TryGetValue(machineToUpdate, out var senderMachineToUpdateValue))
{
- ContextVcMap[machine][machineToUpdate] =
+ _contextVcMap[machine][machineToUpdate] =
Math.Max(senderMachineToUpdateValue, localMachineToUpdateValue);
}
}
else
{
- ContextVcMap[machine].Add(machineToUpdate, senderVcMap[machineToUpdate]);
+ _contextVcMap[machine].Add(machineToUpdate, senderVcMap[machineToUpdate]);
}
}
}
@@ -243,11 +243,11 @@ public void HandleLogEntry(LogEntry logEntry)
if (MachineIsNew(machine))
{
_machines.Add(machine);
- ContextVcMap.Add(machine, new Dictionary { { machine, 0 } });
+ _contextVcMap.Add(machine, new Dictionary { { machine, 0 } });
}
// Always update the local machine count by one on any event.
- ContextVcMap[machine][machine] += 1;
+ _contextVcMap[machine][machine] += 1;
switch (logType)
{
@@ -273,13 +273,13 @@ public void HandleLogEntry(LogEntry logEntry)
// Update the sendReqId with the send count of it.
sendReqId += $":_{_sendRequestsCount[hashedGeneralSendReqId].SentCount}";
var hashedSendReqId = HashString(sendReqId);
- _unhandledSendRequests.Add(hashedSendReqId, CopyVcMap(ContextVcMap[machine]));
+ _unhandledSendRequests.Add(hashedSendReqId, CopyVcMap(_contextVcMap[machine]));
break;
// For MonitorProcessEvents, tie it to the senderMachine's current vector clock
// so that there is some association in the timeline
case "MonitorProcessEvent":
- if (logDetails.Sender != null) updateMachineVcMap(machine, ContextVcMap[logDetails.Sender]);
+ if (logDetails.Sender != null) updateMachineVcMap(machine, _contextVcMap[logDetails.Sender]);
break;
// On dequeue OR receive event, has the string containing information about the current machine that dequeued (i.e. received the event),
@@ -317,7 +317,7 @@ public void HandleLogEntry(LogEntry logEntry)
}
// Update the log entry with the vector clock.
- logEntry.Details.Clock = CopyVcMap(ContextVcMap[machine]);
+ logEntry.Details.Clock = CopyVcMap(_contextVcMap[machine]);
}
}
@@ -349,23 +349,23 @@ public LogEntry()
/// Enum representing the possible attributes in the details dictionary,
/// which represents the data associated with a specific log type. All of
/// the following are available or expanded parameters associated with an
- /// IActorRuntime method. Naming for them is mostly the same except some
+ /// ControlledRuntime method. Naming for them is mostly the same except some
/// are changed for simplicity.
- /// I.e., for OnRaiseEvent(ActorId id, string, stateName, Event e), it
+ /// I.e., for OnRaiseEvent(StateMachineId id, string, stateName, Event e), it
/// will have attributes id, state (simplified from stateName, event
/// (simplified from eventName within Event e), and payload (in Event e).
///
public class LogDetails
{
///
- /// The text log from PLogFormatter. Removes the log tags.
+ /// The text log from PCheckerLogTextFormatter. Removes the log tags.
/// I.e., no <SomeLog> in the beginning.
/// Available for all log types.
///
public string? Log { get; set; }
///
- /// The actor id.
+ /// The state machine id.
///
public string? Id { get; set; }
@@ -437,7 +437,7 @@ public class LogDetails
public int? HaltInboxSize { get; set; }
///
- /// Boolean representing whether an actor was waiting for one or more events
+ /// Boolean representing whether an state machine was waiting for one or more events
/// Available for log type ReceiveEvent.
///
public bool? WasBlocked { get; set; }
@@ -449,7 +449,7 @@ public class LogDetails
public string? Sender { get; set; }
///
- /// Id of target actor.
+ /// Id of target state machine.
/// Available for log type SendEvent.
///
public string? Target { get; set; }
@@ -461,7 +461,7 @@ public class LogDetails
public string? OpGroupId { get; set; }
///
- /// Boolean representing whether the target actor was halted.
+ /// Boolean representing whether the target state machine was halted.
/// Available for log type SendEvent.
///
public bool? IsTargetHalted { get; set; }
@@ -533,7 +533,7 @@ public class JsonWriter
///
/// Vector clock generator instance to help with vector clock generation.
///
- internal VectorClockGenerator VcGenerator {get;}
+ private readonly VectorClockGenerator _vcGenerator;
///
/// Getter for accessing log entry details.
@@ -552,13 +552,13 @@ public JsonWriter()
{
_logs = new List();
_log = new LogEntry();
- VcGenerator = new VectorClockGenerator();
+ _vcGenerator = new VectorClockGenerator();
}
///
/// Enum representing the different log types the JSON error trace logs.
- /// Referenced from PLogFormatter.cs and ActorRuntimeLogTextFormatter.cs
- /// to see what those formatter logs. Check IActorRuntimeLog.cs to see
+ /// Referenced from PCheckerLogTextFormatter.cs and PCheckerLogTextFormatter.cs
+ /// to see what those formatter logs. Check IControlledRuntimeLog.cs to see
/// each log types' description and when they are invoked.
///
public enum LogType
@@ -568,11 +568,6 @@ public enum LogType
///
AssertionFailure,
- ///
- /// Invoked when the specified actor has been created.
- ///
- CreateActor,
-
///
/// Invoked when the specified state machine has been created.
///
@@ -584,13 +579,13 @@ public enum LogType
CreateMonitor,
///
- /// Invoked when the specified actor is idle (there is nothing to dequeue) and the default
+ /// Invoked when the specified state machine is idle (there is nothing to dequeue) and the default
/// event handler is about to be executed.
///
DefaultEventHandler,
///
- /// Invoked when the specified event is dequeued by an actor.
+ /// Invoked when the specified event is dequeued by an state machine.
///
DequeueEvent,
@@ -600,7 +595,7 @@ public enum LogType
ExceptionHandled,
///
- /// Invoked when the specified actor throws an exception.
+ /// Invoked when the specified state machine throws an exception.
///
ExceptionThrown,
@@ -610,7 +605,7 @@ public enum LogType
GotoState,
///
- /// Invoked when the specified actor has been halted.
+ /// Invoked when the specified state machine has been halted.
///
Halt,
@@ -652,12 +647,12 @@ public enum LogType
RaiseEvent,
///
- /// Invoked when the specified event is received by an actor.
+ /// Invoked when the specified event is received by an state machine.
///
ReceiveEvent,
///
- /// Invoked when the specified event is sent to a target actor.
+ /// Invoked when the specified event is sent to a target state machine.
///
SendEvent,
@@ -672,12 +667,12 @@ public enum LogType
StrategyDescription,
///
- /// Invoked when the specified actor waits to receive an event of a specified type.
+ /// Invoked when the specified state machine waits to receive an event of a specified type.
///
WaitEvent,
///
- /// Invoked when the specified actor waits to receive multiple events of a specified type.
+ /// Invoked when the specified state machine waits to receive multiple events of a specified type.
///
WaitMultipleEvents,
@@ -716,7 +711,7 @@ public void AddToLogs(bool updateVcMap = false)
{
if (updateVcMap)
{
- VcGenerator.HandleLogEntry(_log);
+ _vcGenerator.HandleLogEntry(_log);
}
_logs.Add(_log);
diff --git a/Src/PChecker/CheckerCore/Actors/Logging/LogWriter.cs b/Src/PChecker/CheckerCore/Actors/Logging/LogWriter.cs
index aad60d8aab..29b8f5aff8 100644
--- a/Src/PChecker/CheckerCore/Actors/Logging/LogWriter.cs
+++ b/Src/PChecker/CheckerCore/Actors/Logging/LogWriter.cs
@@ -7,6 +7,7 @@
using System.Linq;
using PChecker.Actors.Events;
using PChecker.IO.Logging;
+using PChecker.Runtime.Logging;
namespace PChecker.Actors.Logging
{
diff --git a/Src/PChecker/CheckerCore/CheckerConfiguration.cs b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
index bc296da11c..716f57a70d 100644
--- a/Src/PChecker/CheckerCore/CheckerConfiguration.cs
+++ b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
@@ -229,7 +229,7 @@ public int MaxSchedulingSteps
/// Defaults to true.
///
[DataMember]
- public bool IsJsonLogEnabled { get; set; } = false;
+ public bool IsJsonLogEnabled { get; set; } = true;
///
/// If specified, requests a custom runtime log to be used instead of the default.
@@ -308,7 +308,7 @@ protected CheckerConfiguration()
RandomGeneratorSeed = null;
IncrementalSchedulingSeed = false;
PerformFullExploration = false;
- MaxFairSchedulingSteps = 10000; // 10 times the unfair steps
+ MaxFairSchedulingSteps = 100000; // 10 times the unfair steps
MaxUnfairSchedulingSteps = 10000;
UserExplicitlySetMaxFairSchedulingSteps = false;
TestingProcessId = 0;
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
index 4ada617a5a..9a4b45c375 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
@@ -26,6 +26,7 @@
using PChecker.IO.Logging;
using PChecker.Random;
using PChecker.Runtime;
+using PChecker.Runtime.Logging;
using PChecker.SystematicTesting.Strategies;
using PChecker.SystematicTesting.Strategies.Exhaustive;
using PChecker.SystematicTesting.Strategies.Feedback;
@@ -1102,10 +1103,6 @@ private bool ShouldPrintIteration(int schedule)
var count = schedule.ToString().Length - 1;
var guard = "1" + (count > 0 ? string.Concat(Enumerable.Repeat("0", count)) : string.Empty);
PrintGuard = int.Parse(guard);
- if (PrintGuard > 1000)
- {
- PrintGuard = 1000;
- }
}
return schedule % PrintGuard == 0;
From 8510ec41b336f7be1b957563eeeb67e5096c94e4 Mon Sep 17 00:00:00 2001
From: Ao Li
Date: Fri, 11 Oct 2024 10:04:12 +0800
Subject: [PATCH 12/21] Fix merge conflicts.
---
.../Operations/AsyncOperation.cs | 1 -
.../Feedback/Coverage/TimelineObserver.cs | 147 +++++++++++++++---
2 files changed, 127 insertions(+), 21 deletions(-)
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs b/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs
index 46d7112852..47d4da8cab 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-using PChecker.Actors.Events;
#if !DEBUG
using System.Diagnostics;
#endif
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/TimelineObserver.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/TimelineObserver.cs
index b4503e52a2..e58aacb20b 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/TimelineObserver.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/TimelineObserver.cs
@@ -1,18 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using PChecker.Actors;
-using PChecker.Actors.Events;
-using PChecker.Actors.Logging;
+using PChecker.Runtime.Events;
+using PChecker.Runtime.Logging;
+using PChecker.Runtime.StateMachines;
namespace PChecker.Feedback;
-internal class TimelineObserver: ActorRuntimeLogBase
+internal class TimelineObserver: IControlledRuntimeLog
{
private HashSet<(string, string, string)> _timelines = new();
private Dictionary> _allEvents = new();
private Dictionary> _orderedEvents = new();
+ private IControlledRuntimeLog _controlledRuntimeLogImplementation;
public static readonly List<(int, int)> Coefficients = new();
public static int NumOfCoefficients = 50;
@@ -28,22 +29,6 @@ static TimelineObserver()
}
}
- public override void OnDequeueEvent(ActorId id, string stateName, Event e)
- {
- string actor = id.Type;
-
- _allEvents.TryAdd(actor, new());
- _orderedEvents.TryAdd(actor, new());
-
- string name = e.GetType().Name;
- foreach (var ev in _allEvents[actor])
- {
- _timelines.Add((actor, ev, name));
- }
- _allEvents[actor].Add(name);
- _orderedEvents[actor].Add(name);
- }
-
public int GetTimelineHash()
{
return GetAbstractTimeline().GetHashCode();
@@ -81,4 +66,126 @@ public List GetTimelineMinhash()
}
return minHash;
}
+
+ public void OnCreateStateMachine(StateMachineId id, string creatorName, string creatorType)
+ {
+ }
+
+ public void OnExecuteAction(StateMachineId id, string handlingStateName, string currentStateName, string actionName)
+ {
+ }
+
+ public void OnSendEvent(StateMachineId targetStateMachineId, string senderName, string senderType, string senderStateName,
+ Event e, bool isTargetHalted)
+ {
+ }
+
+ public void OnRaiseEvent(StateMachineId id, string stateName, Event e)
+ {
+ }
+
+ public void OnEnqueueEvent(StateMachineId id, Event e)
+ {
+ }
+
+ public void OnDequeueEvent(StateMachineId id, string stateName, Event e)
+ {
+ string actor = id.Type;
+
+ _allEvents.TryAdd(actor, new());
+ _orderedEvents.TryAdd(actor, new());
+
+ string name = e.GetType().Name;
+ foreach (var ev in _allEvents[actor])
+ {
+ _timelines.Add((actor, ev, name));
+ }
+ _allEvents[actor].Add(name);
+ _orderedEvents[actor].Add(name);
+ }
+
+ public void OnReceiveEvent(StateMachineId id, string stateName, Event e, bool wasBlocked)
+ {
+ }
+
+ public void OnWaitEvent(StateMachineId id, string stateName, Type eventType)
+ {
+ }
+
+ public void OnWaitEvent(StateMachineId id, string stateName, params Type[] eventTypes)
+ {
+ }
+
+ public void OnStateTransition(StateMachineId id, string stateName, bool isEntry)
+ {
+ }
+
+ public void OnGotoState(StateMachineId id, string currentStateName, string newStateName)
+ {
+ }
+
+ public void OnDefaultEventHandler(StateMachineId id, string stateName)
+ {
+ }
+
+ public void OnHalt(StateMachineId id, int inboxSize)
+ {
+ }
+
+ public void OnHandleRaisedEvent(StateMachineId id, string stateName, Event e)
+ {
+ }
+
+ public void OnPopStateUnhandledEvent(StateMachineId id, string stateName, Event e)
+ {
+ }
+
+ public void OnExceptionThrown(StateMachineId id, string stateName, string actionName, Exception ex)
+ {
+ }
+
+ public void OnExceptionHandled(StateMachineId id, string stateName, string actionName, Exception ex)
+ {
+ }
+
+ public void OnCreateMonitor(string monitorType)
+ {
+ }
+
+ public void OnMonitorExecuteAction(string monitorType, string stateName, string actionName)
+ {
+ }
+
+ public void OnMonitorProcessEvent(string monitorType, string stateName, string senderName, string senderType,
+ string senderStateName, Event e)
+ {
+ }
+
+ public void OnMonitorRaiseEvent(string monitorType, string stateName, Event e)
+ {
+ }
+
+ public void OnMonitorStateTransition(string monitorType, string stateName, bool isEntry, bool? isInHotState)
+ {
+ }
+
+ public void OnMonitorError(string monitorType, string stateName, bool? isInHotState)
+ {
+ }
+
+ public void OnRandom(object result, string callerName, string callerType)
+ {
+ }
+
+ public void OnAssertionFailure(string error)
+ {
+ }
+
+ public void OnStrategyDescription(string strategyName, string description)
+ {
+ }
+
+ public void OnCompleted()
+ {
+ }
}
\ No newline at end of file
From 626250252bc582f9c412a1f93059068ad90c5b5b Mon Sep 17 00:00:00 2001
From: Ao Li
Date: Fri, 11 Oct 2024 10:10:35 +0800
Subject: [PATCH 13/21] Remove temp file.
---
Src/PChecker/CheckerCore/CheckerConfiguration.cs | 1 -
Tutorial/2_TwoPhaseCommit/timeline.txt | 0
2 files changed, 1 deletion(-)
delete mode 100644 Tutorial/2_TwoPhaseCommit/timeline.txt
diff --git a/Src/PChecker/CheckerCore/CheckerConfiguration.cs b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
index 38346ff3a9..b2c1d7d869 100644
--- a/Src/PChecker/CheckerCore/CheckerConfiguration.cs
+++ b/Src/PChecker/CheckerCore/CheckerConfiguration.cs
@@ -280,7 +280,6 @@ public int MaxSchedulingSteps
[DataMember]
public string JvmArgs;
-
///
/// Initializes a new instance of the class.
///
diff --git a/Tutorial/2_TwoPhaseCommit/timeline.txt b/Tutorial/2_TwoPhaseCommit/timeline.txt
deleted file mode 100644
index e69de29bb2..0000000000
From 907dcd1b3524ae4756b33cc5b30deb79e29fadda Mon Sep 17 00:00:00 2001
From: Ao Li
Date: Sat, 12 Oct 2024 14:46:34 +0800
Subject: [PATCH 14/21] Rename LastSentReceiver to MessageReceiver
---
Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs | 2 +-
.../CheckerCore/SystematicTesting/Operations/AsyncOperation.cs | 2 +-
.../SystematicTesting/Strategies/Probabilistic/POSScheduler.cs | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs b/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
index ced0693165..23327d0a8d 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
@@ -618,7 +618,7 @@ private EnqueueStatus EnqueueEvent(StateMachineId targetId, Event e, StateMachin
"Cannot send event '{0}' to state machine id '{1}' that is not bound to an state machine instance.",
e.GetType().FullName, targetId.Value);
- Scheduler.ScheduledOperation.LastSentReceiver = targetId.ToString();
+ Scheduler.ScheduledOperation.MessageReceiver = targetId.ToString();
Scheduler.ScheduleNextEnabledOperation(AsyncOperationType.Send);
ResetProgramCounter(sender);
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs b/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs
index 47d4da8cab..bbc6803e96 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Operations/AsyncOperation.cs
@@ -53,7 +53,7 @@ internal abstract class AsyncOperation : IAsyncOperation
///
/// The receiver if the operation is Send.
///
- public string LastSentReceiver = "";
+ public string MessageReceiver = "";
///
/// Initializes a new instance of the class.
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs
index ae44bbec13..942d6020b6 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs
@@ -49,7 +49,7 @@ void ResetPriorities(AsyncOperation next, IEnumerable ops)
{
if (op.Type == AsyncOperationType.Send)
{
- if (op.LastSentReceiver == next.LastSentReceiver)
+ if (op.MessageReceiver == next.MessageReceiver)
{
PrioritizedOperations.Remove(op);
}
From 8153cd682b84eaead178f62e8ad5c9184c8efd2d Mon Sep 17 00:00:00 2001
From: Ao Li
Date: Thu, 17 Oct 2024 15:06:16 +0800
Subject: [PATCH 15/21] Simplify scheduler implementation.
---
.../Feedback/FeedbackGuidedStrategy.cs | 25 +-
.../Feedback/Generator/IGenerator.cs | 6 -
.../Feedback/Generator/Mutator/IMutator.cs | 6 -
.../Generator/Mutator/PCTScheduleMutator.cs | 17 -
.../Generator/Mutator/POSScheduleMutator.cs | 14 -
.../Generator/Mutator/RandomInputMutator.cs | 17 -
.../Mutator/RandomScheduleMutator.cs | 17 -
.../Generator/Object/ControlledRandom.cs | 69 ++++
.../Generator/Object/RandomChoices.cs | 10 +-
.../Generator/PCTScheduleGenerator.cs | 62 ----
.../Generator/POSScheduleGenerator.cs | 63 ----
.../Feedback/Generator/ParametricProvider.cs | 27 --
.../Generator/RandomInputGenerator.cs | 101 ------
.../Generator/RandomScheduleGenerator.cs | 61 ----
...{PrioritizedScheduler.cs => IScheduler.cs} | 5 +-
.../Strategies/Probabilistic/PCTScheduler.cs | 323 ++++++++++--------
.../Strategies/Probabilistic/PCTStrategy.cs | 278 ---------------
.../Strategies/Probabilistic/POSScheduler.cs | 22 +-
.../Probabilistic/PriorizationProvider.cs | 7 -
.../PriorizationSchedulingBase.cs | 194 -----------
.../RandomPriorizationProvider.cs | 27 --
.../Probabilistic/RandomScheduler.cs | 57 ++++
...trategy.cs => ScheduleAndInputStrategy.cs} | 8 +-
.../SystematicTesting/TestReport.cs | 11 +-
.../SystematicTesting/TestingEngine.cs | 35 +-
25 files changed, 380 insertions(+), 1082 deletions(-)
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/IMutator.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PCTScheduleMutator.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/POSScheduleMutator.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomInputMutator.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomScheduleMutator.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/ControlledRandom.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PCTScheduleGenerator.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/POSScheduleGenerator.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/ParametricProvider.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomInputGenerator.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomScheduleGenerator.cs
rename Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/{PrioritizedScheduler.cs => IScheduler.cs} (74%)
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationProvider.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationSchedulingBase.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomPriorizationProvider.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomScheduler.cs
rename Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/{PrioritizedSchedulingStrategy.cs => ScheduleAndInputStrategy.cs} (89%)
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
index 8567bc6539..fa4ca7d04d 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/FeedbackGuidedStrategy.cs
@@ -4,17 +4,17 @@
using System.Linq;
using PChecker.Generator;
using PChecker.Feedback;
+using PChecker.Generator.Object;
+using PChecker.SystematicTesting.Strategies.Probabilistic;
using AsyncOperation = PChecker.SystematicTesting.Operations.AsyncOperation;
using Debug = System.Diagnostics.Debug;
namespace PChecker.SystematicTesting.Strategies.Feedback;
-internal class FeedbackGuidedStrategy : IFeedbackGuidedStrategy
- where TInput: IInputGenerator
- where TSchedule: IScheduleGenerator
+internal class FeedbackGuidedStrategy : IFeedbackGuidedStrategy
{
- public record StrategyGenerator(TInput InputGenerator, TSchedule ScheduleGenerator);
+ public record StrategyGenerator(ControlledRandom InputGenerator, IScheduler Scheduler);
public record GeneratorRecord(int Priority, StrategyGenerator Generator, List MinHash);
@@ -39,9 +39,9 @@ public record GeneratorRecord(int Priority, StrategyGenerator Generator, List
/// Initializes a new instance of the class.
///
- public FeedbackGuidedStrategy(CheckerConfiguration checkerConfiguration, TInput input, TSchedule schedule)
+ public FeedbackGuidedStrategy(CheckerConfiguration checkerConfiguration, ControlledRandom inputGenerator, IScheduler scheduler)
{
- if (schedule is PctScheduleGenerator)
+ if (scheduler is PCTScheduler)
{
_maxScheduledSteps = checkerConfiguration.MaxUnfairSchedulingSteps;
}
@@ -49,16 +49,15 @@ public FeedbackGuidedStrategy(CheckerConfiguration checkerConfiguration, TInput
{
_maxScheduledSteps = checkerConfiguration.MaxFairSchedulingSteps;
}
- Generator = new StrategyGenerator(input, schedule);
+ Generator = new StrategyGenerator(inputGenerator, scheduler);
}
///
public virtual bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
{
- // var enabledOperations = _nfa != null? _nfa.FindHighPriorityOperations(ops) : ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
- next = Generator.ScheduleGenerator.NextRandomOperation(ops.ToList(), current);
+ var result = Generator.Scheduler.GetNextOperation(current, ops, out next);
ScheduledSteps++;
- return next != null;
+ return result;
}
///
@@ -202,7 +201,7 @@ public int TotalSavedInputs()
private void PrepareNextInput()
{
- Generator.ScheduleGenerator.PrepareForNextInput();
+ Generator.Scheduler.PrepareForNextIteration();
if (_savedGenerators.Count == 0)
{
// Mutate current input if no input is saved.
@@ -257,12 +256,12 @@ private void PrepareNextInput()
protected virtual StrategyGenerator MutateGenerator(StrategyGenerator prev)
{
- return new StrategyGenerator(prev.InputGenerator.Mutate(), prev.ScheduleGenerator.Mutate());
+ return new StrategyGenerator(prev.InputGenerator.Mutate(), prev.Scheduler.Mutate());
}
protected virtual StrategyGenerator NewGenerator()
{
- return new StrategyGenerator(Generator.InputGenerator.New(), Generator.ScheduleGenerator.New());
+ return new StrategyGenerator(Generator.InputGenerator.New(), Generator.Scheduler.New());
}
public void DumpStats(TextWriter writer)
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IGenerator.cs
index 6a043dc691..8face2fa56 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IGenerator.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IGenerator.cs
@@ -8,11 +8,5 @@ public interface IGenerator
/// A new generator.
T Mutate();
- ///
- /// Copy the current generator and create a new one.
- ///
- /// A new generator.
- T Copy();
-
T New();
}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/IMutator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/IMutator.cs
deleted file mode 100644
index 93302c6d3a..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/IMutator.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace PChecker.Generator.Mutator;
-
-public interface IMutator
-{
- T Mutate(T prev);
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PCTScheduleMutator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PCTScheduleMutator.cs
deleted file mode 100644
index eec20e4076..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/PCTScheduleMutator.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace PChecker.Generator.Mutator;
-
-internal class PCTScheduleMutator : IMutator
-{
- private int _meanMutationCount = 5;
- private int _meanMutationSize = 5;
- private System.Random _random = new();
- public PctScheduleGenerator Mutate(PctScheduleGenerator prev)
- {
- return new PctScheduleGenerator(prev.Random,
- Utils.MutateRandomChoices(prev.PriorityChoices, _meanMutationCount, _meanMutationSize, _random),
- Utils.MutateRandomChoices(prev.SwitchPointChoices, _meanMutationCount, _meanMutationSize, _random),
- prev.MaxPrioritySwitchPoints,
- prev.ScheduleLength
- );
- }
-}
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/POSScheduleMutator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/POSScheduleMutator.cs
deleted file mode 100644
index b375093a0f..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/POSScheduleMutator.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace PChecker.Generator.Mutator;
-
-internal class POSScheduleMutator: IMutator
-{
- private int _meanMutationCount = 5;
- private int _meanMutationSize = 5;
- private System.Random _random = new();
- public POSScheduleGenerator Mutate(POSScheduleGenerator prev)
- {
- return new POSScheduleGenerator(prev.Random,
- Utils.MutateRandomChoices(prev.PriorityChoices, _meanMutationCount, _meanMutationSize, _random),
- Utils.MutateRandomChoices(prev.SwitchPointChoices, _meanMutationCount, _meanMutationSize, _random));
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomInputMutator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomInputMutator.cs
deleted file mode 100644
index 33409f939a..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomInputMutator.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-using System.IO;
-using PChecker.Generator.Object;
-
-namespace PChecker.Generator.Mutator;
-
-public class RandomInputMutator : IMutator
-{
- private readonly int _meanMutationCount = 10;
- private readonly int _meanMutationSize = 10;
- private System.Random _random = new();
- public RandomInputGenerator Mutate(RandomInputGenerator prev)
- {
- return new RandomInputGenerator(prev.Random, Utils.MutateRandomChoices(prev.IntChoices, _meanMutationCount, _meanMutationSize, _random),
- Utils.MutateRandomChoices(prev.DoubleChoices, _meanMutationCount, _meanMutationSize, _random));
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomScheduleMutator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomScheduleMutator.cs
deleted file mode 100644
index ac6aed409c..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/RandomScheduleMutator.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-using System.Collections.Generic;
-using PChecker.Generator.Object;
-
-namespace PChecker.Generator.Mutator;
-
-internal class RandomScheduleMutator : IMutator
-{
- private readonly int _meanMutationCount = 10;
- private readonly int _meanMutationSize = 10;
- private System.Random _random = new();
- public RandomScheduleGenerator Mutate(RandomScheduleGenerator prev)
- {
- return new RandomScheduleGenerator(prev.Random, Utils.MutateRandomChoices(prev.IntChoices, _meanMutationCount, _meanMutationSize, _random));
- }
-
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/ControlledRandom.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/ControlledRandom.cs
new file mode 100644
index 0000000000..d271a830b2
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/ControlledRandom.cs
@@ -0,0 +1,69 @@
+using System;
+using PChecker.Generator.Mutator;
+using PChecker.Random;
+
+namespace PChecker.Generator.Object;
+
+///
+/// Controlled Random.
+///
+public class ControlledRandom: IRandomValueGenerator
+{
+ public RandomChoices IntChoices;
+ public RandomChoices DoubleChoices;
+
+ ///
+ /// Constructor
+ ///
+ ///
+ ///
+ public ControlledRandom(RandomChoices @int, RandomChoices @double)
+ {
+ IntChoices = @int;
+ DoubleChoices = @double;
+ }
+
+ public ControlledRandom(CheckerConfiguration checkerConfiguration) : this(new System.Random((int?)checkerConfiguration.RandomGeneratorSeed ?? Guid.NewGuid().GetHashCode()))
+ {
+ }
+
+ public ControlledRandom(System.Random random)
+ {
+ IntChoices = new RandomChoices(random);
+ DoubleChoices = new RandomChoices(random);
+ }
+
+ ///
+ public uint Seed { get; set; }
+
+ ///
+ public int Next()
+ {
+ return IntChoices.Next();
+ }
+
+ ///
+ public int Next(int maxValue)
+ {
+ return IntChoices.Next() % maxValue;
+ }
+
+ ///
+ public double NextDouble()
+ {
+ return DoubleChoices.Next();
+ }
+
+ public ControlledRandom New()
+ {
+ return new ControlledRandom(IntChoices.Random);
+ }
+
+ public ControlledRandom Mutate()
+ {
+ return new ControlledRandom(Utils.MutateRandomChoices(IntChoices, 5, 5, IntChoices.Random),
+ Utils.MutateRandomChoices(DoubleChoices, 5, 5, DoubleChoices.Random)
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/RandomChoices.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/RandomChoices.cs
index e32d1e007e..ad7c65674f 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/RandomChoices.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/RandomChoices.cs
@@ -8,18 +8,18 @@ namespace PChecker.Generator.Object;
public class RandomChoices
where T: IConvertible
{
- private readonly System.Random _random;
+ internal readonly System.Random Random;
public int Pos;
public List Data = new();
public RandomChoices(System.Random random)
{
- _random = random;
+ Random = random;
}
public RandomChoices(RandomChoices other)
{
- _random = other._random;
+ Random = other.Random;
Data = new List(other.Data);
}
@@ -36,11 +36,11 @@ public T GenerateNew()
{
if (typeof(T).IsAssignableFrom(typeof(int)))
{
- return (T) Convert.ChangeType(_random.Next(), typeof(T));
+ return (T) Convert.ChangeType(Random.Next(), typeof(T));
}
else if (typeof(T).IsAssignableFrom(typeof(double)))
{
- return (T) Convert.ChangeType(_random.NextDouble(), typeof(T));
+ return (T) Convert.ChangeType(Random.NextDouble(), typeof(T));
}
else
{
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PCTScheduleGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PCTScheduleGenerator.cs
deleted file mode 100644
index 0a0ed19401..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/PCTScheduleGenerator.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using System;
-using System.Collections.Generic;
-using PChecker.Generator.Mutator;
-using PChecker.Generator.Object;
-using PChecker.SystematicTesting.Operations;
-using PChecker.SystematicTesting.Strategies.Probabilistic;
-
-namespace PChecker.Generator;
-
-internal sealed class PctScheduleGenerator: PCTScheduler, IScheduleGenerator
-{
- public System.Random Random;
- public RandomChoices PriorityChoices;
- public RandomChoices SwitchPointChoices;
-
- public PctScheduleGenerator(System.Random random, RandomChoices? priorityChoices, RandomChoices? switchPointChoices, int numSwitchPoints, int maxScheduleLength):
- base(numSwitchPoints, maxScheduleLength,
- new ParametricProvider(
- priorityChoices != null ? new RandomChoices(priorityChoices) : new RandomChoices(random),
- switchPointChoices != null ? new RandomChoices(switchPointChoices) : new RandomChoices(random)))
- {
- Random = random;
- var provider = (ParametricProvider) Provider;
- PriorityChoices = provider.PriorityChoices;
- SwitchPointChoices = provider.SwitchPointChoices;
- }
-
- public PctScheduleGenerator(CheckerConfiguration checkerConfiguration):
- this(new System.Random((int?)checkerConfiguration.RandomGeneratorSeed ?? Guid.NewGuid().GetHashCode()), null, null, checkerConfiguration.StrategyBound, 0)
- {
- }
-
- public PctScheduleGenerator Mutate()
- {
- return new PCTScheduleMutator().Mutate(this);
- }
-
- public PctScheduleGenerator New()
- {
- return new PctScheduleGenerator(Random, null, null, MaxPrioritySwitchPoints, ScheduleLength);
- }
-
- public PctScheduleGenerator Copy()
- {
- return new PctScheduleGenerator(Random, PriorityChoices, SwitchPointChoices, MaxPrioritySwitchPoints, ScheduleLength);
- }
-
- public AsyncOperation? NextRandomOperation(List enabledOperations, AsyncOperation current)
- {
- if (GetNextOperation(current, enabledOperations, out var next)) {
- return next;
- } else {
- return null;
- }
- }
-
-
- public void PrepareForNextInput()
- {
- PrepareForNextIteration();
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/POSScheduleGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/POSScheduleGenerator.cs
deleted file mode 100644
index b3de2b2db1..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/POSScheduleGenerator.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using System;
-using System.Collections.Generic;
-using PChecker.Feedback;
-using PChecker.Generator.Mutator;
-using PChecker.Generator.Object;
-using PChecker.SystematicTesting.Operations;
-using PChecker.SystematicTesting.Strategies.Probabilistic;
-
-namespace PChecker.Generator;
-
-internal class POSScheduleGenerator: POSScheduler, IScheduleGenerator
-{
- public System.Random Random;
- public RandomChoices PriorityChoices;
- public RandomChoices SwitchPointChoices;
-
- public POSScheduleGenerator(System.Random random, RandomChoices? priorityChoices, RandomChoices? switchPointChoices):
- base(new ParametricProvider(
- priorityChoices != null ? new RandomChoices(priorityChoices) : new RandomChoices(random),
- switchPointChoices != null ? new RandomChoices(switchPointChoices) : new RandomChoices(random)))
- {
- Random = random;
- var provider = (ParametricProvider) Provider;
- PriorityChoices = provider.PriorityChoices;
- SwitchPointChoices = provider.SwitchPointChoices;
- }
-
- public POSScheduleGenerator(CheckerConfiguration checkerConfiguration):
- this(new System.Random((int?)checkerConfiguration.RandomGeneratorSeed ?? Guid.NewGuid().GetHashCode()), null,
- null)
- {
- }
-
- public POSScheduleGenerator Mutate()
- {
- return new POSScheduleMutator().Mutate(this);
- }
-
- public POSScheduleGenerator New()
- {
- return new POSScheduleGenerator(Random, null, null);
- }
-
- public POSScheduleGenerator Copy()
- {
- return new POSScheduleGenerator(Random, PriorityChoices, SwitchPointChoices);
- }
-
- public AsyncOperation? NextRandomOperation(List enabledOperations, AsyncOperation current)
- {
- if (GetNextOperation(current, enabledOperations, out var next)) {
- return next;
- } else {
- return null;
- }
- }
-
- public void PrepareForNextInput()
- {
- PrepareForNextIteration();
- }
-
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/ParametricProvider.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/ParametricProvider.cs
deleted file mode 100644
index 0ffc657564..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/ParametricProvider.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using PChecker.Generator.Object;
-using PChecker.SystematicTesting.Strategies.Probabilistic;
-
-namespace PChecker.Generator;
-
-internal class ParametricProvider: PriorizationProvider
-{
- public RandomChoices PriorityChoices;
- public RandomChoices SwitchPointChoices;
- public ParametricProvider(RandomChoices priority, RandomChoices switchPoint)
- {
- PriorityChoices = priority;
- SwitchPointChoices = switchPoint;
- }
-
- public int AssignPriority(int numOps)
- {
-
- return PriorityChoices.Next() % numOps + 1;
- }
-
- public double SwitchPointChoice()
- {
- return SwitchPointChoices.Next();
- }
-
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomInputGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomInputGenerator.cs
deleted file mode 100644
index bde03ddd3c..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomInputGenerator.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.IO;
-using PChecker.Generator.Mutator;
-using PChecker.Generator.Object;
-
-namespace PChecker.Generator
-{
-
- ///
- /// This class implements a JQF-style stream-based input generator.
- /// See more: https://github.com/rohanpadhye/JQF
- ///
- public class RandomInputGenerator : IInputGenerator
- {
- ///
- /// Device for generating random numbers.
- ///
- internal readonly System.Random Random;
-
- internal RandomChoices IntChoices;
- internal RandomChoices DoubleChoices;
-
- public RandomInputGenerator(System.Random random, RandomChoices? intChoices, RandomChoices? doubleChoices)
- {
- Random = random;
- IntChoices = intChoices != null ? new RandomChoices(intChoices) : new RandomChoices(Random);
- DoubleChoices = doubleChoices != null ? new RandomChoices(doubleChoices) : new RandomChoices(Random);
- }
-
-
- ///
- /// Create a stream based value generator using CheckerConfiguration.
- ///
- ///
- public RandomInputGenerator(CheckerConfiguration checkerConfiguration):
- this(new System.Random((int?)checkerConfiguration.RandomGeneratorSeed ?? Guid.NewGuid().GetHashCode()), null, null)
- {
- }
-
- ///
- /// Create a default stream based value generator.
- ///
- public RandomInputGenerator():
- this(new System.Random(Guid.NewGuid().GetHashCode()), null, null)
- {
- }
-
-
- ///
- /// Create a stream based value generator with an existing generator.
- ///
- ///
- public RandomInputGenerator(RandomInputGenerator other) : this(other.Random, other.IntChoices, other.DoubleChoices)
- {
- }
-
- ///
- /// Returns a non-negative random number.
- ///
- public int Next()
- {
- return IntChoices.Next();
- }
-
-
- ///
- /// Returns a non-negative random number less than the specified max value.
- ///
- /// Exclusive upper bound.
- public int Next(int maxValue)
- {
- var value = maxValue == 0 ? 0 : Next() % maxValue;
- return value;
- }
-
- ///
- /// Returns a random floating-point number that is greater
- /// than or equal to 0.0, and less than 1.0.
- ///
- public double NextDouble()
- {
- return DoubleChoices.Next();
- }
-
- public RandomInputGenerator Mutate()
- {
- return new RandomInputMutator().Mutate(this);
- }
-
- public RandomInputGenerator Copy()
- {
- return new RandomInputGenerator(this);
- }
-
- public RandomInputGenerator New()
- {
- return new RandomInputGenerator(Random, null, null);
- }
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomScheduleGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomScheduleGenerator.cs
deleted file mode 100644
index 49d378c87c..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomScheduleGenerator.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using PChecker.Generator.Mutator;
-using PChecker.Generator.Object;
-using PChecker.SystematicTesting.Operations;
-
-namespace PChecker.Generator;
-
-internal class RandomScheduleGenerator: IScheduleGenerator
-{
- internal readonly System.Random Random;
-
- public RandomChoices IntChoices;
-
- public RandomScheduleGenerator(System.Random random, RandomChoices? intChoices)
- {
- Random = random;
- IntChoices = intChoices != null ? new RandomChoices(intChoices) : new RandomChoices(Random);
- }
-
- public RandomScheduleGenerator(CheckerConfiguration checkerConfiguration):
- this(new System.Random((int?)checkerConfiguration.RandomGeneratorSeed ?? Guid.NewGuid().GetHashCode()) , null)
- {
- }
-
- public AsyncOperation? NextRandomOperation(List ops, AsyncOperation current)
- {
- var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
- if (enabledOperations.Count == 0)
- {
- return null;
- }
-
- if (enabledOperations.Count == 1)
- {
- return enabledOperations[0];
- }
- var idx = IntChoices.Next() % enabledOperations.Count;
- return enabledOperations[idx];
- }
-
- public RandomScheduleGenerator Mutate()
- {
- return new RandomScheduleMutator().Mutate(this);
- }
-
- public RandomScheduleGenerator Copy()
- {
- return new RandomScheduleGenerator(Random, IntChoices);
- }
-
- public void PrepareForNextInput()
- {
- }
-
- public RandomScheduleGenerator New()
- {
- return new RandomScheduleGenerator(Random, null);
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/IScheduler.cs
similarity index 74%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedScheduler.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/IScheduler.cs
index 7c38a0629c..1d43076f40 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedScheduler.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/IScheduler.cs
@@ -1,11 +1,14 @@
using System.Collections.Generic;
+using PChecker.Random;
using PChecker.SystematicTesting.Operations;
namespace PChecker.SystematicTesting.Strategies.Probabilistic;
-internal interface PrioritizedScheduler
+internal interface IScheduler
{
public bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next);
public void Reset();
public bool PrepareForNextIteration();
+ public IScheduler Mutate();
+ public IScheduler New();
}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTScheduler.cs
index c0263c68e1..56b15b353f 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTScheduler.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTScheduler.cs
@@ -1,189 +1,236 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
using System;
using System.Collections.Generic;
using System.Linq;
+using PChecker.Generator.Object;
+using PChecker.IO.Debugging;
+using PChecker.Random;
using PChecker.SystematicTesting.Operations;
-using Debug = PChecker.IO.Debugging.Debug;
-
-namespace PChecker.SystematicTesting.Strategies.Probabilistic;
-internal class PCTScheduler: PrioritizedScheduler
+namespace PChecker.SystematicTesting.Strategies.Probabilistic
{
- public readonly PriorizationProvider Provider;
-
- ///
- /// The number of scheduled steps.
- ///
- private int ScheduledSteps;
-
- ///
- /// Max number of priority switch points.
- ///
- public readonly int MaxPrioritySwitchPoints;
-
- ///
- /// Approximate length of the schedule across all iterations.
- ///
- public int ScheduleLength;
-
- ///
- /// List of prioritized operations.
- ///
- private readonly List PrioritizedOperations;
-
- private int _nextPriorityChangePoint;
- private int _numSwitchPointsLeft;
-
///
- /// Initializes a new instance of the class.
+ /// A priority-based probabilistic scheduling strategy.
///
- public PCTScheduler(int maxPrioritySwitchPoints, int scheduleLength, PriorizationProvider provider)
- {
- Provider = provider;
- ScheduledSteps = 0;
- ScheduleLength = scheduleLength;
- MaxPrioritySwitchPoints = maxPrioritySwitchPoints;
- PrioritizedOperations = new List();
- _numSwitchPointsLeft = maxPrioritySwitchPoints;
-
- double switchPointProbability = 0.1;
- if (ScheduleLength != 0)
- {
- switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
- }
- _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice());
- }
-
- public virtual bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
+ ///
+ /// This strategy is described in the following paper:
+ /// https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/asplos277-pct.pdf
+ ///
+ internal class PCTScheduler : IScheduler
{
- ScheduledSteps++;
- next = null;
- var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
- if (enabledOperations.Count == 0)
+
+
+ ///
+ /// Random value generator.
+ ///
+ private readonly IRandomValueGenerator _randomValueGenerator;
+
+ ///
+ /// The maximum number of steps to schedule.
+ ///
+ private readonly int MaxScheduledSteps;
+
+ ///
+ /// The number of scheduled steps.
+ ///
+ private int ScheduledSteps;
+
+ ///
+ /// Max number of priority switch points.
+ ///
+ internal readonly int MaxPrioritySwitchPoints;
+
+ ///
+ /// Approximate length of the schedule across all schedules.
+ ///
+ internal int ScheduleLength;
+
+ ///
+ /// List of prioritized operations.
+ ///
+ private readonly List PrioritizedOperations;
+
+ ///
+ /// Next execution point where the priority should be changed.
+ ///
+ private int _nextPriorityChangePoint;
+
+ ///
+ /// Number of switch points left (leq MaxPrioritySwitchPoints).
+ ///
+ private int _numSwitchPointsLeft;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PCTScheduler(int maxPrioritySwitchPoints, int scheduleLength, IRandomValueGenerator random)
{
- if (_nextPriorityChangePoint == ScheduledSteps)
+ _randomValueGenerator = random;
+ ScheduledSteps = 0;
+ ScheduleLength = scheduleLength;
+ MaxPrioritySwitchPoints = maxPrioritySwitchPoints;
+ PrioritizedOperations = new List();
+ double switchPointProbability = 0.1;
+ if (ScheduleLength != 0)
{
- MovePriorityChangePointForward();
+ switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
}
- return false;
- }
+ _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, random.NextDouble());
- var highestEnabledOp = GetPrioritizedOperation(enabledOperations, current);
- if (next is null)
- {
- next = highestEnabledOp;
}
- return true;
- }
-
- private void MovePriorityChangePointForward()
- {
- _nextPriorityChangePoint += 1;
- Debug.WriteLine(" Moving priority change to '{0}'.", _nextPriorityChangePoint);
- }
- private AsyncOperation GetHighestPriorityEnabledOperation(IEnumerable choices)
- {
- AsyncOperation prioritizedOp = null;
- foreach (var entity in PrioritizedOperations)
+ public virtual bool GetNextOperation(AsyncOperation current, IEnumerable ops,
+ out AsyncOperation next)
{
- if (choices.Any(m => m == entity))
+ ScheduledSteps++;
+ next = null;
+ var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
+ if (enabledOperations.Count == 0)
{
- prioritizedOp = entity;
- break;
+ if (_nextPriorityChangePoint == ScheduledSteps)
+ {
+ MovePriorityChangePointForward();
+ }
+
+ return false;
}
- }
- return prioritizedOp;
- }
+ var highestEnabledOp = GetPrioritizedOperation(enabledOperations, current);
+ if (next is null)
+ {
+ next = highestEnabledOp;
+ }
+ return true;
+ }
- ///
- /// Returns the prioritized operation.
- ///
- private AsyncOperation GetPrioritizedOperation(List ops, AsyncOperation current)
- {
- if (PrioritizedOperations.Count == 0)
+ private void MovePriorityChangePointForward()
{
- PrioritizedOperations.Add(current);
+ _nextPriorityChangePoint += 1;
+ Debug.WriteLine(" Moving priority change to '{0}'.", _nextPriorityChangePoint);
}
- foreach (var op in ops.Where(op => !PrioritizedOperations.Contains(op)))
+ private AsyncOperation GetHighestPriorityEnabledOperation(IEnumerable choices)
{
- var mIndex = Provider.AssignPriority(PrioritizedOperations.Count);
- PrioritizedOperations.Insert(mIndex, op);
- Debug.WriteLine(" Detected new operation '{0}' at index '{1}'.", op.Id, mIndex);
+ AsyncOperation prioritizedOp = null;
+ foreach (var entity in PrioritizedOperations)
+ {
+ if (choices.Any(m => m == entity))
+ {
+ prioritizedOp = entity;
+ break;
+ }
+ }
+
+ return prioritizedOp;
}
- var prioritizedSchedulable = GetHighestPriorityEnabledOperation(ops);
- if (_nextPriorityChangePoint == ScheduledSteps)
+ ///
+ /// Returns the prioritized operation.
+ ///
+ private AsyncOperation GetPrioritizedOperation(List ops, AsyncOperation current)
{
- if (ops.Count == 1)
+ if (PrioritizedOperations.Count == 0)
{
- MovePriorityChangePointForward();
+ PrioritizedOperations.Add(current);
}
- else
+
+ foreach (var op in ops.Where(op => !PrioritizedOperations.Contains(op)))
{
- PrioritizedOperations.Remove(prioritizedSchedulable);
- PrioritizedOperations.Add(prioritizedSchedulable);
- Debug.WriteLine(" Operation '{0}' changes to lowest priority.", prioritizedSchedulable);
+ var mIndex = _randomValueGenerator.Next(PrioritizedOperations.Count) + 1;
+ PrioritizedOperations.Insert(mIndex, op);
+ Debug.WriteLine(" Detected new operation '{0}' at index '{1}'.", op.Id, mIndex);
+ }
+
- _numSwitchPointsLeft -= 1;
- // Update the next priority change point.
- if (_numSwitchPointsLeft > 0)
+ var prioritizedSchedulable = GetHighestPriorityEnabledOperation(ops);
+ if (_nextPriorityChangePoint == ScheduledSteps)
+ {
+ if (ops.Count == 1)
{
- double switchPointProbability = 0.1;
- if (ScheduleLength != 0)
+ MovePriorityChangePointForward();
+ }
+ else
+ {
+ PrioritizedOperations.Remove(prioritizedSchedulable);
+ PrioritizedOperations.Add(prioritizedSchedulable);
+ Debug.WriteLine(" Operation '{0}' changes to lowest priority.", prioritizedSchedulable);
+
+ _numSwitchPointsLeft -= 1;
+ // Update the next priority change point.
+ if (_numSwitchPointsLeft > 0)
{
- switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
+ double switchPointProbability = 0.1;
+ if (ScheduleLength != 0)
+ {
+ switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
+ }
+
+ _nextPriorityChangePoint =
+ Generator.Mutator.Utils.SampleGeometric(switchPointProbability,
+ _randomValueGenerator.NextDouble()) + ScheduledSteps;
}
- _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice()) + ScheduledSteps;
- }
+ }
}
- }
- if (Debug.IsEnabled)
- {
- Debug.WriteLine(" Prioritized schedulable '{0}'.", prioritizedSchedulable);
- Debug.Write(" Priority list: ");
- for (var idx = 0; idx < PrioritizedOperations.Count; idx++)
+ if (Debug.IsEnabled)
{
- if (idx < PrioritizedOperations.Count - 1)
- {
- Debug.Write("'{0}', ", PrioritizedOperations[idx]);
- }
- else
+ Debug.WriteLine(" Prioritized schedulable '{0}'.", prioritizedSchedulable);
+ Debug.Write(" Priority list: ");
+ for (var idx = 0; idx < PrioritizedOperations.Count; idx++)
{
- Debug.WriteLine("'{0}'.", PrioritizedOperations[idx]);
+ if (idx < PrioritizedOperations.Count - 1)
+ {
+ Debug.Write("'{0}', ", PrioritizedOperations[idx]);
+ }
+ else
+ {
+ Debug.WriteLine("'{0}'.", PrioritizedOperations[idx]);
+ }
}
}
+
+ return ops.First(op => op.Equals(prioritizedSchedulable));
}
- return ops.First(op => op.Equals(prioritizedSchedulable));
- }
+ public void Reset()
+ {
+ ScheduleLength = 0;
+ ScheduledSteps = 0;
+ PrioritizedOperations.Clear();
+ }
- public void Reset()
- {
- ScheduleLength = 0;
- ScheduledSteps = 0;
- PrioritizedOperations.Clear();
- }
+ ///
+ public virtual bool PrepareForNextIteration()
+ {
+ ScheduleLength = Math.Max(ScheduleLength, ScheduledSteps);
+ ScheduledSteps = 0;
+ _numSwitchPointsLeft = MaxPrioritySwitchPoints;
- ///
- public virtual bool PrepareForNextIteration()
- {
- ScheduleLength = Math.Max(ScheduleLength, ScheduledSteps);
- ScheduledSteps = 0;
- _numSwitchPointsLeft = MaxPrioritySwitchPoints;
+ PrioritizedOperations.Clear();
+ double switchPointProbability = 0.1;
+ if (ScheduleLength != 0)
+ {
+ switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
+ }
+
+ _nextPriorityChangePoint =
+ Generator.Mutator.Utils.SampleGeometric(switchPointProbability, _randomValueGenerator.NextDouble());
+ return true;
+ }
+
+ public IScheduler Mutate()
+ {
+ return new PCTScheduler(MaxPrioritySwitchPoints, ScheduleLength, ((ControlledRandom) _randomValueGenerator).Mutate());
+ }
- PrioritizedOperations.Clear();
- double switchPointProbability = 0.1;
- if (ScheduleLength != 0)
+ public IScheduler New()
{
- switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
+ return new PCTScheduler(MaxPrioritySwitchPoints, ScheduleLength, ((ControlledRandom) _randomValueGenerator).New());
}
- _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice());
- return true;
}
-}
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs
deleted file mode 100644
index 3ffdc47c3c..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs
+++ /dev/null
@@ -1,278 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using PChecker.IO.Debugging;
-using PChecker.Random;
-using PChecker.SystematicTesting.Operations;
-
-namespace PChecker.SystematicTesting.Strategies.Probabilistic
-{
- ///
- /// A priority-based probabilistic scheduling strategy.
- ///
- ///
- /// This strategy is described in the following paper:
- /// https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/asplos277-pct.pdf
- ///
- internal sealed class PCTStrategy : ISchedulingStrategy
- {
- ///
- /// Random value generator.
- ///
- private readonly IRandomValueGenerator RandomValueGenerator;
-
- ///
- /// The maximum number of steps to schedule.
- ///
- private readonly int MaxScheduledSteps;
-
- ///
- /// The number of scheduled steps.
- ///
- private int ScheduledSteps;
-
- ///
- /// Max number of priority switch points.
- ///
- private readonly int MaxPrioritySwitchPoints;
-
- ///
- /// Approximate length of the schedule across all schedules.
- ///
- private int ScheduleLength;
-
- ///
- /// List of prioritized operations.
- ///
- private readonly List PrioritizedOperations;
-
- ///
- /// Set of priority change points.
- ///
- private readonly SortedSet PriorityChangePoints;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public PCTStrategy(int maxSteps, int maxPrioritySwitchPoints, IRandomValueGenerator random)
- {
- RandomValueGenerator = random;
- MaxScheduledSteps = maxSteps;
- ScheduledSteps = 0;
- ScheduleLength = 0;
- MaxPrioritySwitchPoints = maxPrioritySwitchPoints;
- PrioritizedOperations = new List();
- PriorityChangePoints = new SortedSet();
- }
-
- ///
- public bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
- {
- next = null;
- var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
- if (enabledOperations.Count == 0)
- {
- return false;
- }
-
- var highestEnabledOp = GetPrioritizedOperation(enabledOperations, current);
- if (next is null)
- {
- next = highestEnabledOp;
- }
-
- ScheduledSteps++;
-
- return true;
- }
-
- ///
- public bool GetNextBooleanChoice(AsyncOperation current, int maxValue, out bool next)
- {
- next = false;
- if (RandomValueGenerator.Next(maxValue) == 0)
- {
- next = true;
- }
-
- ScheduledSteps++;
-
- return true;
- }
-
- ///
- public bool GetNextIntegerChoice(AsyncOperation current, int maxValue, out int next)
- {
- next = RandomValueGenerator.Next(maxValue);
- ScheduledSteps++;
- return true;
- }
-
- ///
- public bool PrepareForNextIteration()
- {
- ScheduleLength = Math.Max(ScheduleLength, ScheduledSteps);
- ScheduledSteps = 0;
-
- PrioritizedOperations.Clear();
- PriorityChangePoints.Clear();
-
- var range = new List();
- for (var idx = 0; idx < ScheduleLength; idx++)
- {
- range.Add(idx);
- }
-
- foreach (var point in Shuffle(range).Take(MaxPrioritySwitchPoints))
- {
- PriorityChangePoints.Add(point);
- }
-
- return true;
- }
-
- ///
- public int GetScheduledSteps() => ScheduledSteps;
-
- ///
- public bool HasReachedMaxSchedulingSteps()
- {
- if (MaxScheduledSteps == 0)
- {
- return false;
- }
-
- return ScheduledSteps >= MaxScheduledSteps;
- }
-
- ///
- public bool IsFair() => false;
-
- ///
- public string GetDescription()
- {
- var text = $"pct[priority change points '{MaxPrioritySwitchPoints}' [" +
- string.Join(", ", PriorityChangePoints.ToArray()) +
- "], seed '" + RandomValueGenerator.Seed + "']";
- return text;
- }
-
- ///
- /// Returns the prioritized operation.
- ///
- private AsyncOperation GetPrioritizedOperation(List ops, AsyncOperation current)
- {
- if (PrioritizedOperations.Count == 0)
- {
- PrioritizedOperations.Add(current);
- }
-
- foreach (var op in ops.Where(op => !PrioritizedOperations.Contains(op)))
- {
- var mIndex = RandomValueGenerator.Next(PrioritizedOperations.Count) + 1;
- PrioritizedOperations.Insert(mIndex, op);
- Debug.WriteLine(" Detected new operation '{0}' at index '{1}'.", op.Id, mIndex);
- }
-
- if (PriorityChangePoints.Contains(ScheduledSteps))
- {
- if (ops.Count == 1)
- {
- MovePriorityChangePointForward();
- }
- else
- {
- var priority = GetHighestPriorityEnabledOperation(ops);
- PrioritizedOperations.Remove(priority);
- PrioritizedOperations.Add(priority);
- Debug.WriteLine(" Operation '{0}' changes to lowest priority.", priority);
- }
- }
-
- var prioritizedSchedulable = GetHighestPriorityEnabledOperation(ops);
- if (Debug.IsEnabled)
- {
- Debug.WriteLine(" Prioritized schedulable '{0}'.", prioritizedSchedulable);
- Debug.Write(" Priority list: ");
- for (var idx = 0; idx < PrioritizedOperations.Count; idx++)
- {
- if (idx < PrioritizedOperations.Count - 1)
- {
- Debug.Write("'{0}', ", PrioritizedOperations[idx]);
- }
- else
- {
- Debug.WriteLine("'{0}'.", PrioritizedOperations[idx]);
- }
- }
- }
-
- return ops.First(op => op.Equals(prioritizedSchedulable));
- }
-
- ///
- /// Returns the highest-priority enabled operation.
- ///
- private AsyncOperation GetHighestPriorityEnabledOperation(IEnumerable choices)
- {
- AsyncOperation prioritizedOp = null;
- foreach (var entity in PrioritizedOperations)
- {
- if (choices.Any(m => m == entity))
- {
- prioritizedOp = entity;
- break;
- }
- }
-
- return prioritizedOp;
- }
-
- ///
- /// Shuffles the specified list using the Fisher-Yates algorithm.
- ///
- private IList Shuffle(IList list)
- {
- var result = new List(list);
- for (var idx = result.Count - 1; idx >= 1; idx--)
- {
- var point = RandomValueGenerator.Next(ScheduleLength);
- var temp = result[idx];
- result[idx] = result[point];
- result[point] = temp;
- }
-
- return result;
- }
-
- ///
- /// Moves the current priority change point forward. This is a useful
- /// optimization when a priority change point is assigned in either a
- /// sequential execution or a nondeterministic choice.
- ///
- private void MovePriorityChangePointForward()
- {
- PriorityChangePoints.Remove(ScheduledSteps);
- var newPriorityChangePoint = ScheduledSteps + 1;
- while (PriorityChangePoints.Contains(newPriorityChangePoint))
- {
- newPriorityChangePoint++;
- }
-
- PriorityChangePoints.Add(newPriorityChangePoint);
- Debug.WriteLine(" Moving priority change to '{0}'.", newPriorityChangePoint);
- }
-
- ///
- public void Reset()
- {
- ScheduleLength = 0;
- ScheduledSteps = 0;
- PrioritizedOperations.Clear();
- PriorityChangePoints.Clear();
- }
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs
index 942d6020b6..548c1fb87f 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs
@@ -2,14 +2,16 @@
using System.Collections.Generic;
using System.Linq;
using PChecker.Feedback;
+using PChecker.Generator.Object;
using PChecker.IO.Debugging;
+using PChecker.Random;
using PChecker.SystematicTesting.Operations;
namespace PChecker.SystematicTesting.Strategies.Probabilistic;
-internal class POSScheduler: PrioritizedScheduler
+internal class POSScheduler: IScheduler
{
- internal readonly PriorizationProvider Provider;
+ private IRandomValueGenerator _randomValueGenerator;
///
/// List of prioritized operations.
@@ -19,9 +21,9 @@ internal class POSScheduler: PrioritizedScheduler
///
/// Initializes a new instance of the class.
///
- public POSScheduler(PriorizationProvider provider)
+ public POSScheduler(IRandomValueGenerator random)
{
- Provider = provider;
+ _randomValueGenerator = random;
PrioritizedOperations = new List();
}
@@ -85,7 +87,7 @@ private AsyncOperation GetPrioritizedOperation(List ops, AsyncOp
foreach (var op in ops.Where(op => !PrioritizedOperations.Contains(op)))
{
- var mIndex = Provider.AssignPriority(PrioritizedOperations.Count);
+ var mIndex = _randomValueGenerator.Next(PrioritizedOperations.Count) + 1;
PrioritizedOperations.Insert(mIndex, op);
Debug.WriteLine(" Detected new operation '{0}' at index '{1}'.", op.Id, mIndex);
}
@@ -145,4 +147,14 @@ public virtual bool PrepareForNextIteration()
PrioritizedOperations.Clear();
return true;
}
+
+ public IScheduler Mutate()
+ {
+ return new POSScheduler(((ControlledRandom)_randomValueGenerator).Mutate());
+ }
+
+ public IScheduler New()
+ {
+ return new POSScheduler(((ControlledRandom)_randomValueGenerator).New());
+ }
}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationProvider.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationProvider.cs
deleted file mode 100644
index d4cb446516..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationProvider.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace PChecker.SystematicTesting.Strategies.Probabilistic;
-
-public interface PriorizationProvider
-{
- public int AssignPriority(int numOps);
- public double SwitchPointChoice();
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationSchedulingBase.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationSchedulingBase.cs
deleted file mode 100644
index ae4eee7531..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PriorizationSchedulingBase.cs
+++ /dev/null
@@ -1,194 +0,0 @@
-
-
-using System.Collections.Generic;
-using System.Linq;
-using PChecker.Feedback;
-using PChecker.SystematicTesting.Operations;
-using PChecker.Generator.Mutator;
-using PChecker.IO.Debugging;
-using System;
-
-namespace PChecker.SystematicTesting.Strategies.Probabilistic;
-
-internal class PriorizationSchedulingBase
-{
- public readonly PriorizationProvider Provider;
-
- ///
- /// The number of scheduled steps.
- ///
- private int ScheduledSteps;
-
- ///
- /// Max number of priority switch points.
- ///
- public readonly int MaxPrioritySwitchPoints;
-
- ///
- /// Approximate length of the schedule across all iterations.
- ///
- public int ScheduleLength;
-
- ///
- /// List of prioritized operations.
- ///
- private readonly List PrioritizedOperations;
-
- private int _nextPriorityChangePoint;
- private int _numSwitchPointsLeft;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public PriorizationSchedulingBase(int maxPrioritySwitchPoints, int scheduleLength, PriorizationProvider provider)
- {
- Provider = provider;
- ScheduledSteps = 0;
- ScheduleLength = scheduleLength;
- MaxPrioritySwitchPoints = maxPrioritySwitchPoints;
- PrioritizedOperations = new List();
- _numSwitchPointsLeft = maxPrioritySwitchPoints;
-
- double switchPointProbability = 0.1;
- if (ScheduleLength != 0)
- {
- switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
- }
- _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice());
- }
-
- public virtual bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
- {
- ScheduledSteps++;
- next = null;
- var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
- if (enabledOperations.Count == 0)
- {
- if (_nextPriorityChangePoint == ScheduledSteps)
- {
- MovePriorityChangePointForward();
- }
- return false;
- }
-
- var highestEnabledOp = GetPrioritizedOperation(enabledOperations, current);
- if (next is null)
- {
- next = highestEnabledOp;
- }
- return true;
- }
-
-
- private void MovePriorityChangePointForward()
- {
- _nextPriorityChangePoint += 1;
- Debug.WriteLine(" Moving priority change to '{0}'.", _nextPriorityChangePoint);
- }
- private AsyncOperation GetHighestPriorityEnabledOperation(IEnumerable choices)
- {
- AsyncOperation prioritizedOp = null;
- foreach (var entity in PrioritizedOperations)
- {
- if (choices.Any(m => m == entity))
- {
- prioritizedOp = entity;
- break;
- }
- }
-
- return prioritizedOp;
- }
-
-
-
- ///
- /// Returns the prioritized operation.
- ///
- private AsyncOperation GetPrioritizedOperation(List ops, AsyncOperation current)
- {
- if (PrioritizedOperations.Count == 0)
- {
- PrioritizedOperations.Add(current);
- }
-
- foreach (var op in ops.Where(op => !PrioritizedOperations.Contains(op)))
- {
- var mIndex = Provider.AssignPriority(PrioritizedOperations.Count);
- PrioritizedOperations.Insert(mIndex, op);
- Debug.WriteLine(" Detected new operation '{0}' at index '{1}'.", op.Id, mIndex);
- }
-
- var prioritizedSchedulable = GetHighestPriorityEnabledOperation(ops);
- if (_nextPriorityChangePoint == ScheduledSteps)
- {
- if (ops.Count == 1)
- {
- MovePriorityChangePointForward();
- }
- else
- {
- PrioritizedOperations.Remove(prioritizedSchedulable);
- PrioritizedOperations.Add(prioritizedSchedulable);
- Debug.WriteLine(" Operation '{0}' changes to lowest priority.", prioritizedSchedulable);
-
- _numSwitchPointsLeft -= 1;
- // Update the next priority change point.
- if (_numSwitchPointsLeft > 0)
- {
- double switchPointProbability = 0.1;
- if (ScheduleLength != 0)
- {
- switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
- }
- _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice()) + ScheduledSteps;
- }
-
- }
- }
-
- if (Debug.IsEnabled)
- {
- Debug.WriteLine(" Prioritized schedulable '{0}'.", prioritizedSchedulable);
- Debug.Write(" Priority list: ");
- for (var idx = 0; idx < PrioritizedOperations.Count; idx++)
- {
- if (idx < PrioritizedOperations.Count - 1)
- {
- Debug.Write("'{0}', ", PrioritizedOperations[idx]);
- }
- else
- {
- Debug.WriteLine("'{0}'.", PrioritizedOperations[idx]);
- }
- }
- }
-
- return ops.First(op => op.Equals(prioritizedSchedulable));
- }
-
-
- public void Reset()
- {
- ScheduleLength = 0;
- ScheduledSteps = 0;
- PrioritizedOperations.Clear();
- }
-
- ///
- public virtual bool PrepareForNextIteration()
- {
- ScheduleLength = Math.Max(ScheduleLength, ScheduledSteps);
- ScheduledSteps = 0;
- _numSwitchPointsLeft = MaxPrioritySwitchPoints;
-
- PrioritizedOperations.Clear();
- double switchPointProbability = 0.1;
- if (ScheduleLength != 0)
- {
- switchPointProbability = 1.0 * _numSwitchPointsLeft / (ScheduleLength - ScheduledSteps + 1);
- }
- _nextPriorityChangePoint = Generator.Mutator.Utils.SampleGeometric(switchPointProbability, Provider.SwitchPointChoice());
- return true;
- }
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomPriorizationProvider.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomPriorizationProvider.cs
deleted file mode 100644
index c757366cd4..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomPriorizationProvider.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using PChecker.Random;
-
-namespace PChecker.SystematicTesting.Strategies.Probabilistic;
-
-internal class RandomPriorizationProvider: PriorizationProvider
-{
-
- ///
- /// Random value generator.
- ///
- private readonly IRandomValueGenerator RandomValueGenerator;
-
- public RandomPriorizationProvider(IRandomValueGenerator generator)
- {
- RandomValueGenerator = generator;
- }
- public int AssignPriority(int numOps)
- {
- return RandomValueGenerator.Next(numOps) + 1;
- }
-
- public double SwitchPointChoice()
- {
- return RandomValueGenerator.NextDouble();
- }
-
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomScheduler.cs
new file mode 100644
index 0000000000..4194e51d94
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomScheduler.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using PChecker.Generator.Mutator;
+using PChecker.Generator.Object;
+using PChecker.Random;
+using PChecker.SystematicTesting.Operations;
+using PChecker.SystematicTesting.Strategies.Probabilistic;
+
+namespace PChecker.SystematicTesting.Strategies.Probabilistic;
+
+internal class RandomScheduler : IScheduler
+{
+ private readonly IRandomValueGenerator _randomValueGenerator;
+ public RandomScheduler(IRandomValueGenerator randomValueGenerator)
+ {
+ _randomValueGenerator = randomValueGenerator;
+ }
+
+ public bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
+ {
+ var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
+ next = null;
+ if (enabledOperations.Count == 0)
+ {
+ return false;
+ }
+
+ if (enabledOperations.Count == 1)
+ {
+ next = enabledOperations[0];
+ return true;
+ }
+ var idx = _randomValueGenerator.Next(enabledOperations.Count);
+ next = enabledOperations[idx];
+ return true;
+ }
+
+ public void Reset()
+ {
+ }
+
+ public bool PrepareForNextIteration()
+ {
+ return true;
+ }
+
+ IScheduler IScheduler.Mutate()
+ {
+ return new RandomScheduler(((ControlledRandom)_randomValueGenerator).Mutate());
+ }
+
+ IScheduler IScheduler.New()
+ {
+ return new RandomScheduler(((ControlledRandom)_randomValueGenerator).New());
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedSchedulingStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/ScheduleAndInputStrategy.cs
similarity index 89%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedSchedulingStrategy.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/ScheduleAndInputStrategy.cs
index 6f50c24677..1491786e1f 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PrioritizedSchedulingStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/ScheduleAndInputStrategy.cs
@@ -18,7 +18,7 @@ namespace PChecker.SystematicTesting.Strategies.Probabilistic
/// This strategy is described in the following paper:
/// https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/asplos277-pct.pdf
///
- internal class PrioritizedSchedulingStrategy: ISchedulingStrategy
+ internal class ScheduleAndInputStrategy: ISchedulingStrategy
{
///
@@ -33,12 +33,12 @@ internal class PrioritizedSchedulingStrategy: ISchedulingStrategy
private int _scheduledSteps;
- internal readonly PrioritizedScheduler Scheduler;
+ internal readonly IScheduler Scheduler;
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
- public PrioritizedSchedulingStrategy(int maxSteps, IRandomValueGenerator random, PrioritizedScheduler scheduler)
+ public ScheduleAndInputStrategy(int maxSteps, IRandomValueGenerator random, IScheduler scheduler)
{
RandomValueGenerator = random;
MaxScheduledSteps = maxSteps;
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs
index 6e097b5be8..e8be37de16 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs
@@ -105,7 +105,8 @@ public class TestReport
/// Set of hashes of timelines discovered by the scheduler.
///
[DataMember]
- public Dictionary ExploredTimelines = new();
+ public HashSet ExploredTimelines = new();
+
///
/// Lock for the test report.
@@ -153,6 +154,7 @@ public bool Merge(TestReport testReport)
lock (Lock)
{
CoverageInfo.Merge(testReport.CoverageInfo);
+ ExploredTimelines.UnionWith(testReport.ExploredTimelines);
NumOfFoundBugs += testReport.NumOfFoundBugs;
@@ -238,6 +240,13 @@ public string GetText(CheckerConfiguration checkerConfiguration, string prefix =
prefix.Equals("...") ? "....." : prefix,
totalExploredSchedules,
totalExploredSchedules == 1 ? string.Empty : "s");
+
+ report.AppendLine();
+ report.AppendFormat(
+ "{0} Explored {1} timeline{2}",
+ prefix.Equals("...") ? "....." : prefix,
+ ExploredTimelines.Count,
+ ExploredTimelines.Count == 1 ? string.Empty : "s");
if (totalExploredSchedules > 0 &&
NumOfFoundBugs > 0)
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
index d461c72e51..d0bfe9974d 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
@@ -19,6 +19,7 @@
using PChecker.Feedback;
using PChecker.Generator;
using PChecker.Generator.Mutator;
+using PChecker.Generator.Object;
using PChecker.IO;
using PChecker.IO.Debugging;
using PChecker.IO.Logging;
@@ -285,27 +286,29 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
}
else if (checkerConfiguration.SchedulingStrategy is "random")
{
- Strategy = new RandomStrategy(checkerConfiguration.MaxFairSchedulingSteps, RandomValueGenerator);
+ var scheduler = new RandomScheduler(RandomValueGenerator);
+ Strategy = new ScheduleAndInputStrategy(checkerConfiguration.MaxFairSchedulingSteps,
+ RandomValueGenerator, scheduler);
}
else if (checkerConfiguration.SchedulingStrategy is "pct")
{
var scheduler = new PCTScheduler(checkerConfiguration.StrategyBound, 0,
- new RandomPriorizationProvider(RandomValueGenerator));
- Strategy = new PrioritizedSchedulingStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
+ RandomValueGenerator);
+ Strategy = new ScheduleAndInputStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
RandomValueGenerator, scheduler);
}
else if (checkerConfiguration.SchedulingStrategy is "pos")
{
- var scheduler = new POSScheduler(new RandomPriorizationProvider(RandomValueGenerator));
- Strategy = new PrioritizedSchedulingStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
+ var scheduler = new POSScheduler(RandomValueGenerator);
+ Strategy = new ScheduleAndInputStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
RandomValueGenerator, scheduler);
}
else if (checkerConfiguration.SchedulingStrategy is "fairpct")
{
var prefixLength = checkerConfiguration.MaxUnfairSchedulingSteps;
var scheduler = new PCTScheduler(checkerConfiguration.StrategyBound, 0,
- new RandomPriorizationProvider(RandomValueGenerator));
- var prefixStrategy = new PrioritizedSchedulingStrategy(prefixLength, RandomValueGenerator, scheduler);
+ RandomValueGenerator);
+ var prefixStrategy = new ScheduleAndInputStrategy(prefixLength, RandomValueGenerator, scheduler);
var suffixStrategy =
new RandomStrategy(checkerConfiguration.MaxFairSchedulingSteps, RandomValueGenerator);
Strategy = new ComboStrategy(prefixStrategy, suffixStrategy);
@@ -325,21 +328,18 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
}
else if (checkerConfiguration.SchedulingStrategy is "feedback")
{
- Strategy = new FeedbackGuidedStrategy(
- _checkerConfiguration, new RandomInputGenerator(checkerConfiguration),
- new RandomScheduleGenerator(checkerConfiguration));
+ Strategy = new FeedbackGuidedStrategy(checkerConfiguration, new ControlledRandom(checkerConfiguration),
+ new RandomScheduler(new ControlledRandom(checkerConfiguration)));
}
else if (checkerConfiguration.SchedulingStrategy is "feedbackpct")
{
- Strategy = new FeedbackGuidedStrategy(_checkerConfiguration,
- new RandomInputGenerator(checkerConfiguration), new PctScheduleGenerator(checkerConfiguration));
+ Strategy = new FeedbackGuidedStrategy(checkerConfiguration, new ControlledRandom(checkerConfiguration),
+ new PCTScheduler(checkerConfiguration.StrategyBound, 0, new ControlledRandom(checkerConfiguration)));
}
else if (checkerConfiguration.SchedulingStrategy is "feedbackpos")
{
- Strategy = new FeedbackGuidedStrategy(
- _checkerConfiguration,
- new RandomInputGenerator(checkerConfiguration),
- new POSScheduleGenerator(_checkerConfiguration));
+ Strategy = new FeedbackGuidedStrategy(checkerConfiguration, new ControlledRandom(checkerConfiguration),
+ new POSScheduler(new ControlledRandom(checkerConfiguration)));
}
else if (checkerConfiguration.SchedulingStrategy is "portfolio")
{
@@ -967,8 +967,7 @@ private void GatherTestingStatistics(ControlledRuntime runtime, TimelineObserver
report.CoverageInfo.Merge(coverageInfo);
TestReport.Merge(report);
var timelineHash = timelineObserver.GetTimelineHash();
- TestReport.ExploredTimelines[timelineHash] =
- TestReport.ExploredTimelines.GetValueOrDefault(timelineHash, 0) + 1;
+ TestReport.ExploredTimelines.Add(timelineObserver.GetTimelineHash());
// Also save the graph snapshot of the last iteration, if there is one.
Graph = coverageInfo.CoverageGraph;
// Also save the graph snapshot of the last schedule, if there is one.
From d8331b84d0729ad3ec1b32ad48909060dd40b682 Mon Sep 17 00:00:00 2001
From: Ao Li
Date: Thu, 17 Oct 2024 15:09:31 +0800
Subject: [PATCH 16/21] Revert changes in QLearning strategy.
---
.../Probabilistic/QLearningStrategy.cs | 67 ++++---------------
1 file changed, 12 insertions(+), 55 deletions(-)
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
index 79b29448c4..ba90bcf613 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/QLearningStrategy.cs
@@ -3,20 +3,17 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
-using PChecker.Feedback;
using System.Text;
using PChecker.Random;
using PChecker.SystematicTesting.Operations;
-using PChecker.SystematicTesting.Strategies.Feedback;
namespace PChecker.SystematicTesting.Strategies.Probabilistic
{
///
/// A probabilistic scheduling strategy that uses Q-learning.
///
- internal class QLearningStrategy : RandomStrategy, IFeedbackGuidedStrategy
+ internal class QLearningStrategy : RandomStrategy
{
///
/// Map from program states to a map from next operations to their quality values.
@@ -81,7 +78,6 @@ internal class QLearningStrategy : RandomStrategy, IFeedbackGuidedStrategy
///
private int Epochs;
-
///
/// Initializes a new instance of the class.
/// It uses the specified random number generator.
@@ -152,6 +148,7 @@ public override bool GetNextIntegerChoice(AsyncOperation current, int maxValue,
///
public override bool PrepareForNextIteration()
{
+ this.LearnQValues();
this.ExecutionPath.Clear();
this.PreviousOperation = 0;
this.Epochs++;
@@ -361,50 +358,18 @@ private void InitializeIntegerChoiceQValues(int state, int maxValue)
}
}
- private readonly HashSet _visitedTimelines = new();
- private readonly List> _savedTimelines = new();
- private int ComputeDiversity(int timeline, List hash)
- {
- if (!_visitedTimelines.Add(timeline))
- {
- return 0;
- }
-
- if (_savedTimelines.Count == 0)
- {
- return 20;
- }
-
- var maxSim = int.MinValue;
- foreach (var record in _savedTimelines)
- {
- var similarity = 0;
- for (int i = 0; i < hash.Count; i++)
- {
- if (hash[i] == record[i])
- {
- similarity += 1;
- }
- }
-
- maxSim = Math.Max(maxSim, similarity);
- }
-
-
- return (hash.Count - maxSim) * 10 + 20;
- }
-
- public void ObserveRunningResults(TimelineObserver timelineObserver)
+ ///
+ /// Learn Q values using data from the current execution.
+ ///
+ private void LearnQValues()
{
- var timelineHash = timelineObserver.GetTimelineHash();
- var timelineMinhash = timelineObserver.GetTimelineMinhash();
-
- int priority = 1;
-
+ var pathBuilder = new StringBuilder();
+ int idx = 0;
var node = this.ExecutionPath.First;
while (node != null && node.Next != null)
{
+ pathBuilder.Append($"{node.Value.op},");
var (_, _, state) = node.Value;
var (nextOp, nextType, nextState) = node.Next.Value;
@@ -421,8 +386,8 @@ public void ObserveRunningResults(TimelineObserver timelineObserver)
// Compute the reward. Program states that are visited with higher frequency result into lesser rewards.
var freq = this.TransitionFrequencies[nextState];
- double reward = ((nextType == AsyncOperationType.InjectFailure ?
- this.FailureInjectionReward : this.BasicActionReward) * freq) / priority;
+ double reward = (nextType == AsyncOperationType.InjectFailure ?
+ this.FailureInjectionReward : this.BasicActionReward) * freq;
if (reward > 0)
{
// The reward has underflowed.
@@ -442,16 +407,8 @@ public void ObserveRunningResults(TimelineObserver timelineObserver)
(this.LearningRate * (reward + (this.Gamma * maxQ)));
node = node.Next;
+ idx++;
}
}
-
- public int TotalSavedInputs()
- {
- return 0;
- }
-
- public void DumpStats(TextWriter writer)
- {
- }
}
}
\ No newline at end of file
From b4837daddd56598e99138831b5b26283bf6be1a0 Mon Sep 17 00:00:00 2001
From: Ao Li
Date: Thu, 17 Oct 2024 15:12:51 +0800
Subject: [PATCH 17/21] Refactor.
---
.../{Object => }/ControlledRandom.cs | 0
.../Feedback/Generator/IGenerator.cs | 12 ----------
.../Feedback/Generator/IInputGenerator.cs | 22 -------------------
.../Feedback/Generator/IScheduleGenerator.cs | 18 ---------------
.../Generator/{Object => }/RandomChoices.cs | 0
.../Feedback/Generator/{Mutator => }/Utils.cs | 0
6 files changed, 52 deletions(-)
rename Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/{Object => }/ControlledRandom.cs (100%)
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IGenerator.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IInputGenerator.cs
delete mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IScheduleGenerator.cs
rename Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/{Object => }/RandomChoices.cs (100%)
rename Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/{Mutator => }/Utils.cs (100%)
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/ControlledRandom.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/ControlledRandom.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/ControlledRandom.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/ControlledRandom.cs
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IGenerator.cs
deleted file mode 100644
index 8face2fa56..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IGenerator.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace PChecker.Generator;
-
-public interface IGenerator
-{
- ///
- /// Mutate the current generator and create a new one.
- ///
- /// A new generator.
- T Mutate();
-
- T New();
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IInputGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IInputGenerator.cs
deleted file mode 100644
index a8ce3b097f..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IInputGenerator.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-namespace PChecker.Generator;
-
-public interface IInputGenerator : IGenerator
-{
-
- ///
- /// Returns a non-negative random number.
- ///
- int Next();
-
- ///
- /// Returns a non-negative random number less than maxValue.
- ///
- /// Exclusive upper bound
- int Next(int maxValue);
-
- ///
- /// Returns a random floating-point number that is greater
- /// than or equal to 0.0, and less than 1.0.
- ///
- double NextDouble();
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IScheduleGenerator.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IScheduleGenerator.cs
deleted file mode 100644
index 4850f55ef6..0000000000
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/IScheduleGenerator.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System.Collections.Generic;
-using PChecker.SystematicTesting.Operations;
-
-namespace PChecker.Generator;
-
-internal interface IScheduleGenerator: IGenerator
-{
- ///
- /// Get the next scheduled operation.
- ///
- /// All enabled operations.
- /// Current operation.
- /// Next enabled operation.
- public AsyncOperation? NextRandomOperation(List enabledOperations, AsyncOperation current);
-
-
- public void PrepareForNextInput();
-}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/RandomChoices.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomChoices.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Object/RandomChoices.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/RandomChoices.cs
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/Utils.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Utils.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Mutator/Utils.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Generator/Utils.cs
From 2eda0405e49b61168d6f131d8736cae7a07f2c4d Mon Sep 17 00:00:00 2001
From: ChristineZh0u <48167738+ChristineZh0u@users.noreply.github.com>
Date: Thu, 17 Oct 2024 22:00:46 -0700
Subject: [PATCH 18/21] Added VectorTime and BehavioralObserver class for
feedback strategy (#799)
Co-authored-by: Christine Zhou
---
.../CheckerCore/Runtime/Events/EventInfo.cs | 5 +-
.../StateMachines/EventQueues/EventQueue.cs | 4 +-
.../Runtime/StateMachines/StateMachine.cs | 13 ++
.../CheckerCore/Runtime/VectorTime.cs | 124 +++++++++++++
.../SystematicTesting/ControlledRuntime.cs | 2 +-
.../Feedback/Coverage/BehavioralObserver.cs | 166 ++++++++++++++++++
.../SystematicTesting/TestingEngine.cs | 1 +
7 files changed, 311 insertions(+), 4 deletions(-)
create mode 100644 Src/PChecker/CheckerCore/Runtime/VectorTime.cs
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/BehavioralObserver.cs
diff --git a/Src/PChecker/CheckerCore/Runtime/Events/EventInfo.cs b/Src/PChecker/CheckerCore/Runtime/Events/EventInfo.cs
index a4de780989..993ab9dae7 100644
--- a/Src/PChecker/CheckerCore/Runtime/Events/EventInfo.cs
+++ b/Src/PChecker/CheckerCore/Runtime/Events/EventInfo.cs
@@ -23,6 +23,8 @@ internal class EventInfo
[DataMember]
internal EventOriginInfo OriginInfo { get; private set; }
+ internal VectorTime VectorTime;
+
///
/// Initializes a new instance of the class.
///
@@ -34,10 +36,11 @@ internal EventInfo(Event e)
///
/// Initializes a new instance of the class.
///
- internal EventInfo(Event e, EventOriginInfo originInfo)
+ internal EventInfo(Event e, EventOriginInfo originInfo, VectorTime v)
: this(e)
{
OriginInfo = originInfo;
+ VectorTime = new VectorTime(v);
}
}
}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/EventQueue.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/EventQueue.cs
index 7db5bb7440..569c082438 100644
--- a/Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/EventQueue.cs
+++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/EventQueue.cs
@@ -157,7 +157,7 @@ public EnqueueStatus Enqueue(Event e, EventInfo info)
// A default event handler exists.
var stateName = StateMachine.CurrentState.GetType().Name;
var eventOrigin = new EventOriginInfo(StateMachine.Id, StateMachine.GetType().FullName, stateName);
- return (DequeueStatus.Default, DefaultEvent.Instance, new EventInfo(DefaultEvent.Instance, eventOrigin));
+ return (DequeueStatus.Default, DefaultEvent.Instance, new EventInfo(DefaultEvent.Instance, eventOrigin, StateMachine.VectorTime));
}
///
@@ -209,7 +209,7 @@ public void RaiseEvent(Event e)
{
var stateName = StateMachine.CurrentState.GetType().Name;
var eventOrigin = new EventOriginInfo(StateMachine.Id, StateMachine.GetType().FullName, stateName);
- var info = new EventInfo(e, eventOrigin);
+ var info = new EventInfo(e, eventOrigin, StateMachine.VectorTime);
RaisedEvent = (e, info);
StateMachineManager.OnRaiseEvent(e, info);
}
diff --git a/Src/PChecker/CheckerCore/Runtime/StateMachines/StateMachine.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/StateMachine.cs
index 0c2ae5701a..6f6019b443 100644
--- a/Src/PChecker/CheckerCore/Runtime/StateMachines/StateMachine.cs
+++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/StateMachine.cs
@@ -54,6 +54,11 @@ public abstract class StateMachine
///
private protected IEventQueue Inbox;
+ ///
+ /// Keeps track of state machine's current vector time.
+ ///
+ public VectorTime VectorTime;
+
///
/// Cache of state machine types to a map of action names to action declarations.
///
@@ -295,6 +300,7 @@ internal void Configure(ControlledRuntime runtime, StateMachineId id, IStateMach
Id = id;
Manager = manager;
Inbox = inbox;
+ VectorTime = new VectorTime(Id);
}
///
@@ -535,6 +541,9 @@ public void SendEvent(PMachineValue target, Event ev)
Assert(target.Permissions.Contains(ev.GetType().Name),
$"Event {ev.GetType().Name} is not in the permissions set of the target machine");
AnnounceInternal(ev);
+ // Update vector clock
+ VectorTime.Increment();
+ BehavioralObserver.AddToCurrentTimeline(ev, BehavioralObserver.EventType.SEND, VectorTime);
Runtime.SendEvent(target.Id, ev, this);
}
@@ -590,6 +599,10 @@ internal async Task RunEventHandlerAsync()
if (status is DequeueStatus.Success)
{
+ // Update state machine vector clock
+ VectorTime.Merge(info.VectorTime);
+ BehavioralObserver.AddToCurrentTimeline(e, BehavioralObserver.EventType.DEQUEUE, VectorTime);
+
// Notify the runtime for a new event to handle. This is only used
// during bug-finding and operation bounding, because the runtime
// has to schedule an state machine when a new operation is dequeued.
diff --git a/Src/PChecker/CheckerCore/Runtime/VectorTime.cs b/Src/PChecker/CheckerCore/Runtime/VectorTime.cs
new file mode 100644
index 0000000000..02359e8921
--- /dev/null
+++ b/Src/PChecker/CheckerCore/Runtime/VectorTime.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using PChecker.Runtime.StateMachines;
+using PChecker.IO.Logging;
+
+public class VectorTime
+{
+ // Dictionary that uses StateMachineId as the key and stores the logical clock as the value
+ public Dictionary Clock { get; private set; }
+
+ // The ID of the current state machine
+
+ private StateMachineId stateMachineId;
+
+ public VectorTime(StateMachineId stateMachineId)
+ {
+ this.stateMachineId = stateMachineId;
+ Clock = new Dictionary();
+ Clock[stateMachineId] = 0; // Initialize the clock for this state machine
+ }
+
+ // Clone constructor (creates a snapshot of the vector clock)
+ public VectorTime(VectorTime other)
+ {
+ Clock = new Dictionary(other.Clock);
+ }
+
+ // Increment the logical clock for this state machine
+ public void Increment()
+ {
+ Clock[stateMachineId]++;
+ }
+
+ // Merge another vector clock into this one
+ public void Merge(VectorTime otherTime)
+ {
+ foreach (var entry in otherTime.Clock)
+ {
+ StateMachineId otherMachineId = entry.Key;
+ int otherTimestamp = entry.Value;
+
+ if (Clock.ContainsKey(otherMachineId))
+ {
+ // Take the maximum timestamp for each state machine
+ Clock[otherMachineId] = Math.Max(Clock[otherMachineId], otherTimestamp);
+ }
+ else
+ {
+ // Add the state machine's timestamp if it doesn't exist in this time
+ Clock[otherMachineId] = otherTimestamp;
+ }
+ }
+ }
+
+ // Compare this vector clock to another for sorting purposes
+ // Rturn value: -1 = This vector clock happens after the other, 1 = This vector clock happens before the other,
+ // 0 = Clocks are equal or concurrent
+ public int CompareTo(VectorTime other)
+ {
+ bool atLeastOneLess = false;
+ bool atLeastOneGreater = false;
+
+ foreach (var machineId in Clock.Keys)
+ {
+ int thisTime = Clock[machineId];
+ int otherTime = other.Clock.ContainsKey(machineId) ? other.Clock[machineId] : 0;
+
+ if (thisTime < otherTime)
+ {
+ atLeastOneLess = true;
+ }
+ else if (thisTime > otherTime)
+ {
+ atLeastOneGreater = true;
+ }
+ if (atLeastOneLess && atLeastOneGreater)
+ {
+ return 0;
+ }
+ }
+ if (atLeastOneLess && !atLeastOneGreater)
+ {
+ return -1;
+ }
+ if (atLeastOneGreater && !atLeastOneLess)
+ {
+ return 1;
+ }
+ return 0;
+ }
+
+
+ public override string ToString()
+ {
+ var elements = new List();
+ foreach (var entry in Clock)
+ {
+ elements.Add($"StateMachine {entry.Key.Name}: {entry.Value}");
+ }
+ return $"[{string.Join(", ", elements)}]";
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is VectorTime other)
+ {
+ return Clock.OrderBy(x => x.Key).SequenceEqual(other.Clock.OrderBy(x => x.Key));
+ }
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ int hash = 17;
+ foreach (var entry in Clock)
+ {
+ hash = hash * 31 + entry.Key.GetHashCode();
+ hash = hash * 31 + entry.Value.GetHashCode();
+ }
+ return hash;
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs b/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
index 23327d0a8d..1c6b814453 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs
@@ -649,7 +649,7 @@ private EnqueueStatus EnqueueEvent(StateMachine stateMachine, Event e, StateMach
var originInfo = new EventOriginInfo(sender.Id, sender.GetType().FullName,
sender.CurrentState.GetType().Name);
- var eventInfo = new EventInfo(e, originInfo);
+ var eventInfo = new EventInfo(e, originInfo, sender.VectorTime);
LogWriter.LogSendEvent(stateMachine.Id, sender.Id.Name, sender.Id.Type, sender.CurrentStateName,
e, isTargetHalted: false);
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/BehavioralObserver.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/BehavioralObserver.cs
new file mode 100644
index 0000000000..35a3353d0a
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/Coverage/BehavioralObserver.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using PChecker.IO.Logging;
+using PChecker.Runtime.Events;
+
+namespace PChecker.Runtime;
+
+public class BehavioralObserver
+{
+ private static HashSet<(VectorTime, Event, EventType)> CurrTimeline = new HashSet<(VectorTime, Event, EventType)>();
+ private static List AllTimeline = new List();
+ private static TextWriter Logger = new ConsoleLogger();
+ // MinHash object with 100 hash functions, check how many of these 100 values are identical between the two sets
+ private static MinHash minHash = new MinHash(100);
+
+
+ public enum EventType
+ {
+ SEND, DEQUEUE
+ }
+
+ public BehavioralObserver()
+ {
+ CurrTimeline = new HashSet<(VectorTime, Event, EventType)>();
+ }
+
+ public static void AddToCurrentTimeline(Event e, EventType t, VectorTime vectorTime)
+ {
+ CurrTimeline.Add((new VectorTime(vectorTime), e, t));
+ }
+
+ public static int CalculateDiff(int[] currentSignature, int[] otherSignature)
+ {
+ double similarity = minHash.ComputeSimilarity(currentSignature, otherSignature);
+ double differenceScore = 1 - similarity;
+ return (int)(differenceScore * 100); // Scale the difference score (e.g., multiply by 100)
+ }
+
+ public static int GetUniqueScore(int[] currentSignature)
+ {
+ int scoreSum = 0;
+ foreach (var otherSignature in AllTimeline)
+ {
+ int score = CalculateDiff(currentSignature, otherSignature);
+ if (score == 0)
+ {
+ return 0;
+ }
+ scoreSum += score;
+ }
+ return scoreSum/AllTimeline.Count;
+ }
+
+ public static void PrintTimeline(List<(VectorTime, Event, EventType)> timeline)
+ {
+ Logger.WriteLine("Global state of all machines:");
+ foreach (var entry in timeline)
+ {
+ Logger.WriteLine($"Machine {entry}");
+ }
+ }
+
+ public static List<(VectorTime, Event, EventType)> SortByVectorClock()
+ {
+ List<(VectorTime, Event, EventType)> sortedTimeline = new List<(VectorTime, Event, EventType)>(CurrTimeline);
+
+ // Sort by event name then vector time
+ sortedTimeline.Sort((x, y) => x.Item2.ToString().CompareTo(y.Item2.ToString()));
+ sortedTimeline.Sort((x, y) => x.Item1.CompareTo(y.Item1));
+
+ return sortedTimeline;
+ }
+
+ public static void NextIter()
+ {
+ if (CurrTimeline.Count == 0)
+ {
+ return;
+ }
+ List<(VectorTime, Event, EventType)> SortedCurrTimeline = SortByVectorClock();
+ int[] currSignature = minHash.ComputeMinHashSignature(SortedCurrTimeline);
+ if (AllTimeline.Count == 0)
+ {
+ AllTimeline.Add(currSignature);
+ return;
+ }
+ int uniqueScore = GetUniqueScore(currSignature);
+ Logger.WriteLine($"----**** UniquenessScore: {uniqueScore}");
+ if (uniqueScore != 0)
+ {
+ AllTimeline.Add(currSignature);
+ }
+ CurrTimeline = new HashSet<(VectorTime, Event, EventType)>();
+ }
+}
+
+public class MinHash
+{
+ private int numHashFunctions; // Number of hash functions to use
+ private List> hashFunctions; // List of hash functions
+
+ public MinHash(int numHashFunctions)
+ {
+ this.numHashFunctions = numHashFunctions;
+ this.hashFunctions = new List>();
+
+ System.Random rand = new System.Random();
+ for (int i = 0; i < numHashFunctions; i++)
+ {
+ int a = rand.Next();
+ int b = rand.Next();
+ hashFunctions.Add(x => a * x + b);
+ }
+ }
+
+ // Create a MinHash signature for a given set
+ public int[] ComputeMinHashSignature(List<(VectorTime, Event, BehavioralObserver.EventType)> set)
+ {
+ int[] signature = new int[numHashFunctions];
+
+ for (int i = 0; i < numHashFunctions; i++)
+ {
+ signature[i] = int.MaxValue;
+ }
+ foreach (var element in set)
+ {
+ int elementHash = ComputeElementHash(element);
+
+ for (int i = 0; i < numHashFunctions; i++)
+ {
+ int hashedValue = hashFunctions[i](elementHash);
+ if (hashedValue < signature[i])
+ {
+ signature[i] = hashedValue;
+ }
+ }
+ }
+ return signature;
+ }
+
+ // Compute a composite hash for the (VectorTime, Event, EventType) tuple
+ private int ComputeElementHash((VectorTime, Event, BehavioralObserver.EventType) element)
+ {
+ int hash1 = element.Item1.GetHashCode();
+ int hash2 = element.Item2.GetHashCode();
+ int hash3 = element.Item3.GetHashCode();
+ return hash1 ^ hash2 ^ hash3;
+ }
+
+ // Compute Jaccard similarity based on MinHash signatures
+ public double ComputeSimilarity(int[] signature1, int[] signature2)
+ {
+ int identicalMinHashes = 0;
+
+ for (int i = 0; i < numHashFunctions; i++)
+ {
+ if (signature1[i] == signature2[i])
+ {
+ identicalMinHashes++;
+ }
+ }
+ return (double)identicalMinHashes / numHashFunctions;
+ }
+}
+
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
index d0bfe9974d..da7952ce74 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
@@ -542,6 +542,7 @@ private void RegisterObservers(ControlledRuntime runtime)
///
private void RunNextIteration(int schedule)
{
+ BehavioralObserver.NextIter();
if (!IsReplayModeEnabled && ShouldPrintIteration(schedule + 1))
{
Logger.WriteLine($"..... Schedule #{schedule + 1}");
From 5e306b4d6f2bce0323afd76383bc7192de14cb8a Mon Sep 17 00:00:00 2001
From: Ao Li
Date: Fri, 18 Oct 2024 15:20:05 +0800
Subject: [PATCH 19/21] Revert changes in PCTStrategy.
---
.../{Probabilistic => Feedback}/IScheduler.cs | 0
.../PCTScheduler.cs | 0
.../POSScheduler.cs | 0
.../ScheduleAndInputStrategy.cs | 0
.../Strategies/Probabilistic/PCTStrategy.cs | 278 ++++++++++++++++++
.../SystematicTesting/TestingEngine.cs | 15 +-
6 files changed, 282 insertions(+), 11 deletions(-)
rename Src/PChecker/CheckerCore/SystematicTesting/Strategies/{Probabilistic => Feedback}/IScheduler.cs (100%)
rename Src/PChecker/CheckerCore/SystematicTesting/Strategies/{Probabilistic => Feedback}/PCTScheduler.cs (100%)
rename Src/PChecker/CheckerCore/SystematicTesting/Strategies/{Probabilistic => Feedback}/POSScheduler.cs (100%)
rename Src/PChecker/CheckerCore/SystematicTesting/Strategies/{Probabilistic => Feedback}/ScheduleAndInputStrategy.cs (100%)
create mode 100644 Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/IScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IScheduler.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/IScheduler.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/IScheduler.cs
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/PCTScheduler.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTScheduler.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/PCTScheduler.cs
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/POSScheduler.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/POSScheduler.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/POSScheduler.cs
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/ScheduleAndInputStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/ScheduleAndInputStrategy.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/ScheduleAndInputStrategy.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/ScheduleAndInputStrategy.cs
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs
new file mode 100644
index 0000000000..825a6d4be5
--- /dev/null
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs
@@ -0,0 +1,278 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using PChecker.IO.Debugging;
+using PChecker.Random;
+using PChecker.SystematicTesting.Operations;
+
+namespace PChecker.SystematicTesting.Strategies.Probabilistic
+{
+ ///
+ /// A priority-based probabilistic scheduling strategy.
+ ///
+ ///
+ /// This strategy is described in the following paper:
+ /// https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/asplos277-pct.pdf
+ ///
+ internal sealed class PCTStrategy : ISchedulingStrategy
+ {
+ ///
+ /// Random value generator.
+ ///
+ private readonly IRandomValueGenerator RandomValueGenerator;
+
+ ///
+ /// The maximum number of steps to schedule.
+ ///
+ private readonly int MaxScheduledSteps;
+
+ ///
+ /// The number of scheduled steps.
+ ///
+ private int ScheduledSteps;
+
+ ///
+ /// Max number of priority switch points.
+ ///
+ private readonly int MaxPrioritySwitchPoints;
+
+ ///
+ /// Approximate length of the schedule across all schedules.
+ ///
+ private int ScheduleLength;
+
+ ///
+ /// List of prioritized operations.
+ ///
+ private readonly List PrioritizedOperations;
+
+ ///
+ /// Set of priority change points.
+ ///
+ private readonly SortedSet PriorityChangePoints;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PCTStrategy(int maxSteps, int maxPrioritySwitchPoints, IRandomValueGenerator random)
+ {
+ RandomValueGenerator = random;
+ MaxScheduledSteps = maxSteps;
+ ScheduledSteps = 0;
+ ScheduleLength = 0;
+ MaxPrioritySwitchPoints = maxPrioritySwitchPoints;
+ PrioritizedOperations = new List();
+ PriorityChangePoints = new SortedSet();
+ }
+
+ ///
+ public bool GetNextOperation(AsyncOperation current, IEnumerable ops, out AsyncOperation next)
+ {
+ next = null;
+ var enabledOperations = ops.Where(op => op.Status is AsyncOperationStatus.Enabled).ToList();
+ if (enabledOperations.Count == 0)
+ {
+ return false;
+ }
+
+ var highestEnabledOp = GetPrioritizedOperation(enabledOperations, current);
+ if (next is null)
+ {
+ next = highestEnabledOp;
+ }
+
+ ScheduledSteps++;
+
+ return true;
+ }
+
+ ///
+ public bool GetNextBooleanChoice(AsyncOperation current, int maxValue, out bool next)
+ {
+ next = false;
+ if (RandomValueGenerator.Next(maxValue) == 0)
+ {
+ next = true;
+ }
+
+ ScheduledSteps++;
+
+ return true;
+ }
+
+ ///
+ public bool GetNextIntegerChoice(AsyncOperation current, int maxValue, out int next)
+ {
+ next = RandomValueGenerator.Next(maxValue);
+ ScheduledSteps++;
+ return true;
+ }
+
+ ///
+ public bool PrepareForNextIteration()
+ {
+ ScheduleLength = Math.Max(ScheduleLength, ScheduledSteps);
+ ScheduledSteps = 0;
+
+ PrioritizedOperations.Clear();
+ PriorityChangePoints.Clear();
+
+ var range = new List();
+ for (var idx = 0; idx < ScheduleLength; idx++)
+ {
+ range.Add(idx);
+ }
+
+ foreach (var point in Shuffle(range).Take(MaxPrioritySwitchPoints))
+ {
+ PriorityChangePoints.Add(point);
+ }
+
+ return true;
+ }
+
+ ///
+ public int GetScheduledSteps() => ScheduledSteps;
+
+ ///
+ public bool HasReachedMaxSchedulingSteps()
+ {
+ if (MaxScheduledSteps == 0)
+ {
+ return false;
+ }
+
+ return ScheduledSteps >= MaxScheduledSteps;
+ }
+
+ ///
+ public bool IsFair() => false;
+
+ ///
+ public string GetDescription()
+ {
+ var text = $"pct[priority change points '{MaxPrioritySwitchPoints}' [" +
+ string.Join(", ", PriorityChangePoints.ToArray()) +
+ "], seed '" + RandomValueGenerator.Seed + "']";
+ return text;
+ }
+
+ ///
+ /// Returns the prioritized operation.
+ ///
+ private AsyncOperation GetPrioritizedOperation(List ops, AsyncOperation current)
+ {
+ if (PrioritizedOperations.Count == 0)
+ {
+ PrioritizedOperations.Add(current);
+ }
+
+ foreach (var op in ops.Where(op => !PrioritizedOperations.Contains(op)))
+ {
+ var mIndex = RandomValueGenerator.Next(PrioritizedOperations.Count) + 1;
+ PrioritizedOperations.Insert(mIndex, op);
+ Debug.WriteLine(" Detected new operation '{0}' at index '{1}'.", op.Id, mIndex);
+ }
+
+ if (PriorityChangePoints.Contains(ScheduledSteps))
+ {
+ if (ops.Count == 1)
+ {
+ MovePriorityChangePointForward();
+ }
+ else
+ {
+ var priority = GetHighestPriorityEnabledOperation(ops);
+ PrioritizedOperations.Remove(priority);
+ PrioritizedOperations.Add(priority);
+ Debug.WriteLine(" Operation '{0}' changes to lowest priority.", priority);
+ }
+ }
+
+ var prioritizedSchedulable = GetHighestPriorityEnabledOperation(ops);
+ if (Debug.IsEnabled)
+ {
+ Debug.WriteLine(" Prioritized schedulable '{0}'.", prioritizedSchedulable);
+ Debug.Write(" Priority list: ");
+ for (var idx = 0; idx < PrioritizedOperations.Count; idx++)
+ {
+ if (idx < PrioritizedOperations.Count - 1)
+ {
+ Debug.Write("'{0}', ", PrioritizedOperations[idx]);
+ }
+ else
+ {
+ Debug.WriteLine("'{0}'.", PrioritizedOperations[idx]);
+ }
+ }
+ }
+
+ return ops.First(op => op.Equals(prioritizedSchedulable));
+ }
+
+ ///
+ /// Returns the highest-priority enabled operation.
+ ///
+ private AsyncOperation GetHighestPriorityEnabledOperation(IEnumerable choices)
+ {
+ AsyncOperation prioritizedOp = null;
+ foreach (var entity in PrioritizedOperations)
+ {
+ if (choices.Any(m => m == entity))
+ {
+ prioritizedOp = entity;
+ break;
+ }
+ }
+
+ return prioritizedOp;
+ }
+
+ ///
+ /// Shuffles the specified list using the Fisher-Yates algorithm.
+ ///
+ private IList Shuffle(IList list)
+ {
+ var result = new List(list);
+ for (var idx = result.Count - 1; idx >= 1; idx--)
+ {
+ var point = RandomValueGenerator.Next(ScheduleLength);
+ var temp = result[idx];
+ result[idx] = result[point];
+ result[point] = temp;
+ }
+
+ return result;
+ }
+
+ ///
+ /// Moves the current priority change point forward. This is a useful
+ /// optimization when a priority change point is assigned in either a
+ /// sequential execution or a nondeterministic choice.
+ ///
+ private void MovePriorityChangePointForward()
+ {
+ PriorityChangePoints.Remove(ScheduledSteps);
+ var newPriorityChangePoint = ScheduledSteps + 1;
+ while (PriorityChangePoints.Contains(newPriorityChangePoint))
+ {
+ newPriorityChangePoint++;
+ }
+
+ PriorityChangePoints.Add(newPriorityChangePoint);
+ Debug.WriteLine(" Moving priority change to '{0}'.", newPriorityChangePoint);
+ }
+
+ ///
+ public void Reset()
+ {
+ ScheduleLength = 0;
+ ScheduledSteps = 0;
+ PrioritizedOperations.Clear();
+ PriorityChangePoints.Clear();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
index da7952ce74..32a33cfcec 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
@@ -286,16 +286,12 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
}
else if (checkerConfiguration.SchedulingStrategy is "random")
{
- var scheduler = new RandomScheduler(RandomValueGenerator);
- Strategy = new ScheduleAndInputStrategy(checkerConfiguration.MaxFairSchedulingSteps,
- RandomValueGenerator, scheduler);
+ Strategy = new RandomStrategy(checkerConfiguration.MaxFairSchedulingSteps, RandomValueGenerator);
}
else if (checkerConfiguration.SchedulingStrategy is "pct")
{
- var scheduler = new PCTScheduler(checkerConfiguration.StrategyBound, 0,
+ Strategy = new PCTStrategy(checkerConfiguration.MaxUnfairSchedulingSteps, checkerConfiguration.StrategyBound,
RandomValueGenerator);
- Strategy = new ScheduleAndInputStrategy(checkerConfiguration.MaxUnfairSchedulingSteps,
- RandomValueGenerator, scheduler);
}
else if (checkerConfiguration.SchedulingStrategy is "pos")
{
@@ -306,11 +302,8 @@ private TestingEngine(CheckerConfiguration checkerConfiguration, TestMethodInfo
else if (checkerConfiguration.SchedulingStrategy is "fairpct")
{
var prefixLength = checkerConfiguration.MaxUnfairSchedulingSteps;
- var scheduler = new PCTScheduler(checkerConfiguration.StrategyBound, 0,
- RandomValueGenerator);
- var prefixStrategy = new ScheduleAndInputStrategy(prefixLength, RandomValueGenerator, scheduler);
- var suffixStrategy =
- new RandomStrategy(checkerConfiguration.MaxFairSchedulingSteps, RandomValueGenerator);
+ var prefixStrategy = new PCTStrategy(prefixLength, checkerConfiguration.StrategyBound, RandomValueGenerator);
+ var suffixStrategy = new RandomStrategy(checkerConfiguration.MaxFairSchedulingSteps, RandomValueGenerator);
Strategy = new ComboStrategy(prefixStrategy, suffixStrategy);
}
else if (checkerConfiguration.SchedulingStrategy is "probabilistic")
From 91cd7176ea2fc319cf649d9edaff4db3451c3dbe Mon Sep 17 00:00:00 2001
From: Ao Li
Date: Fri, 18 Oct 2024 15:23:37 +0800
Subject: [PATCH 20/21] Revert changes in Probabilistic folder.
---
.../{Probabilistic => Feedback}/RandomScheduler.cs | 0
.../Strategies/Probabilistic/PCTStrategy.cs | 1 -
.../Strategies/Probabilistic/RandomStrategy.cs | 6 +-----
3 files changed, 1 insertion(+), 6 deletions(-)
rename Src/PChecker/CheckerCore/SystematicTesting/Strategies/{Probabilistic => Feedback}/RandomScheduler.cs (100%)
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/RandomScheduler.cs
similarity index 100%
rename from Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomScheduler.cs
rename to Src/PChecker/CheckerCore/SystematicTesting/Strategies/Feedback/RandomScheduler.cs
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs
index 825a6d4be5..21cee4414c 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs
@@ -1,4 +1,3 @@
-// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomStrategy.cs
index eefa755621..7bd654b618 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/RandomStrategy.cs
@@ -48,11 +48,7 @@ public virtual bool GetNextOperation(AsyncOperation current, IEnumerable 1) {
- idx = RandomValueGenerator.Next(enabledOperations.Count);
- }
-
+ var idx = RandomValueGenerator.Next(enabledOperations.Count);
next = enabledOperations[idx];
ScheduledSteps++;
From 3ee77e317a31f417d575f9cbb61cc8ab50903b6a Mon Sep 17 00:00:00 2001
From: Ao Li
Date: Fri, 18 Oct 2024 15:25:49 +0800
Subject: [PATCH 21/21] revert change.
---
.../SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs
index 21cee4414c..3ffdc47c3c 100644
--- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs
+++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Probabilistic/PCTStrategy.cs
@@ -1,3 +1,4 @@
+// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;