Example #1
0
 private void DumpCallStacksCollected(ITestHeapStacks obj, HeapCollectStats heapStats, int nSizeSpecial)
 {
     foreach (var det in heapStats.details)
     {
         int    numStacks   = 0;
         IntPtr allocStacks = IntPtr.Zero;
         obj.GetCollectedAllocStacks(det.AllocSize, ref numStacks, ref allocStacks);
         for (int nStack = 0; nStack < numStacks; nStack++)
         {
             var collectedStack = Marshal.PtrToStructure <CollectedStack>(allocStacks + nStack * Marshal.SizeOf <CollectedStack>());
             LogMessage($"Num AllocStacks Collected for size {det.AllocSize}= {numStacks}  {collectedStack}");
             //The 1st time a stack is encountered, the stack is slightly diff because the code adds an new entry for the stack.
             // subsequent occurrences of the same stack don't need to add the entry, so they are a different stack.
             // Release builds have optimized C++ code, so the stacks are the same
             for (int iFrame = 0; iFrame < collectedStack.numFrames; iFrame++)
             {
                 var addr = Marshal.ReadIntPtr(collectedStack.pFrameArray + iFrame * IntPtr.Size);
                 LogMessage($"  {(uint)addr:x8}");
             }
             Marshal.FreeHGlobal(collectedStack.pFrameArray);
         }
         if (!heapStats.fReachedMemLimit && det.AllocSize == nSizeSpecial)
         {
             Assert.IsTrue(numStacks > 0, $"Expected > 0 stacks for {det}");
         }
         Marshal.FreeHGlobal(allocStacks);
     }
 }
Example #2
0
        async Task TestCollectStacksHelper(
            string strStacksToCollect,
            int nSizeSpecial,
            int NumFramesToCapture,
            int HeapAllocSizeMinValue,
            int StlAllocLimit,
            int nIter            = 10000,
            int nThreads         = 60,
            bool IsLimited       = false,
            bool WaitForDoCsLife = false)
        {
            using (var oInterop = new Interop())
            {
                var obj = GetTestHeapStacks(oInterop);
                obj.SetHeapCollectParams(strStacksToCollect, NumFramesToCapture, HeapAllocSizeMinValue, StlAllocLimit);
                obj.StartDetours(out var pDetours);
                var lstTasks = new List <Task>
                {
                    Task.Run(() => DoCSLife())
                };
                if (WaitForDoCsLife)
                {
                    await lstTasks[0];
                }
                var procHeap            = Heap.GetProcessHeap();
                var lstIntentionalLeaks = new List <IntPtr>();
                for (int iThread = 0; iThread < nThreads; iThread++)
                {
                    var task = Task.Run(() =>
                    {
                        DoSomeNativeAllocs(nIter, iThread, nSizeSpecial, lstIntentionalLeaks);
                    });
                    lstTasks.Add(task);
                }
                await Task.WhenAll(lstTasks);

                //                await Task.Delay(TimeSpan.FromSeconds(1)); // let things settle down before undetouring
                LogMessage($"Intentional Leaks {lstIntentionalLeaks.Count:n0}  TotAllocs={nIter * nThreads:n0}");
                obj.StopDetours(pDetours);
                //                await Task.Delay(TimeSpan.FromSeconds(1)); // let things settle down before undetouring
                var heapStats    = new HeapCollectStats(strStacksToCollect);
                var ptrHeapStats = heapStats.GetPointer();
                obj.GetStats(ptrHeapStats);

                heapStats = HeapCollectStats.FromPointer(ptrHeapStats);
                LogMessage($"Allocation stacks {heapStats}");
                Array.ForEach <HeapCollectStatDetail>(heapStats.details, (detail) =>
                {
                    LogMessage($"  {detail}");
                });
                Assert.IsTrue(heapStats.MyRtlAllocateHeapCount > nIter * nThreads, $"Expected > {nIter * nThreads}, got {heapStats.MyRtlAllocateHeapCount}");
                var det = heapStats.details.Where(s => s.AllocSize == nSizeSpecial).Single();
                if (IsLimited)
                {
                    Assert.IsTrue(heapStats.fReachedMemLimit, $"Test says limited memory, but didn't reach limit");
                }
                else
                {
                    Assert.IsFalse(heapStats.fReachedMemLimit, $"Test says not limited mem, but did reach limit");
                }
                if (!heapStats.fReachedMemLimit)
                {
                    Assert.IsTrue(det.NumStacksCollected >= nIter, $"Expected numstacks collected ({det.NumStacksCollected}) > {nIter}");
                }
                DumpCallStacksCollected(obj, heapStats, nSizeSpecial);

                foreach (var addr in lstIntentionalLeaks)
                {
                    Heap.HeapFree(procHeap, 0, addr);
                }
                heapStats.Dispose();
                obj.CollectStacksUninitialize();
                Marshal.FreeHGlobal(ptrHeapStats);
                Marshal.ReleaseComObject(obj);
                //                Assert.Fail($"#HeapAlloc={heapStats.MyRtlAllocateHeapCount}");
            }
        }
