/// <summary> /// Gathers the exploration strategy statistics for /// the latest testing iteration. /// </summary> /// <param name="runtime">BugFindingRuntime</param> private void GatherIterationStatistics(BugFindingRuntime runtime) { TestReport report = runtime.Scheduler.GetReport(); report.CoverageInfo.Merge(runtime.CoverageInfo); this.TestReport.Merge(report); }
/// <summary> /// Emits race instrumentation traces. /// </summary> /// <param name="runtime">BugFindingRuntime</param> /// <param name="iteration">Iteration</param> private void EmitRaceInstrumentationTraces(BugFindingRuntime runtime, int iteration) { string name = Path.GetFileNameWithoutExtension(this.Assembly.Location); name += "_" + base.Configuration.TestingProcessId; string directoryPath = base.GetRuntimeTracesDirectory(); foreach (var kvp in runtime.MachineActionTraceMap) { Debug.WriteLine($"<RaceTracing> Machine id '{kvp.Key}'"); foreach (var actionTrace in kvp.Value) { if (actionTrace.Type == MachineActionType.InvocationAction) { Debug.WriteLine($"<RaceTracing> Action '{actionTrace.ActionName}' " + $"'{actionTrace.ActionId}'"); } } if (kvp.Value.Count > 0) { string path = directoryPath + name + "_iteration_" + iteration + "_machine_" + kvp.Key.GetHashCode() + ".osl"; using (FileStream stream = File.Open(path, FileMode.Create)) { DataContractSerializer serializer = new DataContractSerializer(kvp.Value.GetType()); serializer.WriteObject(stream, kvp.Value); Debug.WriteLine($"..... Writing {path}"); } } } }
/// <summary> /// Constructs a reproducable trace. /// </summary> /// <param name="runtime">BugFindingRuntime</param> /// <param name="logger">InMemoryLogger</param> private void ConstructReproducableTrace(BugFindingRuntime runtime, InMemoryLogger logger) { this.ReadableTrace = logger.ToString(); this.ReadableTrace += this.TestReport.GetText(base.Configuration, "<StrategyLog>"); this.BugTrace = runtime.BugTrace; StringBuilder stringBuilder = new StringBuilder(); if (this.Strategy.IsFair()) { stringBuilder.Append("--fair-scheduling").Append(Environment.NewLine); } if (base.Configuration.CacheProgramState) { stringBuilder.Append("--state-caching").Append(Environment.NewLine); stringBuilder.Append("--liveness-temperature-threshold:" + base.Configuration.LivenessTemperatureThreshold). Append(Environment.NewLine); } else { stringBuilder.Append("--liveness-temperature-threshold:" + base.Configuration.LivenessTemperatureThreshold). Append(Environment.NewLine); } if (!base.Configuration.TestMethodName.Equals("")) { stringBuilder.Append("--test-method:" + base.Configuration.TestMethodName). Append(Environment.NewLine); } for (int idx = 0; idx < runtime.ScheduleTrace.Count; idx++) { ScheduleStep step = runtime.ScheduleTrace[idx]; if (step.Type == ScheduleStepType.SchedulingChoice) { stringBuilder.Append($"{step.ScheduledMachineId.Type}" + $"({step.ScheduledMachineId.Value})"); } else if (step.BooleanChoice != null) { stringBuilder.Append(step.BooleanChoice.Value); } else { stringBuilder.Append(step.IntegerChoice.Value); } if (idx < runtime.ScheduleTrace.Count - 1) { stringBuilder.Append(Environment.NewLine); } } this.ReproducableTrace = stringBuilder.ToString(); }
/// <summary> /// Constructor. /// </summary> /// <param name="runtime">BugFindingRuntime</param> /// <param name="strategy">SchedulingStrategy</param> internal BugFindingScheduler(BugFindingRuntime runtime, ISchedulingStrategy strategy) { this.Runtime = runtime; this.Strategy = strategy; this.TaskMap = new ConcurrentDictionary <int, MachineInfo>(); this.CompletionSource = new TaskCompletionSource <bool>(); this.IsSchedulerRunning = true; this.BugFound = false; this.HasFullyExploredSchedule = false; }
/// <summary> /// Constructor. /// </summary> /// <param name="runtime">BugFindingRuntime</param> /// <param name="strategy">SchedulingStrategy</param> internal BugFindingScheduler(BugFindingRuntime runtime, ISchedulingStrategy strategy) { this.Runtime = runtime; this.Strategy = strategy; this.SchedulableInfoMap = new Dictionary <ulong, SchedulableInfo>(); this.CompletionSource = new TaskCompletionSource <bool>(); this.IsSchedulerRunning = true; this.BugFound = false; this.HasFullyExploredSchedule = false; }
/// <summary> /// Initializes the shared counter. /// </summary> /// <param name="value">Initial value</param> /// <param name="Runtime">BugFindingRuntime</param> public MockSharedCounter(int value, BugFindingRuntime Runtime) { this.Runtime = Runtime; CounterMachine = Runtime.CreateMachine(typeof(SharedCounterMachine)); var currentMachine = Runtime.GetCurrentMachine(); Runtime.SendEvent(CounterMachine, SharedCounterEvent.SetEvent(currentMachine.Id, value)); currentMachine.Receive(typeof(SharedCounterResponseEvent)).Wait(); }
/// <summary> /// Constructs a reproducable trace. /// </summary> /// <param name="runtime">BugFindingRuntime</param> private void ConstructReproducableTrace(BugFindingRuntime runtime) { StringBuilder stringBuilder = new StringBuilder(); if (this.Strategy.IsFair()) { stringBuilder.Append("--fair-scheduling").Append(Environment.NewLine); } if (base.Configuration.EnableCycleDetection) { stringBuilder.Append("--cycle-detection").Append(Environment.NewLine); stringBuilder.Append("--liveness-temperature-threshold:" + base.Configuration.LivenessTemperatureThreshold). Append(Environment.NewLine); } else { stringBuilder.Append("--liveness-temperature-threshold:" + base.Configuration.LivenessTemperatureThreshold). Append(Environment.NewLine); } if (!base.Configuration.TestMethodName.Equals("")) { stringBuilder.Append("--test-method:" + base.Configuration.TestMethodName). Append(Environment.NewLine); } for (int idx = 0; idx < runtime.ScheduleTrace.Count; idx++) { ScheduleStep step = runtime.ScheduleTrace[idx]; if (step.Type == ScheduleStepType.SchedulingChoice) { stringBuilder.Append($"({step.ScheduledMachineId})"); } else if (step.BooleanChoice != null) { stringBuilder.Append(step.BooleanChoice.Value); } else { stringBuilder.Append(step.IntegerChoice.Value); } if (idx < runtime.ScheduleTrace.Count - 1) { stringBuilder.Append(Environment.NewLine); } } this.ReproducableTrace = stringBuilder.ToString(); }
/// <summary> /// Initializes the shared dictionary. /// </summary> /// <param name="comparer">Comparre for keys</param> /// <param name="Runtime">BugFindingRuntime</param> public MockSharedDictionary(IEqualityComparer <TKey> comparer, BugFindingRuntime Runtime) { this.Runtime = Runtime; if (comparer != null) { DictionaryMachine = Runtime.CreateMachine(typeof(SharedDictionaryMachine <TKey, TValue>), SharedDictionaryEvent.InitEvent(comparer)); } else { DictionaryMachine = Runtime.CreateMachine(typeof(SharedDictionaryMachine <TKey, TValue>)); } }
/// <summary> /// Constructor. /// </summary> /// <param name="runtime">BugFindingRuntime</param> /// <param name="schedulingStrategy">ISchedulingStrategy</param> internal LivenessChecker(BugFindingRuntime runtime, ISchedulingStrategy schedulingStrategy) { this.Runtime = runtime; this.Monitors = new List <Monitor>(); this.PotentialCycle = new List <Tuple <ScheduleStep, State> >(); this.HotMonitors = new HashSet <Monitor>(); this.LivenessTemperature = 0; this.EndOfCycleIndex = 0; this.CurrentCycleIndex = 0; this.SchedulingStrategy = schedulingStrategy; this.Seed = this.Runtime.Configuration.RandomSchedulingSeed ?? DateTime.Now.Millisecond; this.Random = new DefaultRandomNumberGenerator(this.Seed); }
/// <summary> /// Runs the next testing iteration. /// </summary> /// <param name="iteration">Iteration</param> private void RunNextIteration(int iteration) { if (this.ShouldPrintIteration(iteration + 1)) { base.Logger.WriteLine($"..... Iteration #{iteration + 1}"); } // Runtime used to serialize and test the program in this iteration. BugFindingRuntime runtime = null; // Logger used to intercept the program output if no custom logger // is installed and if verbosity is turned off. InMemoryLogger runtimeLogger = null; // Gets a handle to the standard output and error streams. var stdOut = Console.Out; var stdErr = Console.Error; try { // Creates a new instance of the bug-finding runtime. runtime = new BugFindingRuntime(base.Configuration, base.Strategy, base.Reporter); if (base.Configuration.EnableDataRaceDetection) { // Create a reporter to monitor interesting operations for race detection this.Reporter.SetRuntime(runtime); } // If verbosity is turned off, then intercept the program log, and also dispose // the standard output and error streams. if (base.Configuration.Verbose < 2) { runtimeLogger = new InMemoryLogger(); runtime.SetLogger(runtimeLogger); // Sets the scheduling strategy logger to the in-memory logger. base.SchedulingStrategyLogger.SetLogger(runtimeLogger); var writer = new LogWriter(new DisposingLogger()); Console.SetOut(writer); Console.SetError(writer); } // Runs the test inside the P# test-harness machine. runtime.RunTestHarness(base.TestMethod, base.TestAction); // Wait for the test to terminate. runtime.Wait(); if (runtime.Scheduler.BugFound) { base.ErrorReporter.WriteErrorLine(runtime.Scheduler.BugReport); } // Invokes user-provided cleanup for this iteration. if (base.TestIterationDisposeMethod != null) { // Disposes the test state. base.TestIterationDisposeMethod.Invoke(null, null); } // Invoke the per iteration callbacks, if any. foreach (var callback in base.PerIterationCallbacks) { callback(iteration); } if (base.Configuration.RaceFound) { string message = IO.Utilities.Format("Found a race"); runtime.Scheduler.NotifyAssertionFailure(message, false); foreach (var report in this.TestReport.BugReports) { runtime.Logger.WriteLine(report); } } // 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) { runtime.AssertNoMonitorInHotStateAtTermination(); } this.GatherIterationStatistics(runtime); if (base.TestReport.NumOfFoundBugs > 0) { if (runtimeLogger != null) { this.ReadableTrace = runtimeLogger.ToString(); this.ReadableTrace += this.TestReport.GetText(base.Configuration, "<StrategyLog>"); } this.BugTrace = runtime.BugTrace; this.ConstructReproducableTrace(runtime); } } finally { if (base.Configuration.Verbose < 2) { // Restores the standard output and error streams. Console.SetOut(stdOut); Console.SetError(stdErr); } if (base.Configuration.PerformFullExploration && runtime.Scheduler.BugFound) { base.Logger.WriteLine($"..... Iteration #{iteration + 1} " + $"triggered bug #{base.TestReport.NumOfFoundBugs} " + $"[task-{this.Configuration.TestingProcessId}]"); } // Resets the scheduling strategy logger to the default logger. base.SchedulingStrategyLogger.ResetToDefaultLogger(); // Cleans up the runtime before the next iteration starts. runtimeLogger?.Dispose(); runtime?.Dispose(); } }
/// <summary> /// Constructor. /// </summary> /// <param name="runtime">BugFindingRuntime</param> internal StateCache(BugFindingRuntime runtime) { this.Runtime = runtime; this.StateMap = new Dictionary <ScheduleStep, State>(); this.Fingerprints = new HashSet <Fingerprint>(); }
/// <summary> /// Creates a bug-reproducing task. /// </summary> /// <returns>Task</returns> private Task CreateBugReproducingTask() { Task task = new Task(() => { // Runtime used to serialize and test the program. BugFindingRuntime runtime = null; // Logger used to intercept the program output if no custom logger // is installed and if verbosity is turned off. InMemoryLogger runtimeLogger = null; // Gets a handle to the standard output and error streams. var stdOut = Console.Out; var stdErr = Console.Error; try { if (base.TestInitMethod != null) { // Initializes the test state. base.TestInitMethod.Invoke(null, new object[] { }); } // Creates a new instance of the bug-finding runtime. if (base.TestRuntimeFactoryMethod != null) { runtime = (BugFindingRuntime)base.TestRuntimeFactoryMethod.Invoke(null, new object[] { base.Configuration, base.Strategy, base.Reporter }); } else { runtime = new BugFindingRuntime(base.Configuration, base.Strategy, base.Reporter); } // If verbosity is turned off, then intercept the program log, and also redirect // the standard output and error streams into the runtime logger. if (base.Configuration.Verbose < 2) { runtimeLogger = new InMemoryLogger(); runtime.SetLogger(runtimeLogger); var writer = new LogWriter(new DisposingLogger()); Console.SetOut(writer); Console.SetError(writer); } // Runs the test inside the P# test-harness machine. runtime.RunTestHarness(base.TestMethod, base.TestAction); // Wait for the test to terminate. runtime.Wait(); // Invokes user-provided cleanup for this iteration. if (base.TestIterationDisposeMethod != null) { // Disposes the test state. base.TestIterationDisposeMethod.Invoke(null, new object[] { }); } // Invokes user-provided cleanup for all iterations. if (base.TestDisposeMethod != null) { // Disposes the test state. base.TestDisposeMethod.Invoke(null, new object[] { }); } this.InternalError = (base.Strategy as ReplayStrategy).ErrorText; // 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 && this.InternalError.Length == 0) { runtime.AssertNoMonitorInHotStateAtTermination(); } if (runtime.Scheduler.BugFound && this.InternalError.Length == 0) { base.ErrorReporter.WriteErrorLine(runtime.Scheduler.BugReport); } TestReport report = runtime.Scheduler.GetReport(); report.CoverageInfo.Merge(runtime.CoverageInfo); this.TestReport.Merge(report); } catch (TargetInvocationException ex) { if (!(ex.InnerException is TaskCanceledException)) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } } finally { if (base.Configuration.Verbose < 2) { // Restores the standard output and error streams. Console.SetOut(stdOut); Console.SetError(stdErr); } // Cleans up the runtime. runtimeLogger?.Dispose(); runtime?.Dispose(); } }, base.CancellationTokenSource.Token); return(task); }
/// <summary> /// Runs the next testing iteration. /// </summary> /// <param name="iteration">Iteration</param> private void RunNextIteration(int iteration) { if (this.ShouldPrintIteration(iteration + 1)) { base.Logger.WriteLine($"..... Iteration #{iteration + 1}"); } // Runtime used to serialize and test the program in this iteration. BugFindingRuntime runtime = null; // Logger used to intercept the program output if no custom logger // is installed and if verbosity is turned off. InMemoryLogger runtimeLogger = null; // Gets a handle to the standard output and error streams. var stdOut = Console.Out; var stdErr = Console.Error; try { // Creates a new instance of the bug-finding runtime. runtime = new BugFindingRuntime(base.Configuration, base.Strategy); // If verbosity is turned off, then intercept the program log, and also dispose // the standard output and error streams. if (base.Configuration.Verbose < 2) { runtimeLogger = new InMemoryLogger(); runtime.SetLogger(runtimeLogger); var writer = new LogWriter(new DisposingLogger()); Console.SetOut(writer); Console.SetError(writer); } // Runs the test inside the P# test-harness machine. runtime.RunTestHarness(base.TestMethod, base.TestAction); // Wait for the test to terminate. runtime.Wait(); if (runtime.Scheduler.BugFound) { base.ErrorReporter.WriteErrorLine(runtime.Scheduler.BugReport); } if (this.Configuration.EnableDataRaceDetection) { this.EmitRaceInstrumentationTraces(runtime, iteration); } // Invokes user-provided cleanup for this iteration. if (base.TestIterationDisposeMethod != null) { // Disposes the test state. base.TestIterationDisposeMethod.Invoke(null, null); } // Invoke the per iteration callbacks, if any. foreach (var callback in base.PerIterationCallbacks) { callback(iteration); } // TODO: Clean this up. base.Configuration.RaceDetectionCallback?.Invoke(); if (base.Configuration.RaceFound) { string message = IO.Utilities.Format("Found a race"); runtime.Scheduler.NotifyAssertionFailure(message, false); } // Checks for any liveness property violations. Requires // that the program has terminated and no safety property // violations have been found. if (!runtime.Scheduler.BugFound) { runtime.LivenessChecker.CheckLivenessAtTermination(); } this.GatherIterationStatistics(runtime); if (runtimeLogger != null && base.TestReport.NumOfFoundBugs > 0 && !base.Configuration.PerformFullExploration && !base.Configuration.SuppressTrace) { this.ConstructReproducableTrace(runtime, runtimeLogger); } else if (runtimeLogger != null && base.Configuration.PrintTrace) { this.ConstructReproducableTrace(runtime, runtimeLogger); } } finally { if (base.Configuration.Verbose < 2) { // Restores the standard output and error streams. Console.SetOut(stdOut); Console.SetError(stdErr); } if (base.Configuration.PerformFullExploration && runtime.Scheduler.BugFound) { base.Logger.WriteLine($"..... Iteration #{iteration + 1} " + $"triggered bug #{base.TestReport.NumOfFoundBugs} " + $"[task-{this.Configuration.TestingProcessId}]"); } // Cleans up the runtime before the next iteration starts. runtimeLogger?.Dispose(); runtime?.Dispose(); } }
/// <summary> /// Initializes the shared counter. /// </summary> /// <param name="value">Initial value</param> /// <param name="Runtime">BugFindingRuntime</param> public MockSharedCounter(int value, BugFindingRuntime Runtime) { this.Runtime = Runtime; CounterMachine = Runtime.CreateMachine(typeof(SharedCounterMachine)); Runtime.SendEvent(CounterMachine, SharedCounterEvent.SetEvent(value)); }
public void SetRuntime(PSharpRuntime runtime) { runtime.Assert((runtime as BugFindingRuntime) != null, "Requires passed runtime to support method GetCurrentMachineId"); this.Runtime = runtime as BugFindingRuntime; }
/// <summary> /// Constructor. /// </summary> /// <param name="runtime">PSharpBugFindingRuntime</param> /// <param name="taskMap">Task map</param> internal AsynchronousTaskScheduler(BugFindingRuntime runtime, ConcurrentDictionary <int, Machine> taskMap) { this.Runtime = runtime; this.TaskMap = taskMap; }
/// <summary> /// Constructor. /// </summary> /// <param name="runtime">BugFindingRuntime</param> internal StateCache(BugFindingRuntime runtime) { Runtime = runtime; Fingerprints = new HashSet <Fingerprint>(); }
/// <summary> /// Initializes the shared register. /// </summary> /// <param name="value">Initial value</param> /// <param name="Runtime">Runtime</param> public MockSharedRegister(T value, BugFindingRuntime Runtime) { this.Runtime = Runtime; registerMachine = Runtime.CreateMachine(typeof(SharedRegisterMachine <T>)); Runtime.SendEvent(registerMachine, SharedRegisterEvent.SetEvent(value)); }