void Request_profile_baseline(FunctionIDCollection functionIds, ThreadIDCollection threadIds, out Int32 hr)
        {
            var snapshot = NativeMethods.GetProfileWithRelease(out hr);

            Assert.GreaterOrEqual(hr, 0);
            Assert.IsNotNull(snapshot, "snapshot is null");
            Assert.Greater(snapshot.Length, 0, "snapshot.Length count is <= 0");

            foreach (var snap in snapshot)
            {
                //GetSnapshot will never return a null for the FunctionIDs
                Assert.IsNotNull(snap.FunctionIDs, "snapshot has a null list of function ids");

                Assert.AreNotEqual(snap.ThreadId, IntPtr.Zero, "ThreadId should be non-zero");
                if (snap.ThreadId != UIntPtr.Zero)
                {
                    threadIds?.Add(snap.ThreadId);
                }

                if (snap.ErrorCode < 0)
                {
                    Assert.AreEqual(snap.FunctionIDs.Length, 0, "non empty list of function ids was return with an error code.");
                }
                else
                {
                    Assert.AreNotEqual(snap.FunctionIDs.Length, 0, "empty list of function ids was return with an successful error code.");
                    functionIds?.AddRange(snap.FunctionIDs);
                }
            }
        }
        public void RequestProfile_VerifyThreadIDs()
        {
            //create a number of thread that recurses to a specified depth and block on a ManualResetEvent... this thread should save their threadids (GetCurrentExecutionEngineThreadId)
            //GetSnapshot on this thread
            //Set ManualResetEvent and allow the thread/task to complete/terminate
            //verify that all of the recurse thread ids are in the snapshot
            //call ShutdownThreadProfiler.
            using (var RecurseEvent = new ManualResetEventSlim(false))
            {
                const int ThreadsToCreate = 10;
                const int FramesPerThread = 1;
                int       threadsWaiting  = 0;

                var RecurseThreadIds = new ConcurrentBag <UIntPtr>();

                RecurseEvent.Reset();

                Thread[] threads = new Thread[ThreadsToCreate];

                for (int i = 0; i != threads.Length; ++i)
                {
                    threads[i] = new Thread(() => RecurseFunc(FramesPerThread, ref threadsWaiting, RecurseThreadIds, RecurseEvent), 4096 * 16)
                    {
                        IsBackground = true
                    };
                    threads[i].Start();
                }

                while (threadsWaiting != ThreadsToCreate)
                {
                    Thread.Yield();
                }

                var tidfidmap = new ThreadIDFunctionIDMap();
                Request_profile_baseline(tidfidmap, out Int32 hr);

                //free all of the recurse threads to terminate
                RecurseEvent.Set();
                for (int i = 0; i != threads.Length; ++i)
                {
                    threads[i].Join(); threads[i] = null;
                }

                CollectionAssert.IsSubsetOf(RecurseThreadIds, tidfidmap.Keys);

                var fids = new FunctionIDCollection();
                foreach (var pr in tidfidmap)
                {
                    fids.AddRange(pr.Value);
                }
                var FidTypeMethodNames = Request_function_names_baseline(fids);

                Assert.IsNotNull(FidTypeMethodNames);
                Assert.Greater(FidTypeMethodNames.Length, 0);

                foreach (var tid in RecurseThreadIds)
                {
                    int matchingMethods = 0;
                    foreach (var fid in tidfidmap[tid])
                    {
                        foreach (var ftm in FidTypeMethodNames)
                        {
                            if (ftm.FunctionID == fid)
                            {
                                if (ftm.MethodName.Equals("RecurseFunc"))
                                {
                                    ++matchingMethods;
                                }
                                break;
                            }
                        }
                    }
                    Assert.AreEqual(matchingMethods, FramesPerThread);
                }

                NativeMethods.ShutdownThreadProfiler();
            }
        }