Example #3
0
        public void TestCollectStackAddresses()
        {
            int nSizeSpecial       = 1027;
            var strStacksToCollect = $"{nSizeSpecial}:0";

            using (var oInterop = new Interop())
            {
                var obj = GetTestHeapStacks(oInterop);
                obj.SetHeapCollectParams(strStacksToCollect, NumFramesToCapture: 20, HeapAllocSizeMinValue: 1048576, StlAllocLimit: 65536 * 10);
                obj.StartDetours(out var pDetours);
                int nIter               = 100;
                int nThreads            = 1;
                var lstIntentionalLeaks = new List <IntPtr>();
                for (int iThread = 0; iThread < nThreads; iThread++)
                {
                    DoSomeNativeAllocs(nIter, iThread, nSizeSpecial, lstIntentionalLeaks);
                }
                LogMessage($"Intentional Leaks {lstIntentionalLeaks.Count:n0}  TotAllocs={nIter * nThreads:n0}");
                var heapStats = new HeapCollectStats(strStacksToCollect);
                obj.StopDetours(pDetours);
                var ptrHeapStats = heapStats.GetPointer();
                obj.GetStats(ptrHeapStats);

                heapStats = HeapCollectStats.FromPointer(ptrHeapStats);
                LogMessage($"Allocation stacks {heapStats}");
                Array.ForEach <HeapCollectStatDetail>(heapStats.details, (detail) =>
                {
                    LogMessage($"  {detail}");
                });
                Assert.IsTrue(heapStats.MyRtlAllocateHeapCount > nIter * nThreads, $"Expected > {nIter * nThreads}, got {heapStats.MyRtlAllocateHeapCount}");
                if (!heapStats.fReachedMemLimit)
                {
                    var det = heapStats.details.Where(s => s.AllocSize == nSizeSpecial).Single();
                    Assert.IsTrue(det.NumStacksCollected >= nIter, $"Expected numstacks collected ({det.NumStacksCollected}) > {nIter}");
                }
                {
                    DumpCallStacksCollected(obj, heapStats, nSizeSpecial);
                }
                {
                    var    lstLiveAllocs = new List <LiveHeapAllocation>();
                    int    numAllocs     = 0;
                    IntPtr ptrData       = IntPtr.Zero;
                    obj.GetAllocationAddresses(ref numAllocs, ref ptrData);
                    LogMessage($"# LiveAllocStacks (allocs that are still live)= {numAllocs}");
                    for (int i = 0; i < numAllocs; i++)
                    {
                        var allocdata = Marshal.PtrToStructure <LiveHeapAllocation>(ptrData + i * IntPtr.Size);
                        var str       = "Freed";
                        if (lstIntentionalLeaks.Contains(allocdata.addr))
                        {
                            str = Marshal.PtrToStringAnsi(allocdata.addr);
                            Assert.IsTrue(str.StartsWith("This is a test string"));
                        }
                        LogMessage($" {i}  addr={(uint)(allocdata.addr):x8} stackhash={allocdata.stackhash:x8} str={str}");
                    }
                    Marshal.FreeHGlobal(ptrData);
                }

                foreach (var addr in lstIntentionalLeaks)
                {
                    Heap.HeapFree(Heap.GetProcessHeap(), 0, addr);
                }
                heapStats.Dispose();
                obj.CollectStacksUninitialize();
                Marshal.FreeHGlobal(ptrHeapStats);
                Marshal.ReleaseComObject(obj);
                //                Assert.Fail($"#HeapAlloc={heapStats.MyRtlAllocateHeapCount}");
            }
        }