Пример #1
0
        /// <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);
        }
Пример #2
0
        /// <summary>
        ///   Handles the <paramref name="transitions" />, adding newly discovered states so that they are not visited again.
        /// </summary>
        private void HandleTransitions(TransitionCollection transitions, int sourceState, bool isInitial)
        {
            try
            {
                var transitionCount = 0;
                var stateCount      = 0;

                foreach (var modifier in _transitionModifiers)
                {
                    modifier.ModifyTransitions(_context, this, transitions, _context.States[sourceState], sourceState, isInitial);
                }

                _stateStack.PushFrame();

                foreach (var transition in transitions)
                {
                    int  targetState;
                    bool isNewState;

                    if (TransitionFlags.IsToStutteringState(((CandidateTransition *)transition)->Flags))
                    {
                        isNewState  = false;
                        targetState = _context.StutteringStateIndex;
                    }
                    else
                    {
                        isNewState = _context.States.AddState(((CandidateTransition *)transition)->TargetStatePointer, out targetState);
                    }

                    // Replace the CandidateTransition.TargetState pointer with the unique indexes of the transition's source and target states
                    transition->TargetStateIndex = targetState;
                    transition->SourceStateIndex = sourceState;
                    transition->Flags            = TransitionFlags.SetIsStateTransformedToIndexFlag(transition->Flags);

                    if (isNewState)
                    {
                        ++stateCount;
                        _stateStack.PushState(targetState);

                        foreach (var action in _stateActions)
                        {
                            action.ProcessState(_context, this, _context.States[targetState], targetState, isInitial);
                        }
                    }

                    foreach (var action in _transitionActions)
                    {
                        action.ProcessTransition(_context, this, transition, isInitial);
                    }

                    ++transitionCount;
                }

                Interlocked.Add(ref _context.StateCount, stateCount);
                Interlocked.Add(ref _context.TransitionCount, transitionCount);
                Interlocked.Add(ref _context.ComputedTransitionCount, transitions.TotalCount);

                foreach (var action in _batchedTransitionActions)
                {
                    action.ProcessTransitions(_context, this, sourceState, transitions, transitionCount, isInitial);
                }
            }
            catch (Exception e)
            {
                _context.LoadBalancer.Terminate();
                _context.Exception = e;

                if (!(e is OutOfMemoryException))
                {
                    CreateCounterExample(endsWithException: true, addAdditionalState: false);
                }
            }
        }