/// <summary> /// Initializes a new instance. /// </summary> /// <param name="createModel">Creates the model that should be checked.</param> /// <param name="output">The callback that should be used to output messages.</param> /// <param name="configuration">The analysis configuration that should be used.</param> internal ModelTraverser(AnalysisModelCreator createModel, AnalysisConfiguration configuration, int transitionSize, bool createStutteringState) { Requires.NotNull(createModel, nameof(createModel)); var stopwatch = new Stopwatch(); stopwatch.Start(); TransitionCollection.ValidateTransitionSizes(); var tasks = new Task[configuration.CpuCount]; var stacks = new StateStack[configuration.CpuCount]; _loadBalancer = new LoadBalancer(stacks); Context = new TraversalContext(_loadBalancer, configuration); _workers = new Worker[configuration.CpuCount]; for (var i = 0; i < configuration.CpuCount; ++i) { var index = i; tasks[i] = Task.Factory.StartNew(() => { stacks[index] = new StateStack(configuration.StackCapacity); _workers[index] = new Worker(index, Context, stacks[index], createModel.Create()); }); } Task.WaitAll(tasks); var firstModel = _workers[0].Model; if (transitionSize == DeriveTransitionSizeFromModel) { transitionSize = firstModel.TransitionSize; } if (configuration.WriteStateVectorLayout) { firstModel.WriteStateVectorLayout(configuration.DefaultTraceOutput); } var modelCapacity = configuration.ModelCapacity.DeriveModelByteSize(firstModel.ModelStateVectorSize, transitionSize); Context.ModelCapacity = modelCapacity; if (configuration.UseCompactStateStorage) { _states = new CompactStateStorage(modelCapacity.SizeOfState, modelCapacity.NumberOfStates); } else { _states = new SparseStateStorage(modelCapacity.SizeOfState, modelCapacity.NumberOfStates); } Context.States = _states; if (createStutteringState) { Context.StutteringStateIndex = _states.ReserveStateIndex(); } _initializationTime = stopwatch.Elapsed; stopwatch.Stop(); }
/// <summary> /// Splits the work between this instance and the <paramref name="other" /> instance. Returns <c>true</c> to indicate that /// work has been split; <c>false</c>, otherwise. /// </summary> /// <param name="other">The other instance the work should be split with.</param> public bool SplitWork(StateStack other) { Assert.That(CanSplit, "Cannot split the state stack."); Assert.That(other.FrameCount == 0, "Expected an empty state stack."); // We go through each frame and split the first frame with more than two states in half for (var i = 0; i < FrameCount; ++i) { other.PushFrame(); switch (_frames[i].Count) { // The stack is in an invalid state; clear the other worker's stack and let this worker // continue; it will clean up its stack and try to split work later case 0: other.Clear(); return(false); // We can't split work here, so just push the state to the other worker's stack case 1: other.PushState(_states[_frames[i].Offset]); break; // We've encountered a frame where we can actually split work; we always split work as early as possible, // that is, as low on the stack as possible, to hopefully maximize the amount of work passed to the other worker default: // Split the states of the frame var otherCount = _frames[i].Count / 2; var thisCount = _frames[i].Count - otherCount; // Add the first otherCount states to the other stack for (var j = 0; j < otherCount; ++j) { other.PushState(_states[_frames[i].Offset + j]); } // Adjust the count and offset of the frame _frames[i].Offset += otherCount; _frames[i].Count = thisCount; // Find the next splittable frame if this one no longer is if (thisCount == 1) { UpdateLowestSplittableFrame(); } return(true); } } // This stack could not be split, so we clear the other's stack and let some other worker try again other.Clear(); return(false); }
/// <summary> /// Initializes a new instance. /// </summary> /// <param name="index">The zero-based index of the worker.</param> /// <param name="context">The context the model is traversed in.</param> /// <param name="stateStack">The state stack that should be used by the worker.</param> /// <param name="model">The model that the worker should analyze.</param> public Worker(int index, TraversalContext <TExecutableModel> context, StateStack stateStack, AnalysisModel <TExecutableModel> model) { Requires.NotNull(context, nameof(context)); Requires.NotNull(stateStack, nameof(stateStack)); Requires.NotNull(model, nameof(model)); _index = index; _context = context; _stateStack = stateStack; Model = model; }
/// <summary> /// Initializes a new instance. /// </summary> /// <param name="createModel">Creates the model that should be checked.</param> /// <param name="output">The callback that should be used to output messages.</param> /// <param name="configuration">The analysis configuration that should be used.</param> internal ModelTraverser(AnalysisModelCreator <TExecutableModel> createModel, Action <string> output, AnalysisConfiguration configuration, int transitionSize) { Requires.NotNull(createModel, nameof(createModel)); Requires.NotNull(output, nameof(output)); var stopwatch = new Stopwatch(); stopwatch.Start(); TransitionCollection.ValidateTransitionSizes(); var tasks = new Task[configuration.CpuCount]; var stacks = new StateStack[configuration.CpuCount]; _loadBalancer = new LoadBalancer(stacks); Context = new TraversalContext <TExecutableModel>(_loadBalancer, configuration, output); _workers = new Worker <TExecutableModel> [configuration.CpuCount]; for (var i = 0; i < configuration.CpuCount; ++i) { var index = i; tasks[i] = Task.Factory.StartNew(() => { stacks[index] = new StateStack(configuration.StackCapacity); _workers[index] = new Worker <TExecutableModel>(index, Context, stacks[index], createModel.Create()); }); } Task.WaitAll(tasks); var firstModel = _workers[0].Model; if (transitionSize == DeriveTransitionSizeFromModel) { transitionSize = firstModel.TransitionSize; } var modelCapacity = configuration.ModelCapacity.DeriveModelByteSize(firstModel.StateVectorSize, transitionSize); Context.ModelCapacity = modelCapacity; _states = new StateStorage(modelCapacity.SizeOfState, modelCapacity.NumberOfStates); Context.States = _states; Context.StutteringStateIndex = _states.ReserveStateIndex(); _initializationTime = stopwatch.Elapsed; stopwatch.Stop(); }