예제 #1
0
        /// <summary>
        /// Utility method to show the selected task.
        /// </summary>
        public string ShowSelected()
        {
            int selectedIndex = this.TryGetSelected();

            if (selectedIndex < 0)
            {
                return("-");
            }

            TaskEntry selected  = this.List[selectedIndex];
            int       priorSend = selected.OpType == AsyncOperationType.Receive
                ? selected.SendStepIndex
                : -1;

            return($"({selected.Id}, {selected.OpType}, {selected.OpTarget}, {selected.TargetId}, {priorSend})");
        }
예제 #2
0
        private void DoRandomDPORAddRaces(Stack stack, int lastAccessIndex, int i, TaskEntry step)
        {
            // Note: Only sends are reversible
            // so we will only get here if step.OpType is a send
            // so the if below is redundant.
            // But I am leaving this here in case we end up with more reversible types.
            // The following assert will then fail and more thought will be needed.
            // The if below is probably sufficient though, so the assert can probably just be removed.
            Debug.Assert(step.OpType == AsyncOperationType.Send, "DPOR: step.OpType != AsyncOperationType.Send");

            // Easy case (non-sends).
            if (step.OpType != AsyncOperationType.Send)
            {
                this.Races.Add(new Race(lastAccessIndex, i));
                return;
            }

            // Harder case (sends).

            // In random DPOR, we don't just want the last race;
            // we want all races.
            // In random DPOR, we don't join the VCs of sends,
            // so a send will potentially race with many prior sends to the
            // same mailbox.
            // We scan the stack looking for concurrent sends.
            // We only need to start scanning from the first send to this mailbox.
            int firstSend = this.TargetIdToFirstSend[step.TargetId];

            Debug.Assert(firstSend > 0, "DPOR: We should only get here if a send races with a prior send, but it does not.");

            for (int j = firstSend; j < i; j++)
            {
                var entry = GetSelectedTaskEntry(stack, j);
                if (entry.OpType != AsyncOperationType.Send ||
                    entry.Id == step.Id ||
                    this.HB(entry.Id, j, i))
                {
                    continue;
                }

                this.Races.Add(new Race(j, i));
            }
        }
예제 #3
0
        private void AddBacktrack(Stack stack, bool doRandomDPOR, int lastAccessIndex, int i, TaskEntry step)
        {
            var aTidEntries = GetTasksAt(stack, lastAccessIndex);
            var a           = GetSelectedTaskEntry(stack, lastAccessIndex);

            if (this.HB(a.Id, lastAccessIndex, i) || !Reversible(stack, lastAccessIndex, i))
            {
                return;
            }

            if (doRandomDPOR)
            {
                this.DoRandomDPORAddRaces(stack, lastAccessIndex, i, step);
                return;
            }

            // PSEUDOCODE: Find candidates.
            //  There is a race between `a` and `b`.
            //  Must find first steps after `a` that do not HA `a`
            //  (except maybe b.tid) and do not HA each other.
            // candidates = {}
            // if b.tid is enabled before a:
            //   add b.tid to candidates
            // lookingFor = set of enabled tasks before a - a.tid - b.tid.
            // let vc = [0,0,...]
            // vc[a.tid] = a;
            // for k = aIndex+1 to bIndex:
            //   if lookingFor does not contain k.tid:
            //     continue
            //   remove k.tid from lookingFor
            //   doesHaAnother = false
            //   foreach t in tids:
            //     if vc[t] hb k:
            //       doesHaAnother = true
            //       break
            //   vc[k.tid] = k
            //   if !doesHaAnother:
            //     add k.tid to candidates
            //   if lookingFor is empty:
            //     break
            var candidateTaskIds = new HashSet <int>();

            if (aTidEntries.List.Count > step.Id &&
                (aTidEntries.List[step.Id].Enabled || aTidEntries.List[step.Id].OpType == AsyncOperationType.Yield))
            {
                candidateTaskIds.Add(step.Id);
            }

            var lookingFor = new HashSet <int>();

            for (int j = 0; j < aTidEntries.List.Count; ++j)
            {
                if (j != a.Id &&
                    j != step.Id &&
                    (aTidEntries.List[j].Enabled || aTidEntries.List[j].OpType == AsyncOperationType.Yield))
                {
                    lookingFor.Add(j);
                }
            }

            int[] vc = new int[this.NumTasks];
            vc[a.Id] = lastAccessIndex;
            if (lookingFor.Count > 0)
            {
                for (int k = lastAccessIndex + 1; k < i; ++k)
                {
                    var kEntry = GetSelectedTaskEntry(stack, k);
                    if (!lookingFor.Contains(kEntry.Id))
                    {
                        continue;
                    }

                    lookingFor.Remove(kEntry.Id);
                    bool doesHaAnother = false;
                    for (int t = 0; t < this.NumTasks; ++t)
                    {
                        if (vc[t] > 0 &&
                            vc[t] <= this.ForVCGetClock(k, t))
                        {
                            doesHaAnother = true;
                            break;
                        }
                    }

                    if (!doesHaAnother)
                    {
                        candidateTaskIds.Add(kEntry.Id);
                    }

                    if (lookingFor.Count == 0)
                    {
                        break;
                    }
                }
            }

            // Make sure at least one candidate is found.
            Debug.Assert(candidateTaskIds.Count > 0, "DPOR: There were no candidate backtrack points.");

            // Is one already backtracked?
            foreach (var tid in candidateTaskIds)
            {
                if (aTidEntries.List[tid].Backtrack)
                {
                    return;
                }
            }

            {
                // None are backtracked, so we have to pick one.
                // Try to pick one that is slept first.
                // Start from task b.tid:
                int sleptTask = step.Id;
                for (int k = 0; k < this.NumTasks; ++k)
                {
                    if (candidateTaskIds.Contains(sleptTask) &&
                        aTidEntries.List[sleptTask].Sleep)
                    {
                        aTidEntries.List[sleptTask].Backtrack = true;
                        return;
                    }

                    ++sleptTask;
                    if (sleptTask >= this.NumTasks)
                    {
                        sleptTask = 0;
                    }
                }
            }

            {
                // None are slept.
                // Avoid picking tasks that are disabled (due to yield hack)
                // Start from task b.tid:
                int backtrackTask = step.Id;
                for (int k = 0; k < this.NumTasks; ++k)
                {
                    if (candidateTaskIds.Contains(backtrackTask) &&
                        aTidEntries.List[backtrackTask].Enabled)
                    {
                        aTidEntries.List[backtrackTask].Backtrack = true;
                        return;
                    }

                    ++backtrackTask;
                    if (backtrackTask >= this.NumTasks)
                    {
                        backtrackTask = 0;
                    }
                }
            }

            {
                // None are slept and enabled.
                // Start from task b.tid:
                int backtrackTask = step.Id;
                for (int k = 0; k < this.NumTasks; ++k)
                {
                    if (candidateTaskIds.Contains(backtrackTask))
                    {
                        aTidEntries.List[backtrackTask].Backtrack = true;
                        return;
                    }

                    ++backtrackTask;
                    if (backtrackTask >= this.NumTasks)
                    {
                        backtrackTask = 0;
                    }
                }
            }

            Debug.Assert(false, "DPOR: Did not manage to add backtrack point.");
        }
