Esempio n. 1
0
        private void DoRandomDPORAddRaces(Stack stack,
                                          int lastAccessIndex,
                                          int i,
                                          TidEntry 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.

            Contract.Assert(step.OpType == OperationType.Send);

            // Easy case (non-sends).
            if (step.OpType != OperationType.Send)
            {
                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 = TargetIdToFirstSend[step.TargetId];

            Contract.Assert(
                firstSend > 0,
                "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 = GetSelectedTidEntry(stack, j);
                if (entry.OpType != OperationType.Send ||
                    entry.Id == step.Id ||
                    HB(entry.Id, j, i))
                {
                    continue;
                }

                Races.Add(new Race(j, i));
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Utility method to show the selected thread.
        /// </summary>
        /// <param name="contract">IContract</param>
        public string ShowSelected(IContract contract)
        {
            int selectedIndex = TryGetSelected(contract);

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

            TidEntry selected  = List[selectedIndex];
            int      priorSend = selected.OpType == OperationType.Receive
                ? selected.SendStepIndex
                : -1;

            return($"({selected.Id}, {selected.OpType}, {selected.TargetType}, {selected.TargetId}, {priorSend})");
        }
Esempio n. 3
0
        private void AddBacktrack(Stack stack,
                                  bool doRandomDPOR,
                                  int lastAccessIndex,
                                  int i,
                                  TidEntry step)
        {
            var aTidEntries = GetThreadsAt(stack, lastAccessIndex);
            var a           = GetSelectedTidEntry(stack, lastAccessIndex);

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

            if (doRandomDPOR)
            {
                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 threads 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 candidateThreadIds = new HashSet <int>();

            if (aTidEntries.List.Count > step.Id &&
                (aTidEntries.List[step.Id].Enabled || aTidEntries.List[step.Id].OpType == OperationType.Yield))
            {
                candidateThreadIds.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 == OperationType.Yield))
                {
                    lookingFor.Add(j);
                }
            }

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

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

            // Make sure at least one candidate is found

            Contract.Assert(candidateThreadIds.Count > 0, "DPOR: There were no candidate backtrack points.");

            // Is one already backtracked?
            foreach (var tid in candidateThreadIds)
            {
                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 thread b.tid:
            {
                int sleptThread = step.Id;
                for (int k = 0; k < NumThreads; ++k)
                {
                    if (candidateThreadIds.Contains(sleptThread) &&
                        aTidEntries.List[sleptThread].Sleep)
                    {
                        aTidEntries.List[sleptThread].Backtrack = true;
                        return;
                    }
                    ++sleptThread;
                    if (sleptThread >= NumThreads)
                    {
                        sleptThread = 0;
                    }
                }
            }

            // None are slept.
            // Avoid picking threads that are disabled (due to yield hack)
            // Start from thread b.tid:
            {
                int backtrackThread = step.Id;
                for (int k = 0; k < NumThreads; ++k)
                {
                    if (candidateThreadIds.Contains(backtrackThread) &&
                        aTidEntries.List[backtrackThread].Enabled)
                    {
                        aTidEntries.List[backtrackThread].Backtrack = true;
                        return;
                    }
                    ++backtrackThread;
                    if (backtrackThread >= NumThreads)
                    {
                        backtrackThread = 0;
                    }
                }
            }

            // None are slept and enabled.
            // Start from thread b.tid:
            {
                int backtrackThread = step.Id;
                for (int k = 0; k < NumThreads; ++k)
                {
                    if (candidateThreadIds.Contains(backtrackThread))
                    {
                        aTidEntries.List[backtrackThread].Backtrack = true;
                        return;
                    }
                    ++backtrackThread;
                    if (backtrackThread >= NumThreads)
                    {
                        backtrackThread = 0;
                    }
                }
            }

            Contract.Assert(false, "DPOR: Did not manage to add backtrack point.");
        }
Esempio n. 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)
        {
            UpdateFieldsAndRealocateDatastructuresIfNeeded(stack);

            // Indexes start at 1.

            for (int i = 1; i < NumSteps; ++i)
            {
                TidEntry step = GetSelectedTidEntry(stack, i);
                if (ThreadIdToLastOpIndex[step.Id] > 0)
                {
                    FromVCSetVC(ThreadIdToLastOpIndex[step.Id], i);
                }
                else
                {
                    ClearVC(i);
                }
                ForVCSetClockToValue(i, step.Id, i);
                ThreadIdToLastOpIndex[step.Id] = i;

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

                if (targetId < 0)
                {
                    continue;
                }

                int lastAccessIndex = 0;

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

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

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

                case OperationType.WaitForQuiescence:
                    for (int j = 0; j < ThreadIdToLastOpIndex.Length; j++)
                    {
                        if (j == step.Id || ThreadIdToLastOpIndex[j] == 0)
                        {
                            continue;
                        }
                        ForVCJoinFromVC(i, ThreadIdToLastOpIndex[j]);
                    }
                    // Continue. No backtrack.
                    continue;

                case OperationType.Yield:
                    // Nothing.
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }


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

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

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