예제 #4
0
        /// <summary>
        /// The main entry point to the DPOR algorithm.
        /// </summary>
        /// <param name="stack">Should contain a terminal schedule.</param>
        /// <param name="rand">If non-null, then a randomized DPOR algorithm will be used.</param>
        public void DoDPOR(Stack stack, IRandomNumberGenerator rand)
        {
            this.UpdateFieldsAndRealocateDatastructuresIfNeeded(stack);

            // Indexes start at 1.
            for (int i = 1; i < this.NumSteps; ++i)
            {
                TaskEntry step = GetSelectedTaskEntry(stack, i);
                if (this.TaskIdToLastOpIndex[step.Id] > 0)
                {
                    this.FromVCSetVC(this.TaskIdToLastOpIndex[step.Id], i);
                }
                else
                {
                    this.ClearVC(i);
                }

                this.ForVCSetClockToValue(i, step.Id, i);
                this.TaskIdToLastOpIndex[step.Id] = i;

                int targetId = step.TargetId;
                if (step.OpType == AsyncOperationType.Create && i + 1 < this.NumSteps)
                {
                    targetId = GetTasksAt(stack, i).List.Count;
                }

                if (targetId < 0)
                {
                    continue;
                }

                int lastAccessIndex = 0;

                switch (step.OpType)
                {
                case AsyncOperationType.Start:
                case AsyncOperationType.Stop:
                case AsyncOperationType.Create:
                case AsyncOperationType.Join:
                {
                    lastAccessIndex =
                        this.TargetIdToLastCreateStartEnd[targetId];
                    this.TargetIdToLastCreateStartEnd[targetId] = i;
                    break;
                }

                case AsyncOperationType.Send:
                {
                    lastAccessIndex = this.TargetIdToLastSend[targetId];
                    this.TargetIdToLastSend[targetId] = i;
                    if (this.TargetIdToFirstSend[targetId] == 0)
                    {
                        this.TargetIdToFirstSend[targetId] = i;
                    }

                    break;
                }

                case AsyncOperationType.Receive:
                {
                    lastAccessIndex = step.SendStepIndex;
                    break;
                }

                case AsyncOperationType.WaitForQuiescence:
                    for (int j = 0; j < this.TaskIdToLastOpIndex.Length; j++)
                    {
                        if (j == step.Id || this.TaskIdToLastOpIndex[j] == 0)
                        {
                            continue;
                        }

                        this.ForVCJoinFromVC(i, this.TaskIdToLastOpIndex[j]);
                    }

                    // Continue. No backtrack.
                    continue;

                case AsyncOperationType.Yield:
                    // Nothing.
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                if (lastAccessIndex > 0)
                {
                    this.AddBacktrack(stack, rand != null, lastAccessIndex, i, step);

                    // Random DPOR skips joining for sends.
                    if (!(rand != null && step.OpType == AsyncOperationType.Send))
                    {
                        this.ForVCJoinFromVC(i, lastAccessIndex);
                    }
                }
            }

            if (rand != null)
            {
                this.DoRandomRaceReverse(stack, rand);
            }
        }