Remove outdated GC perf test framework (#20673)
authorSung Yoon Whang <suwhang@microsoft.com>
Mon, 29 Oct 2018 22:04:56 +0000 (15:04 -0700)
committerGitHub <noreply@github.com>
Mon, 29 Oct 2018 22:04:56 +0000 (15:04 -0700)
16 files changed:
tests/src/GC/Performance/Framework/GCPerfTestFramework.csproj [deleted file]
tests/src/GC/Performance/Framework/GCPerfTestFramework.sln [deleted file]
tests/src/GC/Performance/Framework/Metrics/Builders/CircularBuffer.cs [deleted file]
tests/src/GC/Performance/Framework/Metrics/Builders/CondemnedReasonGroup.cs [deleted file]
tests/src/GC/Performance/Framework/Metrics/Builders/DictionaryExtensions.cs [deleted file]
tests/src/GC/Performance/Framework/Metrics/Builders/GCEvent.cs [deleted file]
tests/src/GC/Performance/Framework/Metrics/Builders/GCInfo.cs [deleted file]
tests/src/GC/Performance/Framework/Metrics/Builders/GCProcess.cs [deleted file]
tests/src/GC/Performance/Framework/Metrics/Builders/ThreadWorkSpan.cs [deleted file]
tests/src/GC/Performance/Framework/Metrics/CollectGCMetricsAttribute.cs [deleted file]
tests/src/GC/Performance/Framework/Metrics/GCMetricDiscoverer.cs [deleted file]
tests/src/GC/Performance/Framework/Metrics/GCMetrics.cs [deleted file]
tests/src/GC/Performance/Framework/PerfTests.cs [deleted file]
tests/src/GC/Performance/Framework/ProcessFactory.cs [deleted file]
tests/src/GC/Performance/Framework/packages.config [deleted file]
tests/src/GC/Performance/README.md [deleted file]

diff --git a/tests/src/GC/Performance/Framework/GCPerfTestFramework.csproj b/tests/src/GC/Performance/Framework/GCPerfTestFramework.csproj
deleted file mode 100644 (file)
index 81c380e..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
-  <PropertyGroup>
-    <DisableProjectBuild>true</DisableProjectBuild>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">x64</Platform>
-    <ProjectGuid>{07501894-7A01-4A0D-B9A2-3C72799A68BA}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <RootNamespace>GCPerfTestFramework</RootNamespace>
-    <AssemblyName>GCPerfTestFramework</AssemblyName>
-    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
-    <TargetFrameworkProfile />
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>TRACE;DEBUG;WINDOWS</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE;WINDOWS</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <PlatformTarget>x64</PlatformTarget>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="Microsoft.Diagnostics.Tracing.TraceEvent, Version=1.0.41.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\lib\net40\Microsoft.Diagnostics.Tracing.TraceEvent.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.ComponentModel.Composition" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.IO.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>packages\System.IO.FileSystem.4.0.0\lib\net46\System.IO.FileSystem.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="System.IO.FileSystem.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>packages\System.IO.FileSystem.Primitives.4.0.0\lib\net46\System.IO.FileSystem.Primitives.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Xml" />
-    <Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
-      <HintPath>packages\Microsoft.DotNet.xunit.performance.metrics.1.0.0-alpha-build0040\lib\net46\xunit.abstractions.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="xunit.core, Version=2.2.0.3300, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
-      <HintPath>packages\xunit.extensibility.core.2.2.0-beta2-build3300\lib\netstandard1.0\xunit.core.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="xunit.execution.desktop, Version=2.2.0.3300, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
-      <HintPath>packages\xunit.extensibility.execution.2.2.0-beta2-build3300\lib\net45\xunit.execution.desktop.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="xunit.performance.core, Version=1.0.0.40, Culture=neutral, PublicKeyToken=67066efe964d3b03, processorArchitecture=MSIL">
-      <HintPath>packages\Microsoft.DotNet.xunit.performance.metrics.1.0.0-alpha-build0040\lib\net46\xunit.performance.core.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="xunit.performance.execution.desktop, Version=1.0.0.40, Culture=neutral, PublicKeyToken=67066efe964d3b03, processorArchitecture=MSIL">
-      <HintPath>packages\Microsoft.DotNet.xunit.performance.1.0.0-alpha-build0040\lib\net46\xunit.performance.execution.desktop.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="xunit.performance.metrics, Version=1.0.0.40, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>packages\Microsoft.DotNet.xunit.performance.metrics.1.0.0-alpha-build0040\lib\net46\xunit.performance.metrics.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="PerfTests.cs" />
-    <Compile Include="ProcessFactory.cs" />
-    <Compile Include="Metrics\CollectGCMetricsAttribute.cs" />
-    <Compile Include="Metrics\GCMetricDiscoverer.cs" />
-    <Compile Include="Metrics\GCMetrics.cs" />
-    <Compile Include="Metrics\Builders\CircularBuffer.cs" />
-    <Compile Include="Metrics\Builders\CondemnedReasonGroup.cs" />
-    <Compile Include="Metrics\Builders\DictionaryExtensions.cs" />
-    <Compile Include="Metrics\Builders\GCEvent.cs" />
-    <Compile Include="Metrics\Builders\GCInfo.cs" />
-    <Compile Include="Metrics\Builders\GCProcess.cs" />
-    <Compile Include="Metrics\Builders\ThreadWorkSpan.cs" />
-    <None Include="..\..\..\NuGet.config" />
-  </ItemGroup>
-  <ItemGroup>
-    <Folder Include="Properties\" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <Import Project="packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets" Condition="Exists('packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets')" />
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets'))" />
-  </Target>
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>
\ No newline at end of file
diff --git a/tests/src/GC/Performance/Framework/GCPerfTestFramework.sln b/tests/src/GC/Performance/Framework/GCPerfTestFramework.sln
deleted file mode 100644 (file)
index fcbeef5..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.24912.0
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GCPerfTestFramework", "GCPerfTestFramework.csproj", "{07501894-7A01-4A0D-B9A2-3C72799A68BA}"
-EndProject
-Global
-       GlobalSection(SolutionConfigurationPlatforms) = preSolution
-               Debug|Any CPU = Debug|Any CPU
-               Release|Any CPU = Release|Any CPU
-       EndGlobalSection
-       GlobalSection(ProjectConfigurationPlatforms) = postSolution
-               {07501894-7A01-4A0D-B9A2-3C72799A68BA}.Debug|Any CPU.ActiveCfg = Debug|x64
-               {07501894-7A01-4A0D-B9A2-3C72799A68BA}.Debug|Any CPU.Build.0 = Debug|x64
-               {07501894-7A01-4A0D-B9A2-3C72799A68BA}.Release|Any CPU.ActiveCfg = Release|x64
-               {07501894-7A01-4A0D-B9A2-3C72799A68BA}.Release|Any CPU.Build.0 = Release|x64
-       EndGlobalSection
-       GlobalSection(SolutionProperties) = preSolution
-               HideSolutionNode = FALSE
-       EndGlobalSection
-EndGlobal
diff --git a/tests/src/GC/Performance/Framework/Metrics/Builders/CircularBuffer.cs b/tests/src/GC/Performance/Framework/Metrics/Builders/CircularBuffer.cs
deleted file mode 100644 (file)
index d5e27d9..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-
-namespace GCPerfTestFramework.Metrics.Builders
-{
-    internal class CircularBuffer<T> : IEnumerable<T>
-        where T : class
-    {
-        private int StartIndex, AfterEndIndex, Size;
-        private T[] Items;
-        public CircularBuffer(int size)
-        {
-            if (size < 1)
-                throw new ArgumentException("size");
-
-            StartIndex = 0;
-            AfterEndIndex = 0;
-            Size = size + 1;
-            Items = new T[Size];
-        }
-
-        public void Add(T item)
-        {
-            if (Next(AfterEndIndex) == StartIndex)
-            {
-                Items[StartIndex] = null;
-                StartIndex = Next(StartIndex);
-            }
-            Items[AfterEndIndex] = item;
-            AfterEndIndex = Next(AfterEndIndex);
-        }
-
-        private int Next(int i)
-        {
-            return (i == Size - 1) ? 0 : i + 1;
-        }
-
-        public IEnumerator<T> GetEnumerator()
-        {
-            for (int i = StartIndex; i != AfterEndIndex; i = Next(i))
-            {
-                yield return Items[i];
-            }
-        }
-
-        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
-        {
-            return GetEnumerator();
-        }
-    }
-}
diff --git a/tests/src/GC/Performance/Framework/Metrics/Builders/CondemnedReasonGroup.cs b/tests/src/GC/Performance/Framework/Metrics/Builders/CondemnedReasonGroup.cs
deleted file mode 100644 (file)
index 7e31d0b..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace GCPerfTestFramework.Metrics.Builders
-{
-    // Condemned reasons are organized into the following groups.
-    // Each group corresponds to one or more reasons. 
-    // Groups are organized in the way that they mean something to users. 
-    internal enum CondemnedReasonGroup
-    {
-        // The first 4 will have values of a number which is the generation.
-        // Note that right now these 4 have the exact same value as what's in
-        // Condemned_Reason_Generation.
-        CRG_Initial_Generation = 0,
-        CRG_Final_Generation = 1,
-        CRG_Alloc_Exceeded = 2,
-        CRG_Time_Tuning = 3,
-
-        // The following are either true(1) or false(0). They are not 
-        // a 1:1 mapping from 
-        CRG_Induced = 4,
-        CRG_Low_Ephemeral = 5,
-        CRG_Expand_Heap = 6,
-        CRG_Fragmented_Ephemeral = 7,
-        CRG_Fragmented_Gen1_To_Gen2 = 8,
-        CRG_Fragmented_Gen2 = 9,
-        CRG_Fragmented_Gen2_High_Mem = 10,
-        CRG_GC_Before_OOM = 11,
-        CRG_Too_Small_For_BGC = 12,
-        CRG_Ephemeral_Before_BGC = 13,
-        CRG_Internal_Tuning = 14,
-        CRG_Max = 15,
-    }
-
-}
diff --git a/tests/src/GC/Performance/Framework/Metrics/Builders/DictionaryExtensions.cs b/tests/src/GC/Performance/Framework/Metrics/Builders/DictionaryExtensions.cs
deleted file mode 100644 (file)
index 2ed31ad..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-
-namespace GCPerfTestFramework.Metrics.Builders
-{
-    internal static class DictionaryExtensions
-    {
-        public static V GetOrCreate<K, V>(this IDictionary<K, V> dict, K key) where V : new()
-        {
-            V value;
-            if (dict.TryGetValue(key, out value))
-            {
-                return value;
-            }
-
-            value = new V();
-            dict[key] = value;
-            return value;
-        }
-    }
-}
diff --git a/tests/src/GC/Performance/Framework/Metrics/Builders/GCEvent.cs b/tests/src/GC/Performance/Framework/Metrics/Builders/GCEvent.cs
deleted file mode 100644 (file)
index 61ca074..0000000
+++ /dev/null
@@ -1,1446 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if WINDOWS
-
-using Microsoft.Diagnostics.Tracing.Parsers.Clr;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-
-namespace GCPerfTestFramework.Metrics.Builders
-{
-    internal class GCEvent
-    {
-        #region Public Fields
-        //  Time it takes to do the suspension. Before 4.0 we didn't have a SuspendEnd event so we calculate it by just 
-        // substracting GC duration from pause duration. For concurrent GC this would be inaccurate so we just return 0.
-        public double _SuspendDurationMSec;
-
-        public double[] AllocedSinceLastGCBasedOnAllocTickMB = { 0.0, 0.0 };
-        public long duplicatedPinningReports;
-        public double DurationSinceLastRestartMSec;
-        // The amount of CPU time this GC consumed.
-        public float GCCpuMSec;
-
-        public float[] GCCpuServerGCThreads = null;
-        public double GCDurationMSec;
-        public int GCGeneration;
-        // Primary fields (set in the callbacks)
-        public int GCNumber;
-
-        public double GCStartRelativeMSec;
-        public GCGlobalHeapHistoryTraceData GlobalHeapHistory;
-        public bool HasAllocTickEvents = false;
-        public GCHeapStatsTraceData HeapStats;
-        public int Index;
-        // In 2.0 we didn't have all the events. I try to keep the code not version specific and this is really
-        // for debugging/verification purpose.
-        public bool is20Event;
-
-        // Did we get the complete event sequence for this GC?
-        // For BGC this is the HeapStats event; for other GCs this means you have both the HeapStats and RestartEEEnd event.
-        public bool isComplete;
-
-        //  Set in Start, does not include suspension.  
-        //  Set in Stop This is JUST the GC time (not including suspension) That is Stop-Start.  
-        // This only applies to 2.0. I could just set the type to Background GC but I'd rather not disturb
-        // the code that handles background GC.
-        public bool isConcurrentGC;
-
-        public GCProcess Parent;                //process that did that GC
-        public double PauseDurationMSec;
-
-        public double PauseStartRelativeMSec;
-
-        public List<GCPerHeapHistoryTraceData> PerHeapHistories;
-
-        // The dictionary of heap number and info on time it takes to mark various roots.
-        public Dictionary<int, MarkInfo> PerHeapMarkTimes;
-
-        public Dictionary<ulong, long> PinnedObjects = new Dictionary<ulong, long>();
-
-        public List<PinnedPlug> PinnedPlugs = new List<PinnedPlug>();
-
-        // For background GC we need to remember when the GC before it ended because
-        // when we get the GCStop event some foreground GCs may have happened.
-        public float ProcessCpuAtLastGC;
-
-        //  Total time EE is suspended (can be less than GC time for background)
-        // The amount of CPU time the process consumed since the last GC.
-        public float ProcessCpuMSec;
-
-        public GCReason Reason;
-
-        public long totalPinnedPlugSize;
-
-        public long totalUserPinnedPlugSize;
-
-        //  Set in GCStop(Generation 0, 1 or 2)
-        public GCType Type;
-
-        private GCCondemnedReasons[] _PerHeapCondemnedReasons;
-
-        private GCPerHeapHistoryGenData[][] _PerHeapGenData;
-
-        #endregion
-
-        #region Private Fields
-        //  Set in GCStart
-        private double _TotalGCTimeMSec = -1;
-
-        //  Set in GCStart
-        // When we are using Server GC we store the CPU spent on each thread
-        // so we can see if there's an imbalance. We concurrently don't do this
-        // for server background GC as the imbalance there is much less important.
-        int heapCount = -1;
-
-        private long pinnedObjectSizes;
-
-        //  Set in GCStart
-        //  Set in GCStart
-        //list of workload histories per server GC heap
-        private List<ServerGcHistory> ServerGcHeapHistories = new List<ServerGcHistory>();
-
-        private PerHeapEventVersion Version = PerHeapEventVersion.V0;
-        #endregion
-
-        #region Constructors
-        public GCEvent(GCProcess owningProcess)
-        {
-            Parent = owningProcess;
-            heapCount = owningProcess.heapCount;
-
-            if (heapCount > 1)
-            {
-                GCCpuServerGCThreads = new float[heapCount];
-            }
-
-            pinnedObjectSizes = -1;
-            totalPinnedPlugSize = -1;
-            totalUserPinnedPlugSize = -1;
-            duplicatedPinningReports = 0;
-        }
-
-        #endregion
-
-        #region Private Enums
-        private enum InducedType
-        {
-            Blocking = 1,
-            NotForced = 2,
-        }
-
-        // TODO: get rid of the remaining version checking here - convert the leftover checks with using the Has* methods 
-        // to determine whether that particular data is available.
-        private enum PerHeapEventVersion
-        {
-            V0, // Not set
-            V4_0,
-            V4_5,
-            V4_6,
-        }
-
-        #endregion
-
-        #region Public Properties
-        public double AllocedSinceLastGCMB
-        {
-            get
-            {
-                return GetUserAllocated(Gens.Gen0) + GetUserAllocated(Gens.GenLargeObj);
-            }
-        }
-
-        public double AllocRateMBSec { get { return AllocedSinceLastGCMB * 1000.0 / DurationSinceLastRestartMSec; } }
-
-        public double CondemnedMB
-        {
-            get
-            {
-                double ret = GenSizeBeforeMB(0);
-                if (1 <= GCGeneration)
-                    ret += GenSizeBeforeMB(Gens.Gen1);
-                if (2 <= GCGeneration)
-                    ret += GenSizeBeforeMB(Gens.Gen2) + GenSizeBeforeMB(Gens.GenLargeObj);
-                return ret;
-            }
-        }
-
-        // Index into the list of GC events
-        // The list that contains this event
-        private List<GCEvent> Events
-        {
-            get
-            {
-                return Parent.Events.OfType<GCEvent>().ToList();
-            }
-        }
-
-        public double FragmentationMB
-        {
-            get
-            {
-                double ret = 0;
-                for (Gens gen = Gens.Gen0; gen <= Gens.GenLargeObj; gen++)
-                    ret += GenFragmentationMB(gen);
-                return ret;
-            }
-        }
-
-        public int Generation => GCNumber;
-
-        public bool HasServerGcThreadingInfo
-        {
-            get
-            {
-                foreach (var heap in ServerGcHeapHistories)
-                {
-                    if (heap.SampleSpans.Count > 0 || heap.SwitchSpans.Count > 0)
-                        return true;
-                }
-                return false;
-            }
-        }
-
-        /// <summary>
-        /// This include fragmentation
-        /// </summary>
-        public double HeapSizeAfterMB
-        {
-            get
-            {
-                if (null != HeapStats)
-                {
-                    return (HeapStats.GenerationSize0 + HeapStats.GenerationSize1 + HeapStats.GenerationSize2 + HeapStats.GenerationSize3) / 1000000.0;
-                }
-                else
-                {
-                    return -1.0;
-                }
-            }
-        }
-
-        public double HeapSizeBeforeMB
-        {
-            get
-            {
-                double ret = 0;
-                for (Gens gen = Gens.Gen0; gen <= Gens.GenLargeObj; gen++)
-                    ret += GenSizeBeforeMB(gen);
-                return ret;
-            }
-        }
-
-        public double HeapSizePeakMB
-        {
-            get
-            {
-                var ret = HeapSizeBeforeMB;
-                if (Type == GCType.BackgroundGC)
-                {
-                    var BgGcEndedRelativeMSec = PauseStartRelativeMSec + GCDurationMSec;
-                    for (int i = Index + 1; i < Events.Count; i++)
-                    {
-                        var _event = Events[i];
-                        if (BgGcEndedRelativeMSec < _event.PauseStartRelativeMSec)
-                            break;
-                        ret = Math.Max(ret, _event.HeapSizeBeforeMB);
-                    }
-                }
-                return ret;
-            }
-        }
-
-        //  Set in GCStart (starts at 1, unique for process)
-        // Of all the CPU, how much as a percentage is spent in the GC since end of last GC.
-        public double PercentTimeInGC { get { return (GetTotalGCTime() * 100 / ProcessCpuMSec); } }
-        public double PromotedMB
-        {
-            get
-            {
-                return (HeapStats.TotalPromotedSize0 + HeapStats.TotalPromotedSize1 +
-                       HeapStats.TotalPromotedSize2 + HeapStats.TotalPromotedSize3) / 1000000.0;
-            }
-        }
-
-        public double RatioPeakAfter { get { if (HeapSizeAfterMB == 0) return 0; return HeapSizePeakMB / HeapSizeAfterMB; } }
-
-        private GCCondemnedReasons[] PerHeapCondemnedReasons
-        {
-            get
-            {
-                if ((PerHeapHistories != null) && (_PerHeapCondemnedReasons == null))
-                {
-                    GetVersion();
-
-                    int NumHeaps = PerHeapHistories.Count;
-                    _PerHeapCondemnedReasons = new GCCondemnedReasons[NumHeaps];
-
-                    for (int HeapIndex = 0; HeapIndex < NumHeaps; HeapIndex++)
-                    {
-                        _PerHeapCondemnedReasons[HeapIndex] = new GCCondemnedReasons();
-                        _PerHeapCondemnedReasons[HeapIndex].EncodedReasons.Reasons = PerHeapHistories[HeapIndex].CondemnReasons0;
-                        if (Version != PerHeapEventVersion.V4_0)
-                        {
-                            _PerHeapCondemnedReasons[HeapIndex].EncodedReasons.ReasonsEx = PerHeapHistories[HeapIndex].CondemnReasons1;
-                        }
-                        _PerHeapCondemnedReasons[HeapIndex].CondemnedReasonGroups = new byte[(int)CondemnedReasonGroup.CRG_Max];
-                        _PerHeapCondemnedReasons[HeapIndex].Decode(Version);
-                    }
-                }
-
-                return _PerHeapCondemnedReasons;
-            }
-        }
-
-        // There's a list of things we need to get from the events we collected. 
-        // To increase the efficiency so we don't need to go back to TraceEvent
-        // too often we construct the generation data all at once here.
-        private GCPerHeapHistoryGenData[][] PerHeapGenData
-        {
-            get
-            {
-                if ((PerHeapHistories != null) && (_PerHeapGenData == null))
-                {
-                    GetVersion();
-
-                    int NumHeaps = PerHeapHistories.Count;
-                    _PerHeapGenData = new GCPerHeapHistoryGenData[NumHeaps][];
-                    for (int HeapIndex = 0; HeapIndex < NumHeaps; HeapIndex++)
-                    {
-                        _PerHeapGenData[HeapIndex] = new GCPerHeapHistoryGenData[(int)Gens.GenLargeObj + 1];
-                        for (Gens GenIndex = Gens.Gen0; GenIndex <= Gens.GenLargeObj; GenIndex++)
-                        {
-                            _PerHeapGenData[HeapIndex][(int)GenIndex] = PerHeapHistories[HeapIndex].GenData(GenIndex);
-                        }
-                    }
-                }
-
-                return _PerHeapGenData;
-            }
-        }
-
-        #endregion
-
-        #region Public Methods
-        public void AddLOHWaitThreadInfo(int TID, double time, int reason, bool IsStart)
-        {
-#if HAS_PRIVATE_GC_EVENTS
-            BGCAllocWaitReason ReasonLOHAlloc = (BGCAllocWaitReason)reason;
-
-            if ((ReasonLOHAlloc == BGCAllocWaitReason.GetLOHSeg) ||
-                (ReasonLOHAlloc == BGCAllocWaitReason.AllocDuringSweep))
-            {
-                if (LOHWaitThreads == null)
-                {
-                    LOHWaitThreads = new Dictionary<int, BGCAllocWaitInfo>();
-                }
-
-                BGCAllocWaitInfo info;
-
-                if (LOHWaitThreads.TryGetValue(TID, out info))
-                {
-                    if (IsStart)
-                    {
-                        // If we are finding the value it means we are hitting the small
-                        // window where BGC sweep finished and BGC itself finished, discard
-                        // this.
-                    }
-                    else
-                    {
-                        Debug.Assert(info.Reason == ReasonLOHAlloc);
-                        info.WaitStopRelativeMSec = time;
-                    }
-                }
-                else
-                {
-                    info = new BGCAllocWaitInfo();
-                    if (IsStart)
-                    {
-                        info.Reason = ReasonLOHAlloc;
-                        info.WaitStartRelativeMSec = time;
-                    }
-                    else
-                    {
-                        // We are currently not displaying this because it's incomplete but I am still adding 
-                        // it so we could display if we want to.
-                        info.WaitStopRelativeMSec = time;
-                    }
-
-                    LOHWaitThreads.Add(TID, info);
-                }
-            }
-#endif
-        }
-
-        public void AddServerGcSample(ThreadWorkSpan sample)
-        {
-            if (sample.ProcessorNumber >= 0 && sample.ProcessorNumber < ServerGcHeapHistories.Count)
-                ServerGcHeapHistories[sample.ProcessorNumber].AddSampleEvent(sample);
-        }
-
-        public void AddServerGcThreadSwitch(ThreadWorkSpan cswitch)
-        {
-            if (cswitch.ProcessorNumber >= 0 && cswitch.ProcessorNumber < ServerGcHeapHistories.Count)
-                ServerGcHeapHistories[cswitch.ProcessorNumber].AddSwitchEvent(cswitch);
-        }
-
-        public void AddServerGCThreadTime(int heapIndex, float cpuMSec)
-        {
-            if (GCCpuServerGCThreads != null)
-                GCCpuServerGCThreads[heapIndex] += cpuMSec;
-        }
-
-        // Unfortunately sometimes we just don't get mark events from all heaps, even for GCs that we have seen GCStart for.
-        // So accommodating this scenario.
-        public bool AllHeapsSeenMark()
-        {
-            if (PerHeapMarkTimes != null)
-                return (heapCount == PerHeapMarkTimes.Count);
-            else
-                return false;
-        }
-
-        public bool DetailedGenDataAvailable()
-        {
-            return (PerHeapHistories != null);
-        }
-
-        public void GCEnd()
-        {
-            ConvertMarkTimes();
-
-            if (ServerGcHeapHistories != null)
-            {
-                foreach (var serverHeap in ServerGcHeapHistories)
-                {
-                    serverHeap.GCEnd();
-                }
-            }
-        }
-
-        public double GenBudgetMB(Gens gen)
-        {
-            if (PerHeapHistories == null)
-                return double.NaN;
-            double budget = 0.0;
-            for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-                budget += PerHeapGenData[HeapIndex][(int)gen].Budget / 1000000.0;
-            return budget;
-        }
-
-        public double GenFragmentationMB(Gens gen)
-        {
-            if (PerHeapHistories == null)
-                return double.NaN;
-            double ret = 0.0;
-            for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-                ret += PerHeapGenData[HeapIndex][(int)gen].Fragmentation / 1000000.0;
-            return ret;
-        }
-
-        public double GenFragmentationPercent(Gens gen)
-        {
-            return (GenFragmentationMB(gen) * 100.0 / GenSizeAfterMB(gen));
-        }
-
-        public double GenFreeListAfter(Gens gen)
-        {
-            if (PerHeapHistories == null)
-                return double.NaN;
-            double ret = 0.0;
-            for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-                ret += PerHeapGenData[HeapIndex][(int)gen].FreeListSpaceAfter;
-            return ret;
-        }
-
-        public double GenFreeListBefore(Gens gen)
-        {
-            if (PerHeapHistories == null)
-                return double.NaN;
-            double ret = 0.0;
-            for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-                ret += PerHeapGenData[HeapIndex][(int)gen].FreeListSpaceBefore;
-            return ret;
-        }
-
-        public double GenInMB(Gens gen)
-        {
-            if (PerHeapHistories == null)
-                return double.NaN;
-            double ret = 0.0;
-            for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-                ret += PerHeapGenData[HeapIndex][(int)gen].In / 1000000.0;
-            return ret;
-        }
-
-        public double GenNonePinnedSurv(Gens gen)
-        {
-            if ((PerHeapHistories == null) || !(PerHeapGenData[0][0].HasNonePinnedSurv()))
-                return double.NaN;
-            double ret = 0.0;
-            for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-                ret += PerHeapGenData[HeapIndex][(int)gen].NonePinnedSurv;
-            return ret;
-        }
-
-        public double GenOut(Gens gen)
-        {
-            if (PerHeapHistories == null)
-                return double.NaN;
-            double ret = 0.0;
-            for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-                ret += PerHeapGenData[HeapIndex][(int)gen].Out;
-            return ret;
-        }
-
-        public double GenOutMB(Gens gen)
-        {
-            if (PerHeapHistories == null)
-                return double.NaN;
-            double ret = 0.0;
-            for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-                ret += PerHeapGenData[HeapIndex][(int)gen].Out / 1000000.0;
-            return ret;
-        }
-
-        public double GenPinnedSurv(Gens gen)
-        {
-            if ((PerHeapHistories == null) || !(PerHeapGenData[0][0].HasPinnedSurv()))
-                return double.NaN;
-            double ret = 0.0;
-            for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-                ret += PerHeapGenData[HeapIndex][(int)gen].PinnedSurv;
-            return ret;
-        }
-
-        // Note that in 4.0 TotalPromotedSize is not entirely accurate (since it doesn't
-        // count the pins that got demoted. We could consider using the PerHeap event data
-        // to compute the accurate promoted size. 
-        // In 4.5 this is accurate.
-        public double GenPromotedMB(Gens gen)
-        {
-            if (gen == Gens.GenLargeObj)
-                return HeapStats.TotalPromotedSize3 / 1000000.0;
-            if (gen == Gens.Gen2)
-                return HeapStats.TotalPromotedSize2 / 1000000.0;
-            if (gen == Gens.Gen1)
-                return HeapStats.TotalPromotedSize1 / 1000000.0;
-            if (gen == Gens.Gen0)
-                return HeapStats.TotalPromotedSize0 / 1000000.0;
-            Debug.Assert(false);
-            return double.NaN;
-        }
-
-        public double GenSizeAfterMB(Gens gen)
-        {
-            if (gen == Gens.GenLargeObj)
-                return HeapStats.GenerationSize3 / 1000000.0;
-            if (gen == Gens.Gen2)
-                return HeapStats.GenerationSize2 / 1000000.0;
-            if (gen == Gens.Gen1)
-                return HeapStats.GenerationSize1 / 1000000.0;
-            if (gen == Gens.Gen0)
-                return HeapStats.GenerationSize0 / 1000000.0;
-            Debug.Assert(false);
-            return double.NaN;
-        }
-
-        // Per generation stats.  
-        public double GenSizeBeforeMB(Gens gen)
-        {
-            if (PerHeapHistories != null)
-            {
-                double ret = 0.0;
-                for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-                    ret += PerHeapGenData[HeapIndex][(int)gen].SizeBefore / 1000000.0;
-                return ret;
-            }
-
-            // When we don't have perheap history we can only estimate for gen0 and gen3.
-            double Gen0SizeBeforeMB = 0;
-            if (gen == Gens.Gen0)
-                Gen0SizeBeforeMB = AllocedSinceLastGCBasedOnAllocTickMB[0];
-            if (Index == 0)
-            {
-                return ((gen == Gens.Gen0) ? Gen0SizeBeforeMB : 0);
-            }
-
-            // Find a previous HeapStats.  
-            GCHeapStatsTraceData heapStats = null;
-            for (int j = Index - 1; ; --j)
-            {
-                if (j == 0)
-                    return 0;
-                heapStats = Events[j].HeapStats;
-                if (heapStats != null)
-                    break;
-            }
-            if (gen == Gens.Gen0)
-                return Math.Max((heapStats.GenerationSize0 / 1000000.0), Gen0SizeBeforeMB);
-            if (gen == Gens.Gen1)
-                return heapStats.GenerationSize1 / 1000000.0;
-            if (gen == Gens.Gen2)
-                return heapStats.GenerationSize2 / 1000000.0;
-
-            Debug.Assert(gen == Gens.GenLargeObj);
-
-            if (HeapStats != null)
-                return Math.Max(heapStats.GenerationSize3, HeapStats.GenerationSize3) / 1000000.0;
-            else
-                return heapStats.GenerationSize3 / 1000000.0;
-        }
-
-        public void GetCondemnedReasons(Dictionary<CondemnedReasonGroup, int> ReasonsInfo)
-        {
-            // Older versions of the runtime does not have this event. So even for a complete GC, we may not have this
-            // info.
-            if (PerHeapCondemnedReasons == null)
-                return;
-
-            int HeapIndexHighestGen = 0;
-            if (PerHeapCondemnedReasons.Length != 1)
-            {
-                HeapIndexHighestGen = FindFirstHighestCondemnedHeap();
-            }
-
-            byte[] ReasonGroups = PerHeapCondemnedReasons[HeapIndexHighestGen].CondemnedReasonGroups;
-
-            // These 2 reasons indicate a gen number. If the number is the same as the condemned gen, we 
-            // include this reason.
-            for (int i = (int)CondemnedReasonGroup.CRG_Alloc_Exceeded; i <= (int)CondemnedReasonGroup.CRG_Time_Tuning; i++)
-            {
-                if (ReasonGroups[i] == GCGeneration)
-                    AddCondemnedReason(ReasonsInfo, (CondemnedReasonGroup)i);
-            }
-
-            if (ReasonGroups[(int)CondemnedReasonGroup.CRG_Induced] != 0)
-            {
-                if (ReasonGroups[(int)CondemnedReasonGroup.CRG_Initial_Generation] == GCGeneration)
-                {
-                    AddCondemnedReason(ReasonsInfo, CondemnedReasonGroup.CRG_Induced);
-                }
-            }
-
-            // The rest of the reasons are conditions so include the ones that are set.
-            for (int i = (int)CondemnedReasonGroup.CRG_Low_Ephemeral; i < (int)CondemnedReasonGroup.CRG_Max; i++)
-            {
-                if (ReasonGroups[i] != 0)
-                    AddCondemnedReason(ReasonsInfo, (CondemnedReasonGroup)i);
-            }
-        }
-
-        //
-        // Approximations we do in this function for V4_5 and prior:
-        // On 4.0 we didn't seperate free list from free obj, so we just use fragmentation (which is the sum)
-        // as an approximation. This makes the efficiency value a bit larger than it actually is.
-        // We don't actually update in for the older gen - this means we only know the out for the younger 
-        // gen which isn't necessarily all allocated into the older gen. So we could see cases where the 
-        // out is > 0, yet the older gen's free list doesn't change. Using the younger gen's out as an 
-        // approximation makes the efficiency value larger than it actually is.
-        //
-        // For V4_6 this requires no approximation.
-        //
-        public bool GetFreeListEfficiency(Gens gen, ref double Allocated, ref double FreeListConsumed)
-        {
-            // I am not worried about gen0 or LOH's free list efficiency right now - it's 
-            // calculated differently.
-            if ((PerHeapHistories == null) ||
-                (gen == Gens.Gen0) ||
-                (gen == Gens.GenLargeObj) ||
-                (Index <= 0) ||
-                !(PerHeapHistories[0].VersionRecognized))
-            {
-                return false;
-            }
-
-            int YoungerGen = (int)gen - 1;
-
-            if (GCGeneration != YoungerGen)
-                return false;
-
-            if (PerHeapHistories[0].V4_6)
-            {
-                Allocated = 0;
-                FreeListConsumed = 0;
-                for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-                {
-                    GCPerHeapHistoryTraceData3 hist = (GCPerHeapHistoryTraceData3)PerHeapHistories[HeapIndex];
-                    Allocated += hist.FreeListAllocated;
-                    FreeListConsumed += hist.FreeListAllocated + hist.FreeListRejected;
-                }
-                return true;
-            }
-
-            // I am not using MB here because what's promoted from gen1 can easily be less than a MB.
-            double YoungerGenOut = 0;
-            double FreeListBefore = 0;
-            double FreeListAfter = 0;
-            // Includes fragmentation. This lets us know if we had to expand the size.
-            double GenSizeBefore = 0;
-            double GenSizeAfter = 0;
-            for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-            {
-                YoungerGenOut += PerHeapGenData[HeapIndex][YoungerGen].Out;
-                GenSizeBefore += PerHeapGenData[HeapIndex][(int)gen].SizeBefore;
-                GenSizeAfter += PerHeapGenData[HeapIndex][(int)gen].SizeAfter;
-                if (Version == PerHeapEventVersion.V4_0)
-                {
-                    // Occasionally I've seen a GC in the middle that simply missed some events,
-                    // some of which are PerHeap hist events so we don't have data.
-                    if (Events[Index - 1].PerHeapGenData == null)
-                        return false;
-                    FreeListBefore += Events[Index - 1].PerHeapGenData[HeapIndex][(int)gen].Fragmentation;
-                    FreeListAfter += PerHeapGenData[HeapIndex][(int)gen].Fragmentation;
-                }
-                else
-                {
-                    FreeListBefore += PerHeapGenData[HeapIndex][(int)gen].FreeListSpaceBefore;
-                    FreeListAfter += PerHeapGenData[HeapIndex][(int)gen].FreeListSpaceAfter;
-                }
-            }
-
-            double GenSizeGrown = GenSizeAfter - GenSizeBefore;
-
-            // This is the most accurate situation we can calculuate (if it's not accurate it means
-            // we are over estimating which is ok.
-            if ((GenSizeGrown == 0) && ((FreeListBefore > 0) && (FreeListAfter >= 0)))
-            {
-                Allocated = YoungerGenOut;
-                FreeListConsumed = FreeListBefore - FreeListAfter;
-                // We don't know how much of the survived is pinned so we are overestimating here.
-                if (Allocated < FreeListConsumed)
-                    return true;
-            }
-
-            return false;
-        }
-
-        public void GetGenDataObjSizeAfterMB(ref double[] GenData)
-        {
-            for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-            {
-                for (int GenIndex = 0; GenIndex <= (int)Gens.GenLargeObj; GenIndex++)
-                    GenData[GenIndex] += PerHeapGenData[HeapIndex][GenIndex].ObjSizeAfter / 1000000.0;
-            }
-        }
-
-        public void GetGenDataSizeAfterMB(ref double[] GenData)
-        {
-            for (int GenIndex = 0; GenIndex <= (int)Gens.GenLargeObj; GenIndex++)
-                GenData[GenIndex] = GenSizeAfterMB((Gens)GenIndex);
-        }
-
-        public double GetMaxGen0ObjSizeMB()
-        {
-            double MaxGen0ObjSize = 0;
-            for (int HeapIndex = 0; HeapIndex < PerHeapHistories.Count; HeapIndex++)
-            {
-                MaxGen0ObjSize = Math.Max(MaxGen0ObjSize, PerHeapGenData[HeapIndex][(int)Gens.Gen0].ObjSizeAfter / 1000000.0);
-            }
-            return MaxGen0ObjSize;
-        }
-
-        // This represents the percentage time spent paused for this GC since the last GC completed.
-        public double GetPauseTimePercentageSinceLastGC()
-        {
-            double pauseTimePercentage;
-
-            if (Type == GCType.BackgroundGC)
-            {
-                // Find all GCs that occurred during the current background GC.
-                double startTimeRelativeMSec = this.GCStartRelativeMSec;
-                double endTimeRelativeMSec = this.GCStartRelativeMSec + this.GCDurationMSec;
-
-                // Calculate the pause time for this BGC.
-                // Pause time is defined as pause time for the BGC + pause time for all FGCs that ran during the BGC.
-                double totalPauseTime = this.PauseDurationMSec;
-
-                if (Index + 1 < Events.Count)
-                {
-                    GCEvent gcEvent;
-                    for (int i = Index + 1; i < Events.Count; ++i)
-                    {
-                        gcEvent = Events[i];
-                        if ((gcEvent.GCStartRelativeMSec >= startTimeRelativeMSec) && (gcEvent.GCStartRelativeMSec < endTimeRelativeMSec))
-                        {
-                            totalPauseTime += gcEvent.PauseDurationMSec;
-                        }
-                        else
-                        {
-                            // We've finished processing all FGCs that occurred during this BGC.
-                            break;
-                        }
-                    }
-                }
-
-                // Get the elapsed time since the previous GC finished.
-                int previousGCIndex = Index - 1;
-                double previousGCStopTimeRelativeMSec;
-                if (previousGCIndex >= 0)
-                {
-                    GCEvent previousGCEvent = Events[previousGCIndex];
-                    previousGCStopTimeRelativeMSec = previousGCEvent.GCStartRelativeMSec + previousGCEvent.GCDurationMSec;
-                }
-                else
-                {
-                    // Backstop in case this is the first GC.
-                    previousGCStopTimeRelativeMSec = Events[0].GCStartRelativeMSec;
-                }
-
-                double totalTime = (GCStartRelativeMSec + GCDurationMSec) - previousGCStopTimeRelativeMSec;
-                pauseTimePercentage = (totalPauseTime * 100) / (totalTime);
-            }
-            else
-            {
-                double totalTime = PauseDurationMSec + DurationSinceLastRestartMSec;
-                pauseTimePercentage = (PauseDurationMSec * 100) / (totalTime);
-            }
-
-            Debug.Assert(pauseTimePercentage <= 100);
-            return pauseTimePercentage;
-        }
-
-        public int GetPinnedObjectPercentage()
-        {
-            if (totalPinnedPlugSize == -1)
-            {
-                totalPinnedPlugSize = 0;
-                totalUserPinnedPlugSize = 0;
-
-                foreach (KeyValuePair<ulong, long> item in PinnedObjects)
-                {
-                    ulong Address = item.Key;
-
-                    for (int i = 0; i < PinnedPlugs.Count; i++)
-                    {
-                        if ((Address >= PinnedPlugs[i].Start) && (Address < PinnedPlugs[i].End))
-                        {
-                            PinnedPlugs[i].PinnedByUser = true;
-                            break;
-                        }
-                    }
-                }
-
-                for (int i = 0; i < PinnedPlugs.Count; i++)
-                {
-                    long Size = (long)(PinnedPlugs[i].End - PinnedPlugs[i].Start);
-                    totalPinnedPlugSize += Size;
-                    if (PinnedPlugs[i].PinnedByUser)
-                    {
-                        totalUserPinnedPlugSize += Size;
-                    }
-                }
-            }
-
-            return ((totalPinnedPlugSize == 0) ? -1 : (int)((double)pinnedObjectSizes * 100 / (double)totalPinnedPlugSize));
-        }
-
-        public long GetPinnedObjectSizes()
-        {
-            if (pinnedObjectSizes == -1)
-            {
-                pinnedObjectSizes = 0;
-                foreach (KeyValuePair<ulong, long> item in PinnedObjects)
-                {
-                    pinnedObjectSizes += item.Value;
-                }
-            }
-            return pinnedObjectSizes;
-        }
-
-        public double GetTotalGCTime()
-        {
-            if (_TotalGCTimeMSec < 0)
-            {
-                _TotalGCTimeMSec = 0;
-                if (GCCpuServerGCThreads != null)
-                {
-                    for (int i = 0; i < GCCpuServerGCThreads.Length; i++)
-                    {
-                        _TotalGCTimeMSec += GCCpuServerGCThreads[i];
-                    }
-                }
-                _TotalGCTimeMSec += GCCpuMSec;
-            }
-
-            Debug.Assert(_TotalGCTimeMSec >= 0);
-            return _TotalGCTimeMSec;
-        }
-
-        /// <summary>
-        /// Get what's allocated into gen0 or gen3. For server GC this gets the total for 
-        /// all heaps.
-        /// </summary>
-        public double GetUserAllocated(Gens gen)
-        {
-            Debug.Assert((gen == Gens.Gen0) || (gen == Gens.GenLargeObj));
-
-            if ((Type == GCType.BackgroundGC) && (gen == Gens.Gen0))
-            {
-                return AllocedSinceLastGCBasedOnAllocTickMB[(int)gen];
-            }
-
-            if (PerHeapHistories != null && Index > 0 && Events[Index - 1].PerHeapHistories != null)
-            {
-                double TotalAllocated = 0;
-                if (Index > 0)
-                {
-                    for (int i = 0; i < PerHeapHistories.Count; i++)
-                    {
-                        double Allocated = GetUserAllocatedPerHeap(i, gen);
-
-                        TotalAllocated += Allocated / 1000000.0;
-                    }
-
-                    return TotalAllocated;
-                }
-                else
-                {
-                    return GenSizeBeforeMB(gen);
-                }
-            }
-
-            return AllocedSinceLastGCBasedOnAllocTickMB[(gen == Gens.Gen0) ? 0 : 1];
-        }
-
-        public bool IsLowEphemeral()
-        {
-            return CondemnedReasonGroupSet(CondemnedReasonGroup.CRG_Low_Ephemeral);
-        }
-
-        public bool IsNotCompacting()
-        {
-            return ((GlobalHeapHistory.GlobalMechanisms & (GCGlobalMechanisms.Compaction)) != 0);
-        }
-
-        public double ObjSizeAfter(Gens gen)
-        {
-            double TotalObjSizeAfter = 0;
-
-            if (PerHeapHistories != null)
-            {
-                for (int i = 0; i < PerHeapHistories.Count; i++)
-                {
-                    TotalObjSizeAfter += PerHeapGenData[i][(int)gen].ObjSizeAfter;
-                }
-            }
-
-            return TotalObjSizeAfter;
-        }
-
-        // Set in HeapStats
-        public void SetHeapCount(int count)
-        {
-            if (heapCount == -1)
-            {
-                heapCount = count;
-            }
-        }
-        public void SetUpServerGcHistory()
-        {
-            for (int i = 0; i < heapCount; i++)
-            {
-                int gcThreadId = 0;
-                int gcThreadPriority = 0;
-                Parent.ServerGcHeap2ThreadId.TryGetValue(i, out gcThreadId);
-                Parent.ThreadId2Priority.TryGetValue(gcThreadId, out gcThreadPriority);
-                ServerGcHeapHistories.Add(new ServerGcHistory
-                {
-                    Parent = this,
-                    ProcessId = Parent.ProcessID,
-                    HeapId = i,
-                    GcWorkingThreadId = gcThreadId,
-                    GcWorkingThreadPriority = gcThreadPriority
-                });
-            }
-        }
-
-        public double SurvivalPercent(Gens gen)
-        {
-            double retSurvRate = double.NaN;
-
-            long SurvRate = 0;
-
-            if (gen == Gens.GenLargeObj)
-            {
-                if (GCGeneration < 2)
-                {
-                    return retSurvRate;
-                }
-            }
-            else if ((int)gen > GCGeneration)
-            {
-                return retSurvRate;
-            }
-
-            if (PerHeapHistories != null)
-            {
-                for (int i = 0; i < PerHeapHistories.Count; i++)
-                {
-                    SurvRate += PerHeapGenData[i][(int)gen].SurvRate;
-                }
-
-                SurvRate /= PerHeapHistories.Count;
-            }
-
-            retSurvRate = SurvRate;
-
-            return retSurvRate;
-        }
-
-#endregion
-
-        #region Internal Methods
-        internal void AddGcJoin(GCJoinTraceData data)
-        {
-            if (data.Heap >= 0 && data.Heap < ServerGcHeapHistories.Count)
-                ServerGcHeapHistories[data.Heap].AddJoin(data);
-            else
-            {
-                foreach (var heap in ServerGcHeapHistories)
-                    heap.AddJoin(data);
-            }
-
-        }
-        #endregion
-
-        #region Private Methods
-        private void AddCondemnedReason(Dictionary<CondemnedReasonGroup, int> ReasonsInfo, CondemnedReasonGroup Reason)
-        {
-            if (!ReasonsInfo.ContainsKey(Reason))
-                ReasonsInfo.Add(Reason, 1);
-            else
-                (ReasonsInfo[Reason])++;
-        }
-
-        // For true/false groups, return whether that group is set.
-        private bool CondemnedReasonGroupSet(CondemnedReasonGroup Group)
-        {
-            if (PerHeapCondemnedReasons == null)
-            {
-                return false;
-            }
-
-            int HeapIndexHighestGen = 0;
-            if (PerHeapCondemnedReasons.Length != 1)
-            {
-                HeapIndexHighestGen = FindFirstHighestCondemnedHeap();
-            }
-
-            return (PerHeapCondemnedReasons[HeapIndexHighestGen].CondemnedReasonGroups[(int)Group] != 0);
-        }
-
-        // We recorded these as the timestamps when we saw the mark events, now convert them 
-        // to the actual time that it took for each mark.
-        private void ConvertMarkTimes()
-        {
-            if (PerHeapMarkTimes != null)
-            {
-                foreach (KeyValuePair<int, MarkInfo> item in PerHeapMarkTimes)
-                {
-                    if (item.Value.MarkTimes[(int)MarkRootType.MarkSizedRef] == 0.0)
-                        item.Value.MarkTimes[(int)MarkRootType.MarkSizedRef] = GCStartRelativeMSec;
-
-                    if (GCGeneration == 2)
-                        item.Value.MarkTimes[(int)MarkRootType.MarkOlder] = 0;
-                    else
-                        item.Value.MarkTimes[(int)MarkRootType.MarkOlder] -= item.Value.MarkTimes[(int)MarkRootType.MarkHandles];
-
-                    item.Value.MarkTimes[(int)MarkRootType.MarkHandles] -= item.Value.MarkTimes[(int)MarkRootType.MarkFQ];
-                    item.Value.MarkTimes[(int)MarkRootType.MarkFQ] -= item.Value.MarkTimes[(int)MarkRootType.MarkStack];
-                    item.Value.MarkTimes[(int)MarkRootType.MarkStack] -= item.Value.MarkTimes[(int)MarkRootType.MarkSizedRef];
-                    item.Value.MarkTimes[(int)MarkRootType.MarkSizedRef] -= GCStartRelativeMSec;
-                }
-            }
-        }
-
-        // When survival rate is 0, for certain releases (see comments for GetUserAllocatedPerHeap)
-        // we need to estimate.
-        private double EstimateAllocSurv0(int HeapIndex, Gens gen)
-        {
-            if (HasAllocTickEvents)
-            {
-                return AllocedSinceLastGCBasedOnAllocTickMB[(gen == Gens.Gen0) ? 0 : 1];
-            }
-            else
-            {
-                if (Index > 0)
-                {
-                    // If the prevous GC has that heap get its size.  
-                    var perHeapGenData = Events[Index - 1].PerHeapGenData;
-                    if (HeapIndex < perHeapGenData.Length)
-                        return perHeapGenData[HeapIndex][(int)gen].Budget;
-                }
-                return 0;
-            }
-        }
-
-        private int FindFirstHighestCondemnedHeap()
-        {
-            int GenNumberHighest = (int)GCGeneration;
-            for (int HeapIndex = 0; HeapIndex < PerHeapCondemnedReasons.Length; HeapIndex++)
-            {
-                int gen = PerHeapCondemnedReasons[HeapIndex].CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_Final_Generation];
-                if (gen == GenNumberHighest)
-                {
-                    return HeapIndex;
-                }
-            }
-
-            return 0;
-        }
-
-        /// <summary>
-        /// For a given heap, get what's allocated into gen0 or gen3.
-        /// We calculate this differently on 4.0, 4.5 Beta and 4.5 RC+.
-        /// The caveat with 4.0 and 4.5 Beta is that when survival rate is 0,
-        /// We don't know how to calculate the allocated - so we just use the
-        /// last GC's budget (We should indicate this in the tool)
-        /// </summary>
-        private double GetUserAllocatedPerHeap(int HeapIndex, Gens gen)
-        {
-            long prevObjSize = 0;
-            if (Index > 0)
-            {
-                // If the prevous GC has that heap get its size.  
-                var perHeapGenData = Events[Index - 1].PerHeapGenData;
-                if (HeapIndex < perHeapGenData.Length)
-                    prevObjSize = perHeapGenData[HeapIndex][(int)gen].ObjSizeAfter;
-            }
-            GCPerHeapHistoryGenData currentGenData = PerHeapGenData[HeapIndex][(int)gen];
-            long survRate = currentGenData.SurvRate;
-            long currentObjSize = currentGenData.ObjSizeAfter;
-            double Allocated;
-
-            if (Version == PerHeapEventVersion.V4_0)
-            {
-                if (survRate == 0)
-                    Allocated = EstimateAllocSurv0(HeapIndex, gen);
-                else
-                    Allocated = (currentGenData.Out + currentObjSize) * 100 / survRate - prevObjSize;
-            }
-            else
-            {
-                Allocated = currentGenData.ObjSpaceBefore - prevObjSize;
-            }
-
-            return Allocated;
-        }
-
-        private void GetVersion()
-        {
-            if (Version == PerHeapEventVersion.V0)
-            {
-                if (PerHeapHistories[0].V4_0)
-                    Version = PerHeapEventVersion.V4_0;
-                else if (PerHeapHistories[0].V4_5)
-                {
-                    Version = PerHeapEventVersion.V4_5;
-                    Debug.Assert(PerHeapHistories[0].Version == 2);
-                }
-                else
-                {
-                    Version = PerHeapEventVersion.V4_6;
-                    Debug.Assert(PerHeapHistories[0].Version == 3);
-                }
-            }
-        }
-        #endregion
-
-        #region Inner Private Structs
-        private struct EncodedCondemnedReasons
-        {
-            public int Reasons;
-            public int ReasonsEx;
-        }
-        #endregion
-
-        #region Inner Public Classes
-        public class MarkInfo
-        {
-            public long[] MarkPromoted;
-
-            // Note that in 4.5 and prior (ie, from GCMark events, not GCMarkWithType), the first stage of the time 
-            // includes scanning sizedref handles(which can be very significant). We could distinguish that by interpreting 
-            // the Join events which I haven't done yet.
-            public double[] MarkTimes;
-            public MarkInfo(bool initPromoted = true)
-            {
-                MarkTimes = new double[(int)MarkRootType.MarkMax];
-                if (initPromoted)
-                    MarkPromoted = new long[(int)MarkRootType.MarkMax];
-            }
-        };
-
-        public class PinnedPlug
-        {
-            public ulong End;
-            public bool PinnedByUser;
-            public ulong Start;
-            public PinnedPlug(ulong s, ulong e)
-            {
-                Start = s;
-                End = e;
-                PinnedByUser = false;
-            }
-        };
-
-        public class ServerGcHistory
-        {
-            public int GcWorkingThreadId;
-            public int GcWorkingThreadPriority;
-            public int HeapId;
-            public GCEvent Parent;
-            public int ProcessId;
-            public List<GcWorkSpan> SampleSpans = new List<GcWorkSpan>();
-            public List<GcWorkSpan> SwitchSpans = new List<GcWorkSpan>();
-
-            //list of times in msc starting from GC start when GCJoin events were fired for this heap
-            private List<GcJoin> GcJoins = new List<GcJoin>();
-            public enum WorkSpanType
-            {
-                GcThread,
-                RivalThread,
-                LowPriThread,
-                Idle
-            }
-
-            public double TimeBaseMsc { get { return Parent.PauseStartRelativeMSec; } }
-            public void AddSampleEvent(ThreadWorkSpan sample)
-            {
-                GcWorkSpan lastSpan = SampleSpans.Count > 0 ? SampleSpans[SampleSpans.Count - 1] : null;
-                if (lastSpan != null && lastSpan.ThreadId == sample.ThreadId && lastSpan.ProcessId == sample.ProcessId)
-                {
-                    lastSpan.DurationMsc++;
-                }
-                else
-                {
-                    SampleSpans.Add(new GcWorkSpan(sample)
-                    {
-                        Type = GetSpanType(sample),
-                        RelativeTimestampMsc = sample.AbsoluteTimestampMsc - TimeBaseMsc,
-                        DurationMsc = 1
-                    });
-                }
-            }
-
-            public void AddSwitchEvent(ThreadWorkSpan switchData)
-            {
-                GcWorkSpan lastSpan = SwitchSpans.Count > 0 ? SwitchSpans[SwitchSpans.Count - 1] : null;
-                if (switchData.ThreadId == GcWorkingThreadId && switchData.ProcessId == ProcessId)
-                {
-                    //update gc thread priority since we have new data
-                    GcWorkingThreadPriority = switchData.Priority;
-                }
-
-                if (lastSpan != null)
-                {
-                    //updating duration of the last one, based on a timestamp from the new one
-                    lastSpan.DurationMsc = switchData.AbsoluteTimestampMsc - lastSpan.AbsoluteTimestampMsc;
-
-                    //updating wait readon of the last one
-                    lastSpan.WaitReason = switchData.WaitReason;
-                }
-
-                SwitchSpans.Add(new GcWorkSpan(switchData)
-                {
-                    Type = GetSpanType(switchData),
-                    RelativeTimestampMsc = switchData.AbsoluteTimestampMsc - TimeBaseMsc,
-                    Priority = switchData.Priority
-                });
-            }
-
-            internal void AddJoin(GCJoinTraceData data)
-            {
-                GcJoins.Add(new GcJoin
-                {
-                    Heap = data.ProcessorNumber, //data.Heap is not reliable for reset events, so we use ProcessorNumber
-                    AbsoluteTimestampMsc = data.TimeStampRelativeMSec,
-                    RelativeTimestampMsc = data.TimeStampRelativeMSec - Parent.PauseStartRelativeMSec,
-                    Type = data.JoinType,
-                    Time = data.JoinTime,
-                });
-            }
-
-            internal void GCEnd()
-            {
-                GcWorkSpan lastSpan = SwitchSpans.Count > 0 ? SwitchSpans[SwitchSpans.Count - 1] : null;
-                if (lastSpan != null)
-                {
-                    lastSpan.DurationMsc = Parent.PauseDurationMSec - lastSpan.RelativeTimestampMsc;
-                }
-            }
-
-            private WorkSpanType GetSpanType(ThreadWorkSpan span)
-            {
-                if (span.ThreadId == GcWorkingThreadId && span.ProcessId == ProcessId)
-                    return WorkSpanType.GcThread;
-                if (span.ProcessId == 0)
-                    return WorkSpanType.Idle;
-
-                if (span.Priority >= GcWorkingThreadPriority || span.Priority == -1)
-                    return WorkSpanType.RivalThread;
-                else
-                    return WorkSpanType.LowPriThread;
-            }
-
-            public class GcJoin
-            {
-                public double AbsoluteTimestampMsc;
-                public int Heap;
-                public double RelativeTimestampMsc;
-                public GcJoinTime Time;
-                public GcJoinType Type;
-            }
-
-            public class GcWorkSpan : ThreadWorkSpan
-            {
-                public double RelativeTimestampMsc;
-                public WorkSpanType Type;
-                public GcWorkSpan(ThreadWorkSpan span)
-                    : base(span)
-                {
-                }
-            }
-        }
-#endregion
-
-        #region Inner Private Classes
-        private class GCCondemnedReasons
-        {
-            /// <summary>
-            /// This records which reasons are used and the value. Since the biggest value
-            /// we need to record is the generation number a byte is sufficient.
-            /// </summary>
-            public byte[] CondemnedReasonGroups;
-
-            public EncodedCondemnedReasons EncodedReasons;
-
-#if HAS_PRIVATE_GC_EVENTS
-            public Dictionary<int, BGCAllocWaitInfo> LOHWaitThreads;
-#endif
-
-            enum Condemned_Reason_Condition
-            {
-                CRC_induced_fullgc_p = 0,
-                CRC_expand_fullgc_p = 1,
-                CRC_high_mem_p = 2,
-                CRC_very_high_mem_p = 3,
-                CRC_low_ephemeral_p = 4,
-                CRC_low_card_p = 5,
-                CRC_eph_high_frag_p = 6,
-                CRC_max_high_frag_p = 7,
-                CRC_max_high_frag_e_p = 8,
-                CRC_max_high_frag_m_p = 9,
-                CRC_max_high_frag_vm_p = 10,
-                CRC_max_gen1 = 11,
-                CRC_before_oom = 12,
-                CRC_gen2_too_small = 13,
-                CRC_induced_noforce_p = 14,
-                CRC_before_bgc = 15,
-                CRC_max = 16,
-            };
-
-            // These values right now are the same as the first 4 in CondemnedReasonGroup.
-            enum Condemned_Reason_Generation
-            {
-                CRG_initial = 0,
-                CRG_final_per_heap = 1,
-                CRG_alloc_budget = 2,
-                CRG_time_tuning = 3,
-                CRG_max = 4,
-            };
-            public void Decode(PerHeapEventVersion Version)
-            {
-                // First decode the reasons that return us a generation number. 
-                // It's the same in 4.0 and 4.5.
-                for (Condemned_Reason_Generation i = 0; i < Condemned_Reason_Generation.CRG_max; i++)
-                {
-                    CondemnedReasonGroups[(int)i] = (byte)GetReasonWithGenNumber(i);
-                }
-
-                // Then decode the reasons that just indicate true or false.
-                for (Condemned_Reason_Condition i = 0; i < Condemned_Reason_Condition.CRC_max; i++)
-                {
-                    if (GetReasonWithCondition(i, Version))
-                    {
-                        switch (i)
-                        {
-                            case Condemned_Reason_Condition.CRC_induced_fullgc_p:
-                                CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_Induced] = (byte)InducedType.Blocking;
-                                break;
-                            case Condemned_Reason_Condition.CRC_induced_noforce_p:
-                                CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_Induced] = (byte)InducedType.NotForced;
-                                break;
-                            case Condemned_Reason_Condition.CRC_low_ephemeral_p:
-                                CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_Low_Ephemeral] = 1;
-                                break;
-                            case Condemned_Reason_Condition.CRC_low_card_p:
-                                CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_Internal_Tuning] = 1;
-                                break;
-                            case Condemned_Reason_Condition.CRC_eph_high_frag_p:
-                                CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_Fragmented_Ephemeral] = 1;
-                                break;
-                            case Condemned_Reason_Condition.CRC_max_high_frag_p:
-                                CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_Fragmented_Gen2] = 1;
-                                break;
-                            case Condemned_Reason_Condition.CRC_max_high_frag_e_p:
-                                CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_Fragmented_Gen1_To_Gen2] = 1;
-                                break;
-                            case Condemned_Reason_Condition.CRC_max_high_frag_m_p:
-                            case Condemned_Reason_Condition.CRC_max_high_frag_vm_p:
-                                CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_Fragmented_Gen2_High_Mem] = 1;
-                                break;
-                            case Condemned_Reason_Condition.CRC_max_gen1:
-                                CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_Alloc_Exceeded] = 2;
-                                break;
-                            case Condemned_Reason_Condition.CRC_expand_fullgc_p:
-                                CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_Expand_Heap] = 1;
-                                break;
-                            case Condemned_Reason_Condition.CRC_before_oom:
-                                CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_GC_Before_OOM] = 1;
-                                break;
-                            case Condemned_Reason_Condition.CRC_gen2_too_small:
-                                CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_Too_Small_For_BGC] = 1;
-                                break;
-                            case Condemned_Reason_Condition.CRC_before_bgc:
-                                CondemnedReasonGroups[(int)CondemnedReasonGroup.CRG_Ephemeral_Before_BGC] = 1;
-                                break;
-                            default:
-                                Debug.Assert(false, "Unexpected reason");
-                                break;
-                        }
-                    }
-                }
-            }
-
-            private bool GetReasonWithCondition(Condemned_Reason_Condition Reason_Condition, PerHeapEventVersion Version)
-            {
-                bool ConditionIsSet = false;
-                if (Version == PerHeapEventVersion.V4_0)
-                {
-                    Debug.Assert((int)Reason_Condition < 16);
-                    ConditionIsSet = ((EncodedReasons.Reasons & (1 << (int)(Reason_Condition + 16))) != 0);
-                }
-                else
-                {
-                    ConditionIsSet = ((EncodedReasons.ReasonsEx & (1 << (int)Reason_Condition)) != 0);
-                }
-                return ConditionIsSet;
-            }
-
-            private int GetReasonWithGenNumber(Condemned_Reason_Generation Reason_GenNumber)
-            {
-                int GenNumber = ((EncodedReasons.Reasons >> ((int)Reason_GenNumber * 2)) & 0x3);
-                return GenNumber;
-            }
-        }
-        #endregion
-    }
-}
-
-#endif
diff --git a/tests/src/GC/Performance/Framework/Metrics/Builders/GCInfo.cs b/tests/src/GC/Performance/Framework/Metrics/Builders/GCInfo.cs
deleted file mode 100644 (file)
index 13fd173..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if WINDOWS
-
-namespace GCPerfTestFramework.Metrics.Builders
-{
-    /// <summary>
-    /// GCInfo are accumulated statistics per generation.  
-    /// </summary>    
-    internal class GCInfo
-    {
-        public int GCCount;
-        public int NumInduced;
-        public long PinnedObjectSizes;
-        public int PinnedObjectPercentage;
-        public long NumGCWithPinEvents;
-        public long NumGCWithPinPlugEvents;
-        public double MaxPauseDurationMSec;
-        public double MeanPauseDurationMSec { get { return TotalPauseTimeMSec / GCCount; } }
-        public double MeanSizeAfterMB { get { return TotalSizeAfterMB / GCCount; } }
-        public double MeanSizePeakMB { get { return TotalSizePeakMB / GCCount; } }
-        public double MeanAllocatedMB { get { return TotalAllocatedMB / GCCount; } }
-        public double RatioMeanPeakAfter { get { return MeanSizePeakMB / MeanSizeAfterMB; } }
-        public double MeanGCCpuMSec { get { return TotalGCCpuMSec / GCCount; } }
-
-        public double TotalPauseTimeMSec;
-        public double MaxSuspendDurationMSec;
-        public double MaxSizePeakMB;
-        public double MaxAllocRateMBSec;
-
-        public double TotalAllocatedMB;
-        public double TotalGCCpuMSec;
-        public double TotalPromotedMB;
-
-        // these do not have a useful meaning so we hide them. 
-        internal double TotalSizeAfterMB;
-        internal double TotalSizePeakMB;
-    }
-}
-
-#endif
diff --git a/tests/src/GC/Performance/Framework/Metrics/Builders/GCProcess.cs b/tests/src/GC/Performance/Framework/Metrics/Builders/GCProcess.cs
deleted file mode 100644 (file)
index 29ed680..0000000
+++ /dev/null
@@ -1,1257 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if WINDOWS
-
-using Microsoft.Diagnostics.Tracing;
-using Microsoft.Diagnostics.Tracing.Etlx;
-using Microsoft.Diagnostics.Tracing.Parsers.Clr;
-using Microsoft.Diagnostics.Tracing.Parsers.Kernel;
-using Microsoft.Diagnostics.Tracing.Stacks;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-
-#if HAS_PRIVATE_GC_EVENTS
-using Microsoft.Diagnostics.Tracing.Parsers.ClrPrivate;
-#endif
-
-
-namespace GCPerfTestFramework.Metrics.Builders
-{
-    /// <summary>
-    /// GCProcess holds information about GCs in a particular process. 
-    /// </summary>
-    /// 
-    // Notes on parsing GC events:
-    // GC events need to be interpreted in sequence and if we attach we 
-    // may not get the whole sequence of a GC. We discard the incomplete
-    // GC from the beginning and ending. 
-    //
-    // We can make the assumption if we have the events from the private 
-    // provider it means we have events from public provider, but not the
-    // other way around.
-    //
-    // All GC events are at informational level except the following:
-    // AllocTick from the public provider
-    // GCJoin from the private provider
-    // We may only have events at the informational level, not verbose level.
-    //
-    internal class GCProcess
-    {
-        internal static IDictionary<int, GCProcess> Collect(
-            TraceEventSource source, 
-            float sampleIntervalMSec, 
-            IDictionary<int, GCProcess> perProc = null, 
-            MutableTraceEventStackSource stackSource = null,
-            Predicate<TraceEvent> filterFunc = null)
-        {
-            if (perProc == null)
-            {
-                perProc = new Dictionary<int, GCProcess>();
-            }
-
-            source.Kernel.AddCallbackForEvents(delegate (ProcessCtrTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                var stats = perProc.GetOrCreate(data.ProcessID);
-                stats.PeakVirtualMB = ((double)data.PeakVirtualSize) / 1000000.0;
-                stats.PeakWorkingSetMB = ((double)data.PeakWorkingSetSize) / 1000000.0;
-            });
-
-            Action<RuntimeInformationTraceData> doAtRuntimeStart = delegate (RuntimeInformationTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                var stats = perProc.GetOrCreate(data.ProcessID);
-                stats.RuntimeVersion = "V " + data.VMMajorVersion.ToString() + "." + data.VMMinorVersion + "." + data.VMBuildNumber
-                    + "." + data.VMQfeNumber;
-                stats.StartupFlags = data.StartupFlags;
-                stats.Bitness = (data.RuntimeDllPath.ToLower().Contains("framework64") ? 64 : 32);
-                if (stats.CommandLine == null)
-                    stats.CommandLine = data.CommandLine;
-            };
-
-            // log at both startup and rundown
-            //var clrRundown = new ClrRundownTraceEventParser(source);
-            //clrRundown.RuntimeStart += doAtRuntimeStart;
-            source.Clr.AddCallbackForEvent("Runtime/Start", doAtRuntimeStart);
-
-            Action<ProcessTraceData> processStartCallback = data =>
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                var stats = perProc.GetOrCreate(data.ProcessID);
-
-                if (!string.IsNullOrEmpty(data.KernelImageFileName))
-                {
-                    // When we just have an EventSource (eg, the source was created by 
-                    // ETWTraceEventSource), we don't necessarily have the process names
-                    // decoded - it all depends on whether we have seen a ProcessStartGroup 
-                    // event or not. When the trace was taken after the process started we 
-                    // know we didn't see such an event.
-                    string name = GetImageName(data.KernelImageFileName);
-
-                    // Strictly speaking, this is not really fixing it 'cause 
-                    // it doesn't handle when a process with the same name starts
-                    // with the same pid. The chance of that happening is really small.
-                    if (stats.isDead == true)
-                    {
-                        stats = new GCProcess();
-                        stats.Init(data);
-                        perProc[data.ProcessID] = stats;
-                    }
-                }
-
-                var commandLine = data.CommandLine;
-                if (!string.IsNullOrEmpty(commandLine))
-                    stats.CommandLine = commandLine;
-            };
-
-            source.Kernel.AddCallbackForEvent("Process/Start", processStartCallback);
-            source.Kernel.AddCallbackForEvent("Process/DCStart", processStartCallback);
-
-            Action<ProcessTraceData> processEndCallback = delegate (ProcessTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                var stats = perProc.GetOrCreate(data.ProcessID);
-
-                if (string.IsNullOrEmpty(stats.ProcessName))
-                {
-                    stats.ProcessName = GetImageName(data.KernelImageFileName);
-                }
-
-                if (data.OpcodeName == "Stop")
-                {
-                    stats.isDead = true;
-                }
-            };
-
-            source.Kernel.AddCallbackForEvent("Process/Stop", processEndCallback);
-            source.Kernel.AddCallbackForEvent("Process/DCStop", processEndCallback);
-
-#if (!CAP)
-            CircularBuffer<ThreadWorkSpan> RecentThreadSwitches = new CircularBuffer<ThreadWorkSpan>(10000);
-            source.Kernel.AddCallbackForEvent("Thread/CSwitch", delegate (CSwitchTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                RecentThreadSwitches.Add(new ThreadWorkSpan(data));
-                GCProcess stats;
-                if (perProc.TryGetValue(data.ProcessID, out stats))
-                {
-                    stats.ThreadId2Priority[data.NewThreadID] = data.NewThreadPriority;
-                    if (stats.IsServerGCThread(data.ThreadID) > -1)
-                    {
-                        stats.ServerGcHeap2ThreadId[data.ProcessorNumber] = data.ThreadID;
-                    }
-                }
-
-                foreach (var gcProcess in perProc.Values)
-                {
-                    GCEvent _event = gcProcess.GetCurrentGC();
-                    // If we are in the middle of a GC.
-                    if (_event != null)
-                    {
-                        if ((_event.Type != GCType.BackgroundGC) && (gcProcess.isServerGCUsed == 1))
-                        {
-                            _event.AddServerGcThreadSwitch(new ThreadWorkSpan(data));
-                        }
-                    }
-                }
-            });
-
-            CircularBuffer<ThreadWorkSpan> RecentCpuSamples = new CircularBuffer<ThreadWorkSpan>(1000);
-            StackSourceSample sample = new StackSourceSample(stackSource);
-
-            source.Kernel.AddCallbackForEvent("PerfInfo/Sample", delegate (SampledProfileTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                RecentCpuSamples.Add(new ThreadWorkSpan(data));
-                GCProcess processWithGc = null;
-                foreach (var gcProcess in perProc.Values)
-                {
-                    GCEvent e = gcProcess.GetCurrentGC();
-                    // If we are in the middle of a GC.
-                    if (e != null)
-                    {
-                        if ((e.Type != GCType.BackgroundGC) && (gcProcess.isServerGCUsed == 1))
-                        {
-                            e.AddServerGcSample(new ThreadWorkSpan(data));
-                            processWithGc = gcProcess;
-                        }
-                    }
-                }
-
-                if (stackSource != null && processWithGc != null)
-                {
-                    GCEvent e = processWithGc.GetCurrentGC();
-                    sample.Metric = 1;
-                    sample.TimeRelativeMSec = data.TimeStampRelativeMSec;
-                    var nodeName = string.Format("Server GCs #{0} in {1} (PID:{2})", e.GCNumber, processWithGc.ProcessName, processWithGc.ProcessID);
-                    var nodeIndex = stackSource.Interner.FrameIntern(nodeName);
-                    sample.StackIndex = stackSource.Interner.CallStackIntern(nodeIndex, stackSource.GetCallStack(data.CallStackIndex(), data));
-                    stackSource.AddSample(sample);
-                }
-
-                GCProcess stats;
-                if (perProc.TryGetValue(data.ProcessID, out stats))
-                {
-                    if (stats.IsServerGCThread(data.ThreadID) > -1)
-                    {
-                        stats.ServerGcHeap2ThreadId[data.ProcessorNumber] = data.ThreadID;
-                    }
-
-                    var cpuIncrement = sampleIntervalMSec;
-                    stats.ProcessCpuMSec += cpuIncrement;
-
-                    GCEvent _event = stats.GetCurrentGC();
-                    // If we are in the middle of a GC.
-                    if (_event != null)
-                    {
-                        bool isThreadDoingGC = false;
-                        if ((_event.Type != GCType.BackgroundGC) && (stats.isServerGCUsed == 1))
-                        {
-                            int heapIndex = stats.IsServerGCThread(data.ThreadID);
-                            if (heapIndex != -1)
-                            {
-                                _event.AddServerGCThreadTime(heapIndex, cpuIncrement);
-                                isThreadDoingGC = true;
-                            }
-                        }
-                        else if (data.ThreadID == stats.suspendThreadIDGC)
-                        {
-                            _event.GCCpuMSec += cpuIncrement;
-                            isThreadDoingGC = true;
-                        }
-                        else if (stats.IsBGCThread(data.ThreadID))
-                        {
-                            Debug.Assert(stats.currentBGC != null);
-                            if (stats.currentBGC != null)
-                                stats.currentBGC.GCCpuMSec += cpuIncrement;
-                            isThreadDoingGC = true;
-                        }
-
-                        if (isThreadDoingGC)
-                        {
-                            stats.GCCpuMSec += cpuIncrement;
-                        }
-                    }
-                }
-            });
-#endif
-
-
-            source.Clr.AddCallbackForEvent("GC/SuspendEEStart", delegate (GCSuspendEETraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                var stats = perProc.GetOrCreate(data.ProcessID);
-                switch (data.Reason)
-                {
-                    case GCSuspendEEReason.SuspendForGC:
-                        stats.suspendThreadIDGC = data.ThreadID;
-                        break;
-                    case GCSuspendEEReason.SuspendForGCPrep:
-                        stats.suspendThreadIDBGC = data.ThreadID;
-                        break;
-                    default:
-                        stats.suspendThreadIDOther = data.ThreadID;
-                        break;
-                }
-
-                stats.suspendTimeRelativeMSec = data.TimeStampRelativeMSec;
-            });
-
-            // In 2.0 we didn't have this event.
-
-            source.Clr.AddCallbackForEvent("GC/SuspendEEStop", delegate (GCNoUserDataTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc.GetOrCreate(data.ProcessID);
-
-                if ((stats.suspendThreadIDBGC > 0) && (stats.currentBGC != null))
-                {
-                    stats.currentBGC._SuspendDurationMSec += data.TimeStampRelativeMSec - stats.suspendTimeRelativeMSec;
-                }
-
-                stats.suspendEndTimeRelativeMSec = data.TimeStampRelativeMSec;
-            });
-
-            source.Clr.AddCallbackForEvent("GC/RestartEEStop", delegate (GCNoUserDataTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc.GetOrCreate(data.ProcessID);
-                GCEvent _event = stats.GetCurrentGC();
-                if (_event != null)
-                {
-                    if (_event.Type == GCType.BackgroundGC)
-                    {
-                        stats.AddConcurrentPauseTime(_event, data.TimeStampRelativeMSec);
-                    }
-                    else
-                    {
-                        Debug.Assert(_event.PauseStartRelativeMSec != 0);
-                        // In 2.0 Concurrent GC, since we don't know the GC's type we can't tell if it's concurrent 
-                        // or not. But we know we don't have nested GCs there so simply check if we have received the
-                        // GCStop event; if we have it means it's a blocking GC; otherwise it's a concurrent GC so 
-                        // simply add the pause time to the GC without making the GC complete.
-                        if (_event.GCDurationMSec == 0)
-                        {
-                            Debug.Assert(_event.is20Event);
-                            _event.isConcurrentGC = true;
-                            stats.AddConcurrentPauseTime(_event, data.TimeStampRelativeMSec);
-                        }
-                        else
-                        {
-                            _event.PauseDurationMSec = data.TimeStampRelativeMSec - _event.PauseStartRelativeMSec;
-                            if (_event.HeapStats != null)
-                            {
-                                _event.isComplete = true;
-                                stats.lastCompletedGC = _event;
-                            }
-                        }
-                    }
-                }
-
-                // We don't change between a GC end and the pause resume.   
-                //Debug.Assert(stats.allocTickAtLastGC == stats.allocTickCurrentMB);
-                // Mark that we are not in suspension anymore.  
-                stats.suspendTimeRelativeMSec = -1;
-                stats.suspendThreadIDOther = -1;
-                stats.suspendThreadIDBGC = -1;
-                stats.suspendThreadIDGC = -1;
-            });
-
-            source.Clr.AddCallbackForEvent("GC/AllocationTick", delegate (GCAllocationTickTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc.GetOrCreate(data.ProcessID);
-
-                if (stats.HasAllocTickEvents == false)
-                {
-                    stats.HasAllocTickEvents = true;
-                }
-
-                double valueMB = data.GetAllocAmount(ref stats.SeenBadAllocTick) / 1000000.0;
-
-                if (data.AllocationKind == GCAllocationKind.Small)
-                {
-                    // Would this do the right thing or is it always 0 for SOH since AllocationAmount 
-                    // is an int??? 
-                    stats.allocTickCurrentMB[0] += valueMB;
-                }
-                else
-                {
-                    stats.allocTickCurrentMB[1] += valueMB;
-                }
-            });
-
-            source.Clr.AddCallbackForEvent("GC/Start", delegate (GCStartTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc.GetOrCreate(data.ProcessID);
-
-                // We need to filter the scenario where we get 2 GCStart events for each GC.
-                if ((stats.suspendThreadIDGC > 0) &&
-                    !((stats.events.Count > 0) && stats.events[stats.events.Count - 1].GCNumber == data.Count))
-                {
-                    GCEvent _event = new GCEvent(stats);
-                    Debug.Assert(0 <= data.Depth && data.Depth <= 2);
-                    // _event.GCGeneration = data.Depth;   Old style events only have this in the GCStop event.  
-                    _event.Reason = data.Reason;
-                    _event.GCNumber = data.Count;
-                    _event.Type = data.Type;
-                    _event.Index = stats.events.Count;
-                    _event.is20Event = data.IsClassicProvider;
-                    bool isEphemeralGCAtBGCStart = false;
-                    // Detecting the ephemeral GC that happens at the beginning of a BGC.
-                    if (stats.events.Count > 0)
-                    {
-                        GCEvent lastGCEvent = stats.events[stats.events.Count - 1];
-                        if ((lastGCEvent.Type == GCType.BackgroundGC) &&
-                            (!lastGCEvent.isComplete) &&
-                            (data.Type == GCType.NonConcurrentGC))
-                        {
-                            isEphemeralGCAtBGCStart = true;
-                        }
-                    }
-
-                    Debug.Assert(stats.suspendTimeRelativeMSec != -1);
-                    if (isEphemeralGCAtBGCStart)
-                    {
-                        _event.PauseStartRelativeMSec = data.TimeStampRelativeMSec;
-                    }
-                    else
-                    {
-                        _event.PauseStartRelativeMSec = stats.suspendTimeRelativeMSec;
-                        if (stats.suspendEndTimeRelativeMSec == -1)
-                        {
-                            stats.suspendEndTimeRelativeMSec = data.TimeStampRelativeMSec;
-                        }
-
-                        _event._SuspendDurationMSec = stats.suspendEndTimeRelativeMSec - stats.suspendTimeRelativeMSec;
-                    }
-
-                    _event.GCStartRelativeMSec = data.TimeStampRelativeMSec;
-                    stats.events.Add(_event);
-
-                    if (_event.Type == GCType.BackgroundGC)
-                    {
-                        stats.currentBGC = _event;
-                        _event.ProcessCpuAtLastGC = stats.ProcessCpuAtLastGC;
-                    }
-
-#if (!CAP)
-                    if ((_event.Type != GCType.BackgroundGC) && (stats.isServerGCUsed == 1))
-                    {
-                        _event.SetUpServerGcHistory();
-                        foreach (var s in RecentCpuSamples)
-                            _event.AddServerGcSample(s);
-                        foreach (var s in RecentThreadSwitches)
-                            _event.AddServerGcThreadSwitch(s);
-                    }
-#endif 
-                }
-            });
-
-            source.Clr.AddCallbackForEvent("GC/PinObjectAtGCTime", delegate (PinObjectAtGCTimeTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc.GetOrCreate(data.ProcessID);
-                GCEvent _event = stats.GetCurrentGC();
-                if (_event != null)
-                {
-                    if (!_event.PinnedObjects.ContainsKey(data.ObjectID))
-                    {
-                        _event.PinnedObjects.Add(data.ObjectID, data.ObjectSize);
-                    }
-                    else
-                    {
-                        _event.duplicatedPinningReports++;
-                    }
-                }
-            });
-
-            // Some builds have this as a public event, and some have it as a private event.
-            // All will move to the private event, so we'll remove this code afterwards.
-            source.Clr.AddCallbackForEvent("GC/PinPlugAtGCTime", delegate (PinPlugAtGCTimeTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc.GetOrCreate(data.ProcessID);
-                GCEvent _event = stats.GetCurrentGC();
-                if (_event != null)
-                {
-                    // ObjectID is supposed to be an IntPtr. But "Address" is defined as UInt64 in 
-                    // TraceEvent.
-                    _event.PinnedPlugs.Add(new GCEvent.PinnedPlug(data.PlugStart, data.PlugEnd));
-                }
-            });
-
-            source.Clr.AddCallbackForEvent("GC/Mark", delegate (GCMarkWithTypeTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc.GetOrCreate(data.ProcessID);
-                stats.AddServerGCThreadFromMark(data.ThreadID, data.HeapNum);
-
-                GCEvent _event = stats.GetCurrentGC();
-                if (_event != null)
-                {
-                    if (_event.PerHeapMarkTimes == null)
-                    {
-                        _event.PerHeapMarkTimes = new Dictionary<int, GCEvent.MarkInfo>();
-                    }
-
-                    if (!_event.PerHeapMarkTimes.ContainsKey(data.HeapNum))
-                    {
-                        _event.PerHeapMarkTimes.Add(data.HeapNum, new GCEvent.MarkInfo());
-                    }
-
-                    _event.PerHeapMarkTimes[data.HeapNum].MarkTimes[(int)data.Type] = data.TimeStampRelativeMSec;
-                    _event.PerHeapMarkTimes[data.HeapNum].MarkPromoted[(int)data.Type] = data.Promoted;
-                }
-            });
-
-            source.Clr.AddCallbackForEvent("GC/GlobalHeapHistory", delegate (GCGlobalHeapHistoryTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc.GetOrCreate(data.ProcessID);
-                stats.ProcessGlobalHistory(data);
-            });
-
-            source.Clr.AddCallbackForEvent("GC/PerHeapHistory", delegate (GCPerHeapHistoryTraceData3 data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc.GetOrCreate(data.ProcessID);
-                stats.ProcessPerHeapHistory(data);
-            });
-
-#if HAS_PRIVATE_GC_EVENTS
-            // See if the source knows about the CLR Private provider, if it does, then 
-            var gcPrivate = new ClrPrivateTraceEventParser(source);
-
-            gcPrivate.GCPinPlugAtGCTime += delegate (PinPlugAtGCTimeTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc[data];
-                GCEvent _event = stats.GetCurrentGC();
-                if (_event != null)
-                {
-                    // ObjectID is supposed to be an IntPtr. But "Address" is defined as UInt64 in 
-                    // TraceEvent.
-                    _event.PinnedPlugs.Add(new GCEvent.PinnedPlug(data.PlugStart, data.PlugEnd));
-                }
-            };
-
-            // Sometimes at the end of a trace I see only some mark events are included in the trace and they
-            // are not in order, so need to anticipate that scenario.
-            gcPrivate.GCMarkStackRoots += delegate (GCMarkTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc[data];
-                stats.AddServerGCThreadFromMark(data.ThreadID, data.HeapNum);
-
-                GCEvent _event = stats.GetCurrentGC();
-                if (_event != null)
-                {
-                    if (_event.PerHeapMarkTimes == null)
-                    {
-                        _event.PerHeapMarkTimes = new Dictionary<int, GCEvent.MarkInfo>();
-                    }
-
-                    if (!_event.PerHeapMarkTimes.ContainsKey(data.HeapNum))
-                    {
-                        _event.PerHeapMarkTimes.Add(data.HeapNum, new GCEvent.MarkInfo(false));
-                    }
-
-                    _event.PerHeapMarkTimes[data.HeapNum].MarkTimes[(int)MarkRootType.MarkStack] = data.TimeStampRelativeMSec;
-                }
-            };
-
-            gcPrivate.GCMarkFinalizeQueueRoots += delegate (GCMarkTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc[data];
-                GCEvent _event = stats.GetCurrentGC();
-                if (_event != null)
-                {
-                    if ((_event.PerHeapMarkTimes != null) && _event.PerHeapMarkTimes.ContainsKey(data.HeapNum))
-                    {
-                        _event.PerHeapMarkTimes[data.HeapNum].MarkTimes[(int)MarkRootType.MarkFQ] =
-                            data.TimeStampRelativeMSec;
-                    }
-                }
-            };
-
-            gcPrivate.GCMarkHandles += delegate (GCMarkTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc[data];
-                GCEvent _event = stats.GetCurrentGC();
-                if (_event != null)
-                {
-                    if ((_event.PerHeapMarkTimes != null) && _event.PerHeapMarkTimes.ContainsKey(data.HeapNum))
-                    {
-                        _event.PerHeapMarkTimes[data.HeapNum].MarkTimes[(int)MarkRootType.MarkHandles] =
-                           data.TimeStampRelativeMSec;
-                    }
-                }
-            };
-
-            gcPrivate.GCMarkCards += delegate (GCMarkTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc[data];
-                GCEvent _event = stats.GetCurrentGC();
-                if (_event != null)
-                {
-                    if ((_event.PerHeapMarkTimes != null) && _event.PerHeapMarkTimes.ContainsKey(data.HeapNum))
-                    {
-                        _event.PerHeapMarkTimes[data.HeapNum].MarkTimes[(int)MarkRootType.MarkOlder] =
-                            data.TimeStampRelativeMSec;
-                    }
-                }
-            };
-
-            gcPrivate.GCGlobalHeapHistory += delegate (GCGlobalHeapHistoryTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc[data];
-                stats.ProcessGlobalHistory(data);
-            };
-
-            gcPrivate.GCPerHeapHistory += delegate (GCPerHeapHistoryTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc[data];
-                stats.ProcessPerHeapHistory(data);
-            };
-
-            gcPrivate.GCBGCStart += delegate (GCNoUserDataTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc[data];
-                if (stats.currentBGC != null)
-                {
-                    if (stats.backgroundGCThreads == null)
-                    {
-                        stats.backgroundGCThreads = new Dictionary<int, object>(16);
-                    }
-                    stats.backgroundGCThreads[data.ThreadID] = null;
-                }
-            };
-#endif
-
-            source.Clr.AddCallbackForEvent("GC/Stop", delegate (GCEndTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc.GetOrCreate(data.ProcessID);
-                GCEvent _event = stats.GetCurrentGC();
-                if (_event != null)
-                {
-                    _event.GCDurationMSec = data.TimeStampRelativeMSec - _event.GCStartRelativeMSec;
-                    _event.GCGeneration = data.Depth;
-                    _event.GCEnd();
-                }
-            });
-
-            source.Clr.AddCallbackForEvent("GC/HeapStats", delegate (GCHeapStatsTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc.GetOrCreate(data.ProcessID);
-                GCEvent _event = stats.GetCurrentGC();
-
-                var sizeAfterMB = (data.GenerationSize1 + data.GenerationSize2 + data.GenerationSize3) / 1000000.0;
-                if (_event != null)
-                {
-                    _event.HeapStats = (GCHeapStatsTraceData)data.Clone();
-
-                    if (_event.Type == GCType.BackgroundGC)
-                    {
-                        _event.ProcessCpuMSec = stats.ProcessCpuMSec - _event.ProcessCpuAtLastGC;
-                        _event.DurationSinceLastRestartMSec = data.TimeStampRelativeMSec - stats.lastRestartEndTimeRelativeMSec;
-                    }
-                    else
-                    {
-                        _event.ProcessCpuMSec = stats.ProcessCpuMSec - stats.ProcessCpuAtLastGC;
-                        _event.DurationSinceLastRestartMSec = _event.PauseStartRelativeMSec - stats.lastRestartEndTimeRelativeMSec;
-                    }
-
-                    if (stats.HasAllocTickEvents)
-                    {
-                        _event.HasAllocTickEvents = true;
-                        _event.AllocedSinceLastGCBasedOnAllocTickMB[0] = stats.allocTickCurrentMB[0] - stats.allocTickAtLastGC[0];
-                        _event.AllocedSinceLastGCBasedOnAllocTickMB[1] = stats.allocTickCurrentMB[1] - stats.allocTickAtLastGC[1];
-                    }
-
-                    // This is where a background GC ends.
-                    if ((_event.Type == GCType.BackgroundGC) && (stats.currentBGC != null))
-                    {
-                        stats.currentBGC.isComplete = true;
-                        stats.lastCompletedGC = stats.currentBGC;
-                        stats.currentBGC = null;
-                    }
-
-                    if (_event.isConcurrentGC)
-                    {
-                        Debug.Assert(_event.is20Event);
-                        _event.isComplete = true;
-                        stats.lastCompletedGC = _event;
-                    }
-                }
-
-                stats.ProcessCpuAtLastGC = stats.ProcessCpuMSec;
-                stats.allocTickAtLastGC[0] = stats.allocTickCurrentMB[0];
-                stats.allocTickAtLastGC[1] = stats.allocTickCurrentMB[1];
-                stats.lastRestartEndTimeRelativeMSec = data.TimeStampRelativeMSec;
-            });
-
-            source.Clr.AddCallbackForEvent("GC/TerminateConcurrentThread", delegate (GCTerminateConcurrentThreadTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc.GetOrCreate(data.ProcessID);
-                if (stats.backgroundGCThreads != null)
-                {
-                    stats.backgroundGCThreads = null;
-                }
-            });
-
-#if HAS_PRIVATE_GC_EVENTS
-            gcPrivate.GCBGCAllocWaitStart += delegate (BGCAllocWaitTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc[data];
-                Debug.Assert(stats.currentBGC != null);
-
-                if (stats.currentBGC != null)
-                {
-                    stats.currentBGC.AddLOHWaitThreadInfo(data.ThreadID, data.TimeStampRelativeMSec, data.Reason, true);
-                }
-            };
-
-            gcPrivate.GCBGCAllocWaitStop += delegate (BGCAllocWaitTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess stats = perProc[data];
-
-                GCEvent _event = stats.GetLastBGC();
-
-                if (_event != null)
-                {
-                    _event.AddLOHWaitThreadInfo(data.ThreadID, data.TimeStampRelativeMSec, data.Reason, false);
-                }
-            };
-
-            gcPrivate.GCJoin += delegate (GCJoinTraceData data)
-            {
-                if (filterFunc != null && !filterFunc.Invoke(data))
-                {
-                    return;
-                }
-
-                GCProcess gcProcess = perProc[data];
-                GCEvent _event = gcProcess.GetCurrentGC();
-                if (_event != null)
-                {
-                    _event.AddGcJoin(data);
-                }
-            };
-
-            source.Process();
-#endif
-            return perProc;
-        }
-
-        public int ProcessID { get; set; }
-        public string ProcessName { get; set; }
-        bool isDead;
-        public bool Interesting { get { return Total.GCCount > 0 || RuntimeVersion != null; } }
-        public bool InterestingForAnalysis
-        {
-            get
-            {
-                return ((Total.GCCount > 3) &&
-                        ((GetGCPauseTimePercentage() > 1.0) || (Total.MaxPauseDurationMSec > 200.0)));
-            }
-        }
-
-        // A process can have one or more SBAs associated with it.
-        public GCInfo[] Generations = new GCInfo[3] { new GCInfo(), new GCInfo(), new GCInfo() };
-        public GCInfo Total = new GCInfo();
-        public float ProcessCpuMSec;     // Total CPU time used in process (approximate)
-        public float GCCpuMSec;          // CPU time used in the GC (approximate)
-        public int NumberOfHeaps = 1;
-
-        // Of all the CPU, how much as a percentage is spent in the GC. 
-        public float PercentTimeInGC { get { return GCCpuMSec * 100 / ProcessCpuMSec; } }
-
-        public static string GetImageName(string path)
-        {
-            int startIdx = path.LastIndexOf('\\');
-            if (0 <= startIdx)
-                startIdx++;
-            else
-                startIdx = 0;
-            int endIdx = path.LastIndexOf('.');
-            if (endIdx <= startIdx)
-                endIdx = path.Length;
-            string name = path.Substring(startIdx, endIdx - startIdx);
-            return name;
-        }
-
-        // This is calculated based on the GC events which is fine for the GC analysis purpose.
-        public double ProcessDuration
-        {
-            get
-            {
-                double startRelativeMSec = 0.0;
-
-                for (int i = 0; i < events.Count; i++)
-                {
-                    if (events[i].isComplete)
-                    {
-                        startRelativeMSec = events[i].PauseStartRelativeMSec;
-                        break;
-                    }
-                }
-
-                if (startRelativeMSec == 0.0)
-                    return 0;
-
-                // Get the end time of the last GC.
-                double endRelativeMSec = lastRestartEndTimeRelativeMSec;
-                return (endRelativeMSec - startRelativeMSec);
-            }
-        }
-
-        public StartupFlags StartupFlags;
-        public string RuntimeVersion;
-        public int Bitness = -1;
-        public Dictionary<int, int> ThreadId2Priority = new Dictionary<int, int>();
-        public Dictionary<int, int> ServerGcHeap2ThreadId = new Dictionary<int, int>();
-
-        public string CommandLine { get; set; }
-
-        public double PeakWorkingSetMB { get; set; }
-        public double PeakVirtualMB { get; set; }
-
-        /// <summary>
-        /// Means it detected that the ETW information is in a format it does not understand.
-        /// </summary>
-        public bool GCVersionInfoMismatch { get; private set; }
-
-        public double GetGCPauseTimePercentage()
-        {
-            return ((ProcessDuration == 0) ? 0.0 : ((Total.TotalPauseTimeMSec * 100) / ProcessDuration));
-        }
-
-        internal static void ComputeRollup(IDictionary<int, GCProcess> perProc)
-        {
-            // Compute rollup information.  
-            foreach (GCProcess stats in perProc.Values)
-            {
-                for (int i = 0; i < stats.events.Count; i++)
-                {
-                    GCEvent _event = stats.events[i];
-                    if (!_event.isComplete)
-                    {
-                        continue;
-                    }
-
-                    _event.Index = i;
-                    if (_event.DetailedGenDataAvailable())  //per heap histories is not null
-                        stats.m_detailedGCInfo = true;
-
-                    // Update the per-generation information 
-                    stats.Generations[_event.GCGeneration].GCCount++;
-                    bool isInduced = ((_event.Reason == GCReason.Induced) || (_event.Reason == GCReason.InducedNotForced));
-                    if (isInduced)
-                        (stats.Generations[_event.GCGeneration].NumInduced)++;
-
-                    long PinnedObjectSizes = _event.GetPinnedObjectSizes();
-                    if (PinnedObjectSizes != 0)
-                    {
-                        stats.Generations[_event.GCGeneration].PinnedObjectSizes += PinnedObjectSizes;
-                        stats.Generations[_event.GCGeneration].NumGCWithPinEvents++;
-                    }
-
-                    int PinnedObjectPercentage = _event.GetPinnedObjectPercentage();
-                    if (PinnedObjectPercentage != -1)
-                    {
-                        stats.Generations[_event.GCGeneration].PinnedObjectPercentage += _event.GetPinnedObjectPercentage();
-                        stats.Generations[_event.GCGeneration].NumGCWithPinPlugEvents++;
-                    }
-
-                    stats.Generations[_event.GCGeneration].TotalGCCpuMSec += _event.GetTotalGCTime();
-                    stats.Generations[_event.GCGeneration].TotalSizeAfterMB += _event.HeapSizeAfterMB;
-
-                    stats.Generations[_event.GCGeneration].TotalSizePeakMB += _event.HeapSizePeakMB;
-                    stats.Generations[_event.GCGeneration].TotalPromotedMB += _event.PromotedMB;
-                    stats.Generations[_event.GCGeneration].TotalPauseTimeMSec += _event.PauseDurationMSec;
-                    stats.Generations[_event.GCGeneration].TotalAllocatedMB += _event.AllocedSinceLastGCMB;
-                    stats.Generations[_event.GCGeneration].MaxPauseDurationMSec = Math.Max(stats.Generations[_event.GCGeneration].MaxPauseDurationMSec, _event.PauseDurationMSec);
-                    stats.Generations[_event.GCGeneration].MaxSizePeakMB = Math.Max(stats.Generations[_event.GCGeneration].MaxSizePeakMB, _event.HeapSizePeakMB);
-                    stats.Generations[_event.GCGeneration].MaxAllocRateMBSec = Math.Max(stats.Generations[_event.GCGeneration].MaxAllocRateMBSec, _event.AllocRateMBSec);
-                    stats.Generations[_event.GCGeneration].MaxPauseDurationMSec = Math.Max(stats.Generations[_event.GCGeneration].MaxPauseDurationMSec, _event.PauseDurationMSec);
-                    stats.Generations[_event.GCGeneration].MaxSuspendDurationMSec = Math.Max(stats.Generations[_event.GCGeneration].MaxSuspendDurationMSec, _event._SuspendDurationMSec);
-
-                    // And the totals 
-                    stats.Total.GCCount++;
-                    if (isInduced)
-                        stats.Total.NumInduced++;
-                    if (PinnedObjectSizes != 0)
-                    {
-                        stats.Total.PinnedObjectSizes += PinnedObjectSizes;
-                        stats.Total.NumGCWithPinEvents++;
-                    }
-                    if (PinnedObjectPercentage != -1)
-                    {
-                        stats.Total.PinnedObjectPercentage += _event.GetPinnedObjectPercentage();
-                        stats.Total.NumGCWithPinPlugEvents++;
-                    }
-                    stats.Total.TotalGCCpuMSec += _event.GetTotalGCTime();
-                    stats.Total.TotalSizeAfterMB += _event.HeapSizeAfterMB;
-                    stats.Total.TotalPromotedMB += _event.PromotedMB;
-                    stats.Total.TotalSizePeakMB += _event.HeapSizePeakMB;
-                    stats.Total.TotalPauseTimeMSec += _event.PauseDurationMSec;
-                    stats.Total.TotalAllocatedMB += _event.AllocedSinceLastGCMB;
-                    stats.Total.MaxPauseDurationMSec = Math.Max(stats.Total.MaxPauseDurationMSec, _event.PauseDurationMSec);
-                    stats.Total.MaxSizePeakMB = Math.Max(stats.Total.MaxSizePeakMB, _event.HeapSizePeakMB);
-                    stats.Total.MaxAllocRateMBSec = Math.Max(stats.Total.MaxAllocRateMBSec, _event.AllocRateMBSec);
-                    stats.Total.MaxSuspendDurationMSec = Math.Max(stats.Total.MaxSuspendDurationMSec, _event._SuspendDurationMSec);
-                }
-            }
-        }
-
-#region private
-        protected virtual void Init(TraceEvent data)
-        {
-            ProcessID = data.ProcessID;
-            ProcessName = data.ProcessName;
-            isDead = false;
-        }
-        private GCEvent GetCurrentGC()
-        {
-            if (events.Count > 0)
-            {
-                if (!events[events.Count - 1].isComplete)
-                {
-                    return events[events.Count - 1];
-                }
-                else if (currentBGC != null)
-                {
-                    return currentBGC;
-                }
-            }
-
-            return null;
-        }
-
-        // This is the last GC in progress. We need this for server Background GC.
-        // See comments for lastCompletedGC.
-        private GCEvent GetLastGC()
-        {
-            GCEvent _event = GetCurrentGC();
-            if ((isServerGCUsed == 1) &&
-                (_event == null))
-            {
-                if (lastCompletedGC != null)
-                {
-                    Debug.Assert(lastCompletedGC.Type == GCType.BackgroundGC);
-                    _event = lastCompletedGC;
-                }
-            }
-
-            return _event;
-        }
-
-        private GCEvent GetLastBGC()
-        {
-            if (currentBGC != null)
-            {
-                return currentBGC;
-            }
-
-            if ((lastCompletedGC != null) && (lastCompletedGC.Type == GCType.BackgroundGC))
-            {
-                return lastCompletedGC;
-            }
-
-            // Otherwise we search till we find the last BGC if we have seen one.
-            for (int i = (events.Count - 1); i >= 0; i--)
-            {
-                if (events[i].Type == GCType.BackgroundGC)
-                {
-                    return events[i];
-                }
-            }
-
-            return null;
-        }
-
-        private void AddConcurrentPauseTime(GCEvent _event, double RestartEEMSec)
-        {
-            if (suspendThreadIDBGC > 0)
-            {
-                _event.PauseDurationMSec += RestartEEMSec - suspendTimeRelativeMSec;
-            }
-            else
-            {
-                Debug.Assert(_event.PauseDurationMSec == 0);
-                _event.PauseDurationMSec = RestartEEMSec - _event.PauseStartRelativeMSec;
-            }
-        }
-
-        private void AddServerGCThreadFromMark(int ThreadID, int HeapNum)
-        {
-            if (isServerGCUsed == 1)
-            {
-                Debug.Assert(heapCount > 1);
-
-                if (serverGCThreads.Count < heapCount)
-                {
-                    // I am seeing that sometimes we are not getting these events from all heaps
-                    // for a complete GC so I have to check for that.
-                    if (!serverGCThreads.ContainsKey(ThreadID))
-                    {
-                        serverGCThreads.Add(ThreadID, HeapNum);
-                    }
-                }
-            }
-        }
-
-        private void ProcessGlobalHistory(GCGlobalHeapHistoryTraceData data)
-        {
-            if (isServerGCUsed == -1)
-            {
-                // We detected whether we are using Server GC now.
-                isServerGCUsed = ((data.NumHeaps > 1) ? 1 : 0);
-                if (heapCount == -1)
-                {
-                    heapCount = data.NumHeaps;
-                }
-
-                if (isServerGCUsed == 1)
-                {
-                    serverGCThreads = new Dictionary<int, int>(data.NumHeaps);
-                }
-            }
-
-            GCEvent _event = GetLastGC();
-            if (_event != null)
-            {
-                _event.GlobalHeapHistory = (GCGlobalHeapHistoryTraceData)data.Clone();
-                _event.SetHeapCount(heapCount);
-            }
-        }
-
-        private void ProcessPerHeapHistory(GCPerHeapHistoryTraceData data)
-        {
-            if (!data.VersionRecognized)
-            {
-                GCVersionInfoMismatch = true;
-                return;
-            }
-
-            GCEvent _event = GetLastGC();
-            if (_event != null)
-            {
-                if (_event.PerHeapHistories == null)
-                    _event.PerHeapHistories = new List<GCPerHeapHistoryTraceData>();
-                _event.PerHeapHistories.Add((GCPerHeapHistoryTraceData)data.Clone());
-            }
-        }
-
-        public IList<GCEvent> Events
-        {
-            get
-            {
-                return events;
-            }
-        }
-
-        private List<GCEvent> events = new List<GCEvent>();
-
-        // The amount of memory allocated by the user threads. So they are divided up into gen0 and LOH allocations.
-        double[] allocTickCurrentMB = { 0.0, 0.0 };
-        double[] allocTickAtLastGC = { 0.0, 0.0 };
-        bool HasAllocTickEvents = false;
-        bool SeenBadAllocTick = false;
-
-        double lastRestartEndTimeRelativeMSec;
-
-        // EE can be suspended via different reasons. The only ones we care about are
-        // SuspendForGC(1) - suspending for GC start
-        // SuspendForGCPrep(6) - BGC uses it in the middle of a BGC.
-        // We need to filter out the rest of the suspend/resume events.
-        // Keep track of the last time we started suspending the EE.  Will use in 'Start' to set PauseStartRelativeMSec
-        int suspendThreadIDOther = -1;
-        int suspendThreadIDBGC = -1;
-        // This is either the user thread (in workstation case) or a server GC thread that called SuspendEE to do a GC
-        int suspendThreadIDGC = -1;
-        double suspendTimeRelativeMSec = -1;
-        double suspendEndTimeRelativeMSec = -1;
-
-        // This records the amount of CPU time spent at the end of last GC.
-        float ProcessCpuAtLastGC = 0;
-
-        // This is the BGC that's in progress as we are parsing. We need to remember this 
-        // so we can correctly attribute the suspension time.
-        GCEvent currentBGC = null;
-        Dictionary<int, object> backgroundGCThreads = null;
-        bool IsBGCThread(int threadID)
-        {
-            if (backgroundGCThreads != null)
-                return backgroundGCThreads.ContainsKey(threadID);
-            return false;
-        }
-
-        // I keep this for the purpose of server Background GC. Unfortunately for server background 
-        // GC we are firing the GCEnd/GCHeaps events and Global/Perheap events in the reversed order.
-        // This is so that the Global/Perheap events can still be attributed to the right BGC.
-        GCEvent lastCompletedGC = null;
-        // We don't necessarily have the GCSettings event (only fired at the beginning if we attach)
-        // So we have to detect whether we are running server GC or not.
-        // Till we get our first GlobalHeapHistory event which indicates whether we use server GC 
-        // or not this remains -1.
-        public int isServerGCUsed = -1;
-        public int heapCount = -1;
-        // This is the server GC threads. It's built up in the 2nd server GC we see. 
-        Dictionary<int, int> serverGCThreads = null;
-
-
-        internal bool m_detailedGCInfo;
-        int IsServerGCThread(int threadID)
-        {
-            int heapIndex;
-            if (serverGCThreads != null)
-            {
-                if (serverGCThreads.TryGetValue(threadID, out heapIndex))
-                {
-                    return heapIndex;
-                }
-            }
-            return -1;
-        }
-#endregion
-    }
-
-#if HAS_PRIVATE_GC_EVENTS
-    class BGCAllocWaitInfo
-    {
-        public double WaitStartRelativeMSec;
-        public double WaitStopRelativeMSec;
-        public BGCAllocWaitReason Reason;
-
-        public bool GetWaitTime(ref double pauseMSec)
-        {
-            if ((WaitStartRelativeMSec != 0) &&
-                (WaitStopRelativeMSec != 0))
-            {
-                pauseMSec = WaitStopRelativeMSec - WaitStartRelativeMSec;
-                return true;
-            }
-            return false;
-        }
-
-        public bool IsLOHWaitLong(double pauseMSecMin)
-        {
-            double pauseMSec = 0;
-            if (GetWaitTime(ref pauseMSec))
-            {
-                return (pauseMSec > pauseMSecMin);
-            }
-            return false;
-        }
-
-        public override string ToString()
-        {
-            if ((Reason == BGCAllocWaitReason.GetLOHSeg) ||
-                (Reason == BGCAllocWaitReason.AllocDuringSweep))
-            {
-                return "Waiting for BGC to thread free lists";
-            }
-            else
-            {
-                Debug.Assert(Reason == BGCAllocWaitReason.AllocDuringBGC);
-                return "Allocated too much during BGC, waiting for BGC to finish";
-            }
-        }
-    }
-#endif
-}
-
-#endif
diff --git a/tests/src/GC/Performance/Framework/Metrics/Builders/ThreadWorkSpan.cs b/tests/src/GC/Performance/Framework/Metrics/Builders/ThreadWorkSpan.cs
deleted file mode 100644 (file)
index 443641c..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if WINDOWS
-
-using Microsoft.Diagnostics.Tracing.Parsers.Kernel;
-
-namespace GCPerfTestFramework.Metrics.Builders
-{
-    /// <summary>
-    /// Span of thread work recorded by CSwitch or CPU Sample Profile events
-    /// </summary>
-    internal class ThreadWorkSpan
-    {
-        public int ThreadId;
-        public int ProcessId;
-        public string ProcessName;
-        public int ProcessorNumber;
-        public double AbsoluteTimestampMsc;
-        public double DurationMsc;
-        public int Priority = -1;
-        public int WaitReason = -1;
-
-        public ThreadWorkSpan(CSwitchTraceData switchData)
-        {
-            ProcessName = switchData.NewProcessName;
-            ThreadId = switchData.NewThreadID;
-            ProcessId = switchData.NewProcessID;
-            ProcessorNumber = switchData.ProcessorNumber;
-            AbsoluteTimestampMsc = switchData.TimeStampRelativeMSec;
-            Priority = switchData.NewThreadPriority;
-            WaitReason = (int)switchData.OldThreadWaitReason;
-        }
-
-        public ThreadWorkSpan(ThreadWorkSpan span)
-        {
-            ProcessName = span.ProcessName;
-            ThreadId = span.ThreadId;
-            ProcessId = span.ProcessId;
-            ProcessorNumber = span.ProcessorNumber;
-            AbsoluteTimestampMsc = span.AbsoluteTimestampMsc;
-            DurationMsc = span.DurationMsc;
-            Priority = span.Priority;
-            WaitReason = span.WaitReason;
-        }
-
-        public ThreadWorkSpan(SampledProfileTraceData sample)
-        {
-            ProcessName = sample.ProcessName;
-            ProcessId = sample.ProcessID;
-            ThreadId = sample.ThreadID;
-            ProcessorNumber = sample.ProcessorNumber;
-            AbsoluteTimestampMsc = sample.TimeStampRelativeMSec;
-            DurationMsc = 1;
-            Priority = 0;
-        }
-    }
-}
-
-#endif
diff --git a/tests/src/GC/Performance/Framework/Metrics/CollectGCMetricsAttribute.cs b/tests/src/GC/Performance/Framework/Metrics/CollectGCMetricsAttribute.cs
deleted file mode 100644 (file)
index fe9d243..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.Xunit.Performance.Sdk;
-using System;
-
-namespace GCPerfTestFramework.Metrics
-{
-    /// <summary>
-    /// This attribute marks a xunit-performance test artifact as requiring GC metrics. When this attribute adorns
-    /// a test artifact, xunit-performance creates an instance of <see cref="GCMetricDiscoverer"/> and uses
-    /// it to populate the list of metrics provided for that artifact.
-    /// </summary>
-    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly)]
-#if WINDOWS
-    [PerformanceMetricDiscoverer("GCPerfTestFramework.Metrics.GCMetricDiscoverer", "GCPerfTestFramework")]
-#endif
-    public class CollectGCMetricsAttribute : 
-        Attribute
-#if WINDOWS
-        , IPerformanceMetricAttribute
-#endif
-    {
-    }
-}
diff --git a/tests/src/GC/Performance/Framework/Metrics/GCMetricDiscoverer.cs b/tests/src/GC/Performance/Framework/Metrics/GCMetricDiscoverer.cs
deleted file mode 100644 (file)
index 0f4f7cd..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if WINDOWS
-
-using GCPerfTestFramework.Metrics.Builders;
-using Microsoft.Diagnostics.Tracing;
-using Microsoft.Diagnostics.Tracing.Parsers;
-using Microsoft.Xunit.Performance;
-using Microsoft.Xunit.Performance.Sdk;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using Xunit.Abstractions;
-
-namespace GCPerfTestFramework.Metrics
-{
-    /// <summary>
-    /// GCMetricDiscoverer is one of two publicly-exposed classes from the library and is the
-    /// portion of this library that speaks directly to xunit-performance. When a
-    /// <see cref="CollectGCMetricsAttribute"/> is observed when xunit-performance is enumerating
-    /// the attributes on a test method, it instantiates an instance of this class and calls
-    /// GetMetrics on it, which yields the list of metrics that this library provides.
-    /// 
-    /// This class and <see cref="CollectGCMetricsAttribute"/> should be the *only* classes
-    /// exposed by this namespace.
-    /// </summary>
-    public class GCMetricDiscoverer : IPerformanceMetricDiscoverer
-    {
-        /// <summary>
-        /// Yields all current custom GC metrics.
-        /// </summary>
-        /// <param name="metricAttribute">Unused.</param>
-        /// <returns>An enumerator yielding new instances of all of the existing custom GC metrics.</returns>
-        public IEnumerable<PerformanceMetricInfo> GetMetrics(IAttributeInfo metricAttribute)
-        {
-            yield return new GCMaxPauseMetric();
-            yield return new GCMeanPauseMetric();
-            yield return new GCPeakVirtualMemoryMetric();
-            yield return new GCPeakWorkingSetMetric();
-            yield return new GCTotalPauseTimeMetric();
-            yield return new GCCpuTimeInGCMetric();
-            yield return new GCGenZeroMeanPauseDuration();
-            yield return new GCGenOneMeanPauseDuration();
-            yield return new GCGenTwoMeanPauseDuration();
-            yield return new GCGenZeroCount();
-            yield return new GCGenOneCount();
-            yield return new GCGenTwoBGCCount();
-            yield return new GCGenTwoGCCount();
-        }
-    }
-    
-    /// <summary>
-    /// Base class for all GC-related metrics that handles provider registration for child metrics, since
-    /// all GC-related metrics will be listening to the same trace providers.
-    /// </summary>
-    internal abstract class GCMetric : PerformanceMetric
-    {
-        /// <summary>
-        /// Number of bytes in a megabyte, for convenience.
-        /// </summary>
-        public const int BytesInMegabyte = 1048576;
-
-        /// <summary>
-        /// Creates a new GCMetric with the given ID, display name, and unit.
-        /// </summary>
-        /// <param name="id">The ID of the metric</param>
-        /// <param name="displayName">A human-friendly display name of the metric</param>
-        /// <param name="unit">The unit of the metric</param>
-        public GCMetric(string id, string displayName, string unit)
-            : base(id, displayName, unit)
-        {
-        }
-
-        /// <summary>
-        /// Indicates to xunit-performance what trace providers that these metrics
-        /// require.
-        /// </summary>
-        public override IEnumerable<ProviderInfo> ProviderInfo
-        {
-            get
-            {
-                yield return new KernelProviderInfo()
-                {
-                    Keywords = (ulong)(KernelTraceEventParser.Keywords.ContextSwitch
-                        | KernelTraceEventParser.Keywords.Profile
-                        | KernelTraceEventParser.Keywords.ProcessCounters)
-                };
-                yield return new UserProviderInfo()
-                {
-                    ProviderGuid = ClrTraceEventParser.ProviderGuid,
-                    Level = TraceEventLevel.Verbose,
-                    Keywords = (ulong)ClrTraceEventParser.Keywords.GC
-                };
-            }
-        }
-
-        /// <summary>
-        /// Constructs a new PerformanceMetricEvaluator for this metric. Implementors of a custom metric must override
-        /// this method and instruct it to instantiate the GCEvaluator for that custom metric.
-        /// </summary>
-        /// <param name="context"></param>
-        /// <returns></returns>
-        public abstract override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context);
-    }
-
-    /// <summary>
-    /// Base class for all GC-related metric evaluators that handles the complexity of multiplexing possibly many
-    /// GC metrics on top of a single "trace session" using a reference-counting strategy.
-    /// </summary>
-    internal abstract class GCEvaluator : PerformanceMetricEvaluator
-    {
-        /// <summary>
-        /// The sample rate used by xunit-performance when collecting ETW traces. Used
-        /// to infer the total time spent in GC based on CPU samples.
-        /// </summary>
-        const float SampleRate = 1.0f;
-
-        // These three fields are part of a bit of a hack to avoid having to re-parse the ETL file
-        // every time a new metric is evaluated.
-        //
-        // The idea here is that every class that derives from GCEvaluator increments the
-        // reference count whenever an iteration begins and decrements it whenever an iteration ends.
-        // When the reference count is zero, the session is nulled out for the next iteration.
-        // If _session is null when an iteration begins, the first metric to reach it will set it up
-        // to trace the session. In this way, the first metric in sets up the session and the last one
-        // out tears it down in preparation for the next iteration.
-        //
-        // This scheme is not thread-safe and will break if xunit-performance ever runs benchmarks in
-        // parallel, although that's pretty unlikely for a benchmarking framework.
-        private static IDictionary<int, GCProcess> s_session;
-        private static int s_sessionRefCount;
-        private static bool s_hasComputedRollup;
-
-        private readonly PerformanceMetricEvaluationContext _context;
-
-        /// <summary>
-        /// Property exposed to child metrics that automatically ensures that the session is valid and that
-        /// rollup information has been calculated, calculating it if it has not happened already.
-        /// </summary>
-        /// <exception cref="InvalidOperationException">
-        /// Thrown if this property is unable to determine an
-        /// appropriate process for analysis. Usually this occurs when
-        /// the test framework itself crashes and fails to launch a test.
-        /// </exception>
-        protected GCProcess ProcessInfo
-        {
-            get
-            {
-                if (!s_hasComputedRollup)
-                {
-                    GCProcess.ComputeRollup(s_session);
-                    s_hasComputedRollup = true;
-                }
-
-                // Since we are spawning this process with UseShellExecute set to false,
-                // the spawned process itself spawns an instance of "conhost.exe" on Windows.
-                // We want to be sure we don't pick out that one for analysis.
-                foreach (var candidate in s_session.Values)
-                {
-                    if (candidate.CommandLine != null)
-                    {
-                        if (!candidate.CommandLine.Contains("conhost.exe"))
-                        {
-                            return candidate;
-                        }
-                    }
-                }
-
-                // This should never happen in GC-related tests, which are always required to spawn an additional process.
-                throw new InvalidOperationException("Failed to find an appropriate target process for analysis!");
-            }
-        }
-
-        /// <summary>
-        /// Constructs a new GCEvaluator and sets its content to the given PerformanceMetricEvaluationContext.
-        /// </summary>
-        /// <param name="context">The context received from the test framework</param>
-        public GCEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            Debug.Assert(context.TraceEventSource is TraceEventDispatcher);
-            _context = context;
-        }
-
-        /// <summary>
-        /// Creates a session if it does not exist and increments the reference count on the session.
-        /// </summary>
-        /// <param name="beginEvent">Unused.</param>
-        public override void BeginIteration(TraceEvent beginEvent)
-        {
-            if (s_session == null)
-            {
-                // The filter function here is to filter out events that we are not concerned with collecting, i.e. events from
-                // processes not spawned by us.
-                s_session = GCProcess.Collect(_context.TraceEventSource as TraceEventDispatcher, SampleRate, filterFunc: _context.IsTestEvent);
-                s_hasComputedRollup = false;
-            }
-
-            s_sessionRefCount++;
-        }
-
-        /// <summary>
-        /// Yields the metric and decrements the reference count on the session, disposing it
-        /// if the reference count is zero.
-        /// </summary>
-        /// <param name="endEvent">Unused.</param>
-        /// <returns>The value of the metric calculated by this class</returns>
-        public override double EndIteration(TraceEvent endEvent)
-        {
-            var metric = YieldMetric();
-            s_sessionRefCount--;
-            if (s_sessionRefCount == 0)
-            {
-                s_session = null;
-
-                // not doing this results in tremendous memory leaks!
-                _context.TraceEventSource.Kernel.RemoveCallback<TraceEvent>(null);
-                _context.TraceEventSource.Clr.RemoveCallback<TraceEvent>(null);
-            }
-
-            return metric;
-        }
-
-        /// <summary>
-        /// Overriden by child metrics to determine how to yield the value of the metric
-        /// that the child metric provides. In general, overriders of this method
-        /// do something with the value of the <see cref="ProcessInfo"/> property.
-        /// </summary>
-        /// <returns>The value of this metric</returns>
-        protected abstract double YieldMetric();
-    }
-}
-
-#endif
diff --git a/tests/src/GC/Performance/Framework/Metrics/GCMetrics.cs b/tests/src/GC/Performance/Framework/Metrics/GCMetrics.cs
deleted file mode 100644 (file)
index 7c10849..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#if WINDOWS
-
-using System.Linq;
-using Microsoft.Xunit.Performance.Sdk;
-using Microsoft.Diagnostics.Tracing.Parsers.Clr;
-
-/// <summary>
-/// This file contains a number of GC-related metrics that are provided to xunit-performance.
-/// Each one of these derives from GCMetric, which manages the creation of the GC object model
-/// from an ETL trace - these classes are only responsible for using it to produce a meaningful
-/// metric.
-/// 
-/// Each one of these metrics should be fairly self-explanatory.
-/// </summary>
-namespace GCPerfTestFramework.Metrics
-{
-    #region Maximum Pause Duration
-    internal class GCMaxPauseMetric : GCMetric
-    {
-        public GCMaxPauseMetric()
-            : base("GCMaxPause", "Maximum GC Pause Duraction", PerformanceMetricUnits.Milliseconds)
-        {
-
-        }
-
-        public override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            return new GCMaxPauseEvaluator(context);
-        }
-    }
-
-    internal class GCMaxPauseEvaluator : GCEvaluator
-    {
-        public GCMaxPauseEvaluator(PerformanceMetricEvaluationContext context)
-            : base(context)
-        {
-
-        }
-
-        protected override double YieldMetric()
-        {
-            return ProcessInfo.Total.MaxPauseDurationMSec;
-        }
-    }
-    #endregion
-
-    #region Mean Pause Duration
-    internal class GCMeanPauseMetric : GCMetric
-    {
-        public GCMeanPauseMetric()
-            : base("GCMeanPause", "Mean GC Pause Duraction", PerformanceMetricUnits.Milliseconds)
-        {
-
-        }
-
-        public override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            return new GCMeanPauseEvaluator(context);
-        }
-    }
-
-    internal class GCMeanPauseEvaluator : GCEvaluator
-    {
-        public GCMeanPauseEvaluator(PerformanceMetricEvaluationContext context)
-            : base(context)
-        {
-
-        }
-
-        protected override double YieldMetric()
-        {
-            return ProcessInfo.Total.MeanPauseDurationMSec;
-        }
-    }
-    #endregion
-
-    #region Peak Virtual Memory Size
-    internal class GCPeakVirtualMemoryMetric : GCMetric
-    {
-        public GCPeakVirtualMemoryMetric()
-            : base("GCPeakVirtualMemory", "Process Peak Virtual Memory", PerformanceMetricUnits.Bytes)
-        {
-
-        }
-
-        public override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            return new GCPeakVirtualMemoryMetricEvaluator(context);
-        }
-    }
-
-    internal class GCPeakVirtualMemoryMetricEvaluator : GCEvaluator
-    {
-        public GCPeakVirtualMemoryMetricEvaluator(PerformanceMetricEvaluationContext context)
-            : base(context)
-        {
-
-        }
-
-        protected override double YieldMetric()
-        {
-            return ProcessInfo.PeakVirtualMB * GCMetric.BytesInMegabyte;
-        }
-    }
-    #endregion
-
-    #region Peak Working Set Size
-    internal class GCPeakWorkingSetMetric : GCMetric
-    {
-        public GCPeakWorkingSetMetric()
-            : base("GCPeakWorkingSet", "Process Peak Working Set", PerformanceMetricUnits.Bytes)
-        {
-
-        }
-
-        public override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            return new GCPeakWorkingSetMetricEvaluator(context);
-        }
-    }
-
-    internal class GCPeakWorkingSetMetricEvaluator : GCEvaluator
-    {
-        public GCPeakWorkingSetMetricEvaluator(PerformanceMetricEvaluationContext context)
-            : base(context)
-        {
-
-        }
-
-        protected override double YieldMetric()
-        {
-            return ProcessInfo.PeakWorkingSetMB * GCMetric.BytesInMegabyte;
-        }
-    }
-    #endregion
-
-    #region Total Pause Time
-    internal class GCTotalPauseTimeMetric : GCMetric
-    {
-        public GCTotalPauseTimeMetric()
-            : base("GCTotalPauseTime", "Total time spent paused due to GC activity", PerformanceMetricUnits.Milliseconds)
-        {
-
-        }
-
-        public override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            return new GCTotalPauseTimeMetricEvaluator(context);
-        }
-    }
-
-    internal class GCTotalPauseTimeMetricEvaluator : GCEvaluator
-    {
-        public GCTotalPauseTimeMetricEvaluator(PerformanceMetricEvaluationContext context)
-            : base(context)
-        {
-
-        }
-
-        protected override double YieldMetric()
-        {
-            return ProcessInfo.Total.TotalPauseTimeMSec;
-        }
-    }
-    #endregion
-
-    #region CPU time in GC
-    internal class GCCpuTimeInGCMetric : GCMetric
-    {
-        public GCCpuTimeInGCMetric()
-            : base("GCCpuTimeInGC", "Total CPU time spent in GC activity", PerformanceMetricUnits.Milliseconds)
-        {
-
-        }
-
-        public override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            return new GCCpuTimeInGCMetricEvaluator(context);
-        }
-    }
-
-    internal class GCCpuTimeInGCMetricEvaluator : GCEvaluator
-    {
-        public GCCpuTimeInGCMetricEvaluator(PerformanceMetricEvaluationContext context)
-            : base(context)
-        {
-
-        }
-
-        protected override double YieldMetric()
-        {
-            return ProcessInfo.Total.TotalGCCpuMSec;
-        }
-    }
-    #endregion
-
-    #region Generation Zero Mean Pause Duration
-    internal class GCGenZeroMeanPauseDuration : GCMetric
-    {
-        public GCGenZeroMeanPauseDuration()
-            : base("GCGenZeroMeanPauseDuration", "Mean pause duration for Gen0 collections", PerformanceMetricUnits.Count)
-        {
-
-        }
-
-        public override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            return new GCGenZeroMeanPauseDurationEvaluator(context);
-        }
-    }
-
-    internal class GCGenZeroMeanPauseDurationEvaluator : GCEvaluator
-    {
-        public GCGenZeroMeanPauseDurationEvaluator(PerformanceMetricEvaluationContext context)
-            : base(context)
-        {
-
-        }
-
-        protected override double YieldMetric()
-        {
-            return ProcessInfo.Generations[0].MeanPauseDurationMSec;
-        }
-    }
-    #endregion
-
-    #region Generation One Mean Pause Duration
-    internal class GCGenOneMeanPauseDuration : GCMetric
-    {
-        public GCGenOneMeanPauseDuration()
-            : base("GCGenOneMeanPauseDuration", "Mean pause duration for Gen1 collections", PerformanceMetricUnits.Count)
-        {
-
-        }
-
-        public override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            return new GCGenOneMeanPauseDurationEvaluator(context);
-        }
-    }
-
-    internal class GCGenOneMeanPauseDurationEvaluator : GCEvaluator
-    {
-        public GCGenOneMeanPauseDurationEvaluator(PerformanceMetricEvaluationContext context)
-            : base(context)
-        {
-
-        }
-
-        protected override double YieldMetric()
-        {
-            return ProcessInfo.Generations[1].MeanPauseDurationMSec;
-        }
-    }
-    #endregion
-
-    #region Generation Two Mean Pause Duration
-    internal class GCGenTwoMeanPauseDuration : GCMetric
-    {
-        public GCGenTwoMeanPauseDuration()
-            : base("GCGenTwoMeanPauseDuration", "Mean pause duration for Gen2 collections", PerformanceMetricUnits.Count)
-        {
-
-        }
-
-        public override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            return new GCGenTwoMeanPauseDurationEvaluator(context);
-        }
-    }
-
-    internal class GCGenTwoMeanPauseDurationEvaluator : GCEvaluator
-    {
-        public GCGenTwoMeanPauseDurationEvaluator(PerformanceMetricEvaluationContext context)
-            : base(context)
-        {
-
-        }
-
-        protected override double YieldMetric()
-        {
-            return ProcessInfo.Generations[2].MeanPauseDurationMSec;
-        }
-    }
-    #endregion
-
-    #region Generation Zero GC Count
-    internal class GCGenZeroCount : GCMetric
-    {
-        public GCGenZeroCount()
-            : base("GCGenZeroCount", "Number of Generation 0 GCs", PerformanceMetricUnits.Count)
-        {
-
-        }
-
-        public override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            return new GCGenZeroCountEvaluator(context);
-        }
-    }
-
-    internal class GCGenZeroCountEvaluator : GCEvaluator
-    {
-        public GCGenZeroCountEvaluator(PerformanceMetricEvaluationContext context)
-            : base(context)
-        {
-
-        }
-
-        protected override double YieldMetric()
-        {
-            return ProcessInfo.Generations[0].GCCount;
-        }
-    }
-    #endregion
-
-    #region Generation One GC Count
-    internal class GCGenOneCount : GCMetric
-    {
-        public GCGenOneCount()
-            : base("GCGenOneCount", "Number of Generation 1 GCs", PerformanceMetricUnits.Count)
-        {
-
-        }
-
-        public override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            return new GCGenOneCountEvaluator(context);
-        }
-    }
-
-    internal class GCGenOneCountEvaluator : GCEvaluator
-    {
-        public GCGenOneCountEvaluator(PerformanceMetricEvaluationContext context)
-            : base(context)
-        {
-
-        }
-
-        protected override double YieldMetric()
-        {
-            return ProcessInfo.Generations[1].GCCount;
-        }
-    }
-    #endregion
-
-    #region Generation 2 Background GC Count
-    internal class GCGenTwoBGCCount : GCMetric
-    {
-        public GCGenTwoBGCCount()
-            : base("GCGenTwoBGCCount", "Number of Generation 2 background GCs", PerformanceMetricUnits.Count)
-        {
-
-        }
-
-        public override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            return new GCGenTwoBGCCountEvaluator(context);
-        }
-    }
-
-    internal class GCGenTwoBGCCountEvaluator : GCEvaluator
-    {
-        public GCGenTwoBGCCountEvaluator(PerformanceMetricEvaluationContext context)
-            : base(context)
-        {
-
-        }
-
-        protected override double YieldMetric()
-        {
-            return ProcessInfo.Events.Count(e => e.Generation == 2 && e.Type == GCType.BackgroundGC);
-        }
-    }
-    #endregion
-
-    #region Generation 2 Blocking GC Count
-    internal class GCGenTwoGCCount : GCMetric
-    {
-        public GCGenTwoGCCount()
-            : base("GCGenTwoGCCount", "Number of Generation 2 blocking GCs", PerformanceMetricUnits.Count)
-        {
-
-        }
-
-        public override PerformanceMetricEvaluator CreateEvaluator(PerformanceMetricEvaluationContext context)
-        {
-            return new GCGenTwoGCCountEvaluator(context);
-        }
-    }
-
-    internal class GCGenTwoGCCountEvaluator : GCEvaluator
-    {
-        public GCGenTwoGCCountEvaluator(PerformanceMetricEvaluationContext context)
-            : base(context)
-        {
-
-        }
-
-        protected override double YieldMetric()
-        {
-            return ProcessInfo.Events.Count(e => e.Generation == 2 && e.Type == GCType.NonConcurrentGC);
-        }
-    }
-    #endregion
-}
-
-#endif
diff --git a/tests/src/GC/Performance/Framework/PerfTests.cs b/tests/src/GC/Performance/Framework/PerfTests.cs
deleted file mode 100644 (file)
index 3693e0b..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using GCPerfTestFramework.Metrics;
-using Microsoft.Xunit.Performance;
-using System.Collections.Generic;
-
-[assembly: CollectGCMetrics]
-
-namespace GCPerfTestFramework
-{
-    public class PerfTests
-    {
-        const string ConcurrentGC = "COMPLUS_gcConcurrent";
-        const string ServerGC = "COMPLUS_gcServer";
-
-        [Benchmark]
-        public void ClientSimulator_Concurrent()
-        {
-            var exe = ProcessFactory.ProbeForFile("GCSimulator.exe");
-            var env = new Dictionary<string, string>()
-            {
-                [ConcurrentGC] = "1"
-            };
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe, "-i 100", env);
-                }
-            }
-        }
-
-        [Benchmark]
-        public void ClientSimulator_Server()
-        {
-            var exe = ProcessFactory.ProbeForFile("GCSimulator.exe");
-            var env = new Dictionary<string, string>()
-            {
-                [ServerGC] = "1"
-            };
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe, "-i 100", env);
-                }
-            }
-        }
-
-        [Benchmark]
-        public void ClientSimulator_Server_One_Thread()
-        {
-            var exe = ProcessFactory.ProbeForFile("GCSimulator.exe");
-            var env = new Dictionary<string, string>()
-            {
-                [ServerGC] = "1"
-            };
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe, "-i 10 -notimer -dp 0.0", env);
-                }
-            }
-        }
-
-        [Benchmark]
-        public void ClientSimulator_Server_Two_Threads()
-        {
-            var exe = ProcessFactory.ProbeForFile("GCSimulator.exe");
-            var env = new Dictionary<string, string>()
-            {
-                [ServerGC] = "1"
-            };
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe, "-i 10 -notimer -dp 0.0 -t 2", env);
-                }
-            }
-        }
-
-        [Benchmark]
-        public void ClientSimulator_Server_Four_Threads()
-        {
-            var exe = ProcessFactory.ProbeForFile("GCSimulator.exe");
-            var env = new Dictionary<string, string>()
-            {
-                [ServerGC] = "1"
-            };
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe, "-i 10 -notimer -dp 0.0 -t 4", env);
-                }
-            }
-        }
-
-
-        [Benchmark]
-        public void LargeStringConcat()
-        {
-            var exe = ProcessFactory.ProbeForFile("LargeStrings.exe");
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe);
-                }
-            }
-        }
-
-        [Benchmark]
-        public void LargeStringConcat_Server()
-        {
-            var exe = ProcessFactory.ProbeForFile("LargeStrings.exe");
-            var env = new Dictionary<string, string>()
-            {
-                [ServerGC] = "1"
-            };
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe, environmentVariables: env);
-                }
-            }
-        }
-
-        [Benchmark]
-        public void LargeStringConcat_Workstation()
-        {
-            var exe = ProcessFactory.ProbeForFile("LargeStrings.exe");
-            var env = new Dictionary<string, string>()
-            {
-                [ServerGC] = "0"
-            };
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe, environmentVariables: env);
-                }
-            }
-        }
-
-        [Benchmark]
-        public void MidLife_Concurrent()
-        {
-            var exe = ProcessFactory.ProbeForFile("MidLife.exe");
-            var env = new Dictionary<string, string>()
-            {
-                [ConcurrentGC] = "1"
-            };
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe, environmentVariables: env);
-                }
-            }
-        }
-
-        [Benchmark]
-        public void MidLife_Server()
-        {
-            var exe = ProcessFactory.ProbeForFile("MidLife.exe");
-            var env = new Dictionary<string, string>()
-            {
-                [ServerGC] = "1"
-            };
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe, environmentVariables: env);
-                }
-            }
-        }
-
-        [Benchmark]
-        public void MidLife_Workstation()
-        {
-            var exe = ProcessFactory.ProbeForFile("MidLife.exe");
-            var env = new Dictionary<string, string>()
-            {
-                [ServerGC] = "0"
-            };
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe, environmentVariables: env);
-                }
-            }
-        }
-
-        [Benchmark]
-        public void ConcurrentSpin()
-        {
-            var exe = ProcessFactory.ProbeForFile("ConcurrentSpin.exe");
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe);
-                }
-            }
-        }
-
-        [Benchmark]
-        public void ConcurrentSpin_Server()
-        {
-            var exe = ProcessFactory.ProbeForFile("ConcurrentSpin.exe");
-            var env = new Dictionary<string, string>()
-            {
-                [ServerGC] = "1"
-            };
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe, environmentVariables: env);
-                }
-            }
-        }
-
-        [Benchmark]
-        public void ConcurrentSpin_Server_NonConcurrent()
-        {
-            var exe = ProcessFactory.ProbeForFile("ConcurrentSpin.exe");
-            var env = new Dictionary<string, string>()
-            {
-                [ServerGC] = "1",
-                [ConcurrentGC] = "0"
-            };
-
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe, environmentVariables: env);
-                }
-            }
-        }
-
-        [Benchmark]
-        public void ConcurrentSpin_Workstation()
-        {
-            var exe = ProcessFactory.ProbeForFile("ConcurrentSpin.exe");
-            var env = new Dictionary<string, string>()
-            {
-                [ServerGC] = "0",
-            };
-
-            foreach (var iteration in Benchmark.Iterations)
-            {
-                using (iteration.StartMeasurement())
-                {
-                    ProcessFactory.LaunchProcess(exe, environmentVariables: env);
-                }
-            }
-        }
-    }
-}
diff --git a/tests/src/GC/Performance/Framework/ProcessFactory.cs b/tests/src/GC/Performance/Framework/ProcessFactory.cs
deleted file mode 100644 (file)
index 206ef3b..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-
-namespace GCPerfTestFramework
-{
-    public static class ProcessFactory
-    {
-        const string ProbePathEnvironmentVariable = "GC_PERF_TEST_PROBE_PATH";
-        const string CoreRunProbePathEnvironmentVariable = "GC_PERF_TEST_CORE_RUN_PROBE_PATH";
-        const string UseCoreCLREnvironmentVariable = "GC_PERF_TEST_CORECLR";
-        const string ConcurrentGCVariable = "COMPLUS_gcConcurrent";
-        const string ServerGCVariable = "COMPLUS_gcServer";
-        const string CoreRunName = "CoreRun.exe";
-        const string UnixCoreRunName = "corerun";
-
-        // The default timeout for a test is half an hour. If a test takes that long, it is
-        // definitely not responding.
-        const int DefaultTimeout = 1800000 /* ms */;
-
-        /// <summary>
-        /// Location of the CoreRun hosting process, for use in CoreCLR performance runs
-        /// when the operating system can't launch a managed assembly directly. This runs
-        /// as part of the static constructor and so all tests will fail if CoreRun cannot
-        /// be found.
-        /// </summary>
-        private static string s_coreRun = LocateCoreRun();
-
-        /// <summary>
-        /// Launches a process that is part of a test scenario, waits for it complete, and returns.
-        ///  This API does several things specific to this test framework:
-        /// 
-        ///  1. The fileName argument is absolute, and must be resolved using executable probing:
-        ///     see <see cref="ProbeForFile"/> for more information. The reason why this function does not
-        ///     perform the probing is that this function is invoked while "on the clock" by the benchmarking process
-        ///     and file system probing is costly and only needs to be done once, before the test begins.
-        ///     The general pattern for perf tests is that the test executable is located before beginning the benchmark
-        ///     step to avoid doing file system lookups while on the clock.
-        ///  2. The arguments argument is passed verbatim to the Process that is spawned,
-        ///  3. The passed environment variables are set for the child process, replacing any variables
-        ///     in the existing process. xunit-performance by default turns off ConcurrentGC and ServerGC, 
-        ///     and we need to restore that when our process is completed.
-        ///  4. The timeout parameter controls how long this function will wait once a process is spawned.
-        ///     if the supplied timeout is less than or equal to zero, this function will wait indefinitely for the child process.
-        ///     If a process does timeout, this function throws a <see cref="TimeoutException"/>.
-        /// 
-        /// This method delegates partially to a platform-specific implementation which determines whether or not the operating
-        /// system is capable of executing a managed assembly directly or if a hosting process needs to be used.
-        /// Currently, this means that the executable will be directly executed on Desktop CLR, running on Windows, while
-        /// CoreCLR on any platform will need to invoke a hosting process.
-        /// </summary>
-        /// <param name="fileName">The absolute path to the executable to execute</param>
-        /// <param name="arguments">The arguments to pass to the executable</param>
-        /// <param name="environmentVariables">Any environment variables to pass to the child process</param>
-        /// <param name="timeout">How long to wait, in milliseconds, on the child process. If less than or equal to zero,
-        /// no timeout is used.</param>
-        /// <exception cref="TimeoutException">Thrown if the process takes longer than timout to terminate.</exception>
-        public static void LaunchProcess(
-            string fileName,
-            string arguments = "",
-            IDictionary<string, string> environmentVariables = null,
-            int timeout = DefaultTimeout)
-        {
-            var previousEnvironmentVars = new Dictionary<string, string>();
-
-            if (environmentVariables != null)
-            {
-                foreach (var pair in environmentVariables)
-                {
-                    var replacedValue = Environment.GetEnvironmentVariable(pair.Key);
-                    previousEnvironmentVars.Add(pair.Key, replacedValue);
-                    Environment.SetEnvironmentVariable(pair.Key, pair.Value);
-                }
-            }
-
-            try
-            {
-                Process process;
-
-                // for CoreCLR, we need to launch using the CoreRun hosting process.
-                if (ShouldUseCoreRun())
-                {
-                    process = LaunchProcessCoreClrImpl(fileName, arguments);
-                }
-                else
-                {
-                    process = LaunchProcessDesktopImpl(fileName, arguments);
-                }
-
-                if (timeout > 0)
-                {
-                    // the caller has specified a timeout. Use it.
-                    if (!process.WaitForExit(timeout))
-                    {
-                        process.Kill();
-                        throw new TimeoutException("Process did not complete within the allotted time");
-                    }
-
-                    return;
-                }
-
-                process.WaitForExit();
-            }
-            finally
-            {
-                // Restore the original environment variables
-                if (environmentVariables != null)
-                {
-                    foreach (var pair in previousEnvironmentVars)
-                    {
-                        Environment.SetEnvironmentVariable(pair.Key, pair.Value);
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// Launches a process directly by allowing the underlying operating system to invoke the managed
-        /// assembly.
-        /// </summary>
-        /// <param name="fileName">The absolute path of the executable to run</param>
-        /// <param name="arguments">The arguments to the target executable</param>
-        private static Process LaunchProcessDesktopImpl(string fileName, string arguments)
-        {
-            var process = new Process();
-            process.StartInfo.FileName = fileName;
-            process.StartInfo.Arguments = arguments;
-            process.StartInfo.UseShellExecute = false;
-            process.StartInfo.CreateNoWindow = false;
-            process.Start();
-            return process;
-        }
-
-        /// <summary>
-        /// Launches a process indirectly by invoking a hosting process that will invoke the given managed assembly.
-        /// This is usually called "corerun" for CoreCLR.
-        /// </summary>
-        /// <param name="fileName">The absolute path of the executable to run</param>
-        /// <param name="arguments">The arguments to the target executable</param>
-        private static Process LaunchProcessCoreClrImpl(string fileName, string arguments)
-        {
-            var process = new Process();
-            process.StartInfo.FileName = s_coreRun;
-            process.StartInfo.Arguments = fileName + " " + arguments;
-            process.StartInfo.UseShellExecute = false;
-            process.StartInfo.CreateNoWindow = false;
-            process.Start();
-            return process;
-        }
-
-        /// <summary>
-        /// Locates the CoreRun executable based on the probe path given in the CoreRunProbePathEnvironmentVariable
-        /// environment variable.
-        /// </summary>
-        /// <returns>The located path of CoreRun.exe</returns>
-        /// <exception cref="InvalidOperationException">If CoreRun.exe cannot be found on the given path.</exception>
-        private static string LocateCoreRun()
-        {
-            if (!ShouldUseCoreRun())
-            {
-                // no need to locate CoreRun if it won't be used.
-                return string.Empty;
-            }
-
-            var coreRunProbePath = Environment.GetEnvironmentVariable(CoreRunProbePathEnvironmentVariable);
-            if (coreRunProbePath == null)
-            {
-                throw new InvalidOperationException($"Environment variable {CoreRunProbePathEnvironmentVariable} must be set for CoreCLR performance runs!");
-            }
-
-            var path = ProbeForFileImpl(CoreRunName, coreRunProbePath);
-
-#if !WINDOWS
-            // CoreRun.exe may not have the .exe extension on non-Windows platforms.
-            if (path == null)
-            {
-                path = ProbeForFileImpl(UnixCoreRunName, coreRunProbePath);
-            }
-#endif
-
-            if (path == null)
-            {
-                throw new InvalidOperationException($"Failed to locate {CoreRunName} on search path {coreRunProbePath}");
-            }
-
-            return path;
-        }
-
-        private static bool ShouldUseCoreRun()
-        {
-#if WINDOWS
-            return Environment.GetEnvironmentVariable(UseCoreCLREnvironmentVariable) == "1";
-#else
-            return true;
-#endif
-        }
-
-        /// <summary>
-        /// Probes for a file named fileName starting recursively from the directory named in the ProbePathEnvironmentVariable.
-        /// </summary>
-        /// <param name="fileName">The filename to probe for</param>
-        /// <returns>An absolute path to the located file</returns>
-        /// <exception cref="InvalidOperationException">
-        /// If the probe path environment variable is not set, or the named file cannot be found
-        /// in the probe path.
-        /// </exception>
-        public static string ProbeForFile(string fileName)
-        {
-            var probePath = Environment.GetEnvironmentVariable(ProbePathEnvironmentVariable);
-            if (probePath == null)
-            {
-                // fall back to the current working directory if the probe path is not set
-                probePath = Directory.GetCurrentDirectory();
-            }
-
-            var path = ProbeForFileImpl(fileName, probePath);
-            if (path == null)
-            {
-                throw new InvalidOperationException($"Failed to locate file \"{ fileName }\" on path \"{probePath}\"");
-            }
-
-            return path;
-        }
-
-        /// <summary>
-        /// Starting at probePath, probe all files in that directory and all directories
-        /// recursively for a file named fileName. The filename equality check is case-insensitive.
-        /// </summary>
-        /// <param name="fileName">The name of the file to search for</param>
-        /// <param name="probePath">The directory to start the recursive search</param>
-        /// <returns>An absolute path to the file if found, or null if the file is not found.</returns>
-        private static string ProbeForFileImpl(string fileName, string probePath)
-        {
-            // probe from the top down - we don't want to waste lots of time doing a bottom up
-            // search in a deep directory tree if the files we are looking for are at the top-level.
-            foreach (var file in Directory.EnumerateFiles(probePath))
-            {
-                if (StringComparer.OrdinalIgnoreCase.Equals(Path.GetFileName(file), fileName))
-                {
-                    return file;
-                }
-            }
-
-            foreach (var directory in Directory.EnumerateDirectories(probePath))
-            {
-                var result = ProbeForFileImpl(fileName, directory);
-                if (result != null) return result;
-            }
-
-            return null;
-        }
-    }
-}
diff --git a/tests/src/GC/Performance/Framework/packages.config b/tests/src/GC/Performance/Framework/packages.config
deleted file mode 100644 (file)
index c43e175..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Microsoft.Diagnostics.Tracing.TraceEvent" version="1.0.41" targetFramework="net461" />
-  <package id="Microsoft.DotNet.xunit.performance" version="1.0.0-alpha-build0040" targetFramework="net461" />
-  <package id="Microsoft.DotNet.xunit.performance.metrics" version="1.0.0-alpha-build0040" targetFramework="net461" />
-  <package id="System.Collections" version="4.0.10" targetFramework="net461" />
-  <package id="System.Diagnostics.Debug" version="4.0.10" targetFramework="net461" />
-  <package id="System.Diagnostics.Tracing" version="4.1.0" targetFramework="net461" />
-  <package id="System.Globalization" version="4.0.10" targetFramework="net461" />
-  <package id="System.IO" version="4.1.0" targetFramework="net461" />
-  <package id="System.IO.FileSystem" version="4.0.0" targetFramework="net461" />
-  <package id="System.IO.FileSystem.Primitives" version="4.0.0" targetFramework="net461" />
-  <package id="System.Linq" version="4.1.0" targetFramework="net461" />
-  <package id="System.Reflection" version="4.1.0" targetFramework="net461" />
-  <package id="System.Runtime" version="4.1.0" targetFramework="net461" />
-  <package id="System.Runtime.Extensions" version="4.1.0" targetFramework="net461" />
-  <package id="System.Runtime.Handles" version="4.0.0" targetFramework="net461" />
-  <package id="System.Text.Encoding" version="4.0.10" targetFramework="net461" />
-  <package id="System.Threading" version="4.0.10" targetFramework="net461" />
-  <package id="System.Threading.Tasks" version="4.0.10" targetFramework="net461" />
-  <package id="xunit.abstractions" version="2.0.1-rc2" targetFramework="net461" />
-  <package id="xunit.extensibility.core" version="2.2.0-beta2-build3300" targetFramework="net461" />
-  <package id="xunit.extensibility.execution" version="2.2.0-beta2-build3300" targetFramework="net461" />
-</packages>
\ No newline at end of file
diff --git a/tests/src/GC/Performance/README.md b/tests/src/GC/Performance/README.md
deleted file mode 100644 (file)
index c38e9c7..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-# CLR Garbage Collector Performance Tests
-This folder houses both the test framework and test artifacts for performance tests
-targeting the garbage collector. These tests are run using the
-[xunit-performance](https://github.com/Microsoft/xunit-performance) performance testing
-framework and can be used with the standard tools provided by that repository.
-
-The performance tests themselves, as defined in the `Framework` folder in `PerfTests.cs`,
-all invoke one of the test artifacts (as defined in the `Tests` assembly) and collects the duration
-in which the child process runs, as well as a number of other metrics on Windows platforms.
-
-## Building the test framework
-The test framework currently does not build as part of the CoreCLR test build. The
-framework targets Desktop CLR and compiles using msbuild.
-
-The Desktop (DNX46) target of the test framework contains a number of custom metrics that are given
-to `xunit.performance` to evaluate the test run. These metrics provide a number of interesting
-statistics about the performance of the GC, like the duration of the longest pause, the average pause
-durations, and number of garbage collections for each generation.
-
-The CoreCLR (DNXCORE5) target of the test framework consists only of the tests themselves and not
-the metrics. This is because metric definitions have a dependency on TraceEvent, which is itself
-not available currently on CoreCLR. This target is temporarily disabled for now.
-
-## Running the tests on Windows
-Since the Desktop CLR is already installed on Windows machines, we can use the host CLR to
-invoke the `xunit.performance.run` test runner, even if we are testing CoreCLR.
-
-Regardless of whether or not we are testing the Desktop CLR or CoreCLR, we first need to set up
-the coreclr repo by building a build that we will be testing:
-
-```
-build.cmd Release
-tests\runtest.cmd Release GenerateLayoutOnly
-```
-
-Then, we create a temporary directory somewhere on our system and set up all of our dependencies:
-
-```
-mkdir sandbox
-pushd sandbox
-
-REM Get the xunit-performance console runner
-xcopy /sy C:\<path_to_your_coreclr>\coreclr\packages\Microsoft.DotNet.xunit.performance.runner.Windows\1.0.0-alpha-build0035\tools\* .
-
-REM Get the xunit-performance analysis engine
-xcopy /sy C:\<path_to_your_coreclr>\coreclr\packages\Microsoft.DotNet.xunit.performance.analysis\1.0.0-alpha-build0035\tools\* .
-
-REM Get the xunit console runner
-xcopy /sy C:\<path_to_your_coreclr>\coreclr\packages\xunit.runner.console\2.1.0\tools\* .
-
-REM Get the test executables' dependencies
-xcopy /sy C:\<path_to_your_coreclr>\coreclr\bin\tests\Windows_NT.x64.Release\Tests\Core_Root\* .
-
-REM Get the test executables themselves
-for /r C:\<path_to_your_coreclr>\coreclr\bin\tests\Windows_NT.x64.Release\GC\Performance\Tests\ %%f in (*) do xcopy /sy "%%f" .
-
-REM Get the test framework assembly
-xcopy /sy C:\<path_to_your_coreclr>\coreclr\tests\src\GC\Performance\Framework\bin\Release\* .
-
-REM Instruct the framework to 1) run using CoreRun (coreclr) and 2) find CoreRun in the current directory
-REM If not set, the framework will test the currently running Desktop CLR instead.
-set GC_PERF_TEST_CORECLR=1
-set GC_PERF_TEST_CORE_RUN_PROBE_PATH=.
-```
-
-Once all of our dependencies are in the same place, we can run the tests:
-```
-xunit.performance.run.exe GCPerfTestFramework.dll -runner xunit.console.exe -verbose -runid PerformanceTest
-```
-
-The result of this invocation will be `PerformanceTest.etl`, an ETW trace, and `PerformanceTest.xml`, a file
-containing a summary of every test run and the metrics that were calculated for every test iteration. A summary
-XML file can be created using the analysis executable:
-
-```
-xunit.performance.analysis.exe PerformanceTest.xml -xml PerformanceTestSummary.xml
-```
-
-This summary XML only contains test durations and discards all custom metrics.
-
-## Running on other platforms
-The GC performance test framework is temporarily not available on non-Windows platform. It will be brought to
-non-Windows platforms in the very near future!
-
-## Environment Variables
-On Windows, the test runner respects the following environment variables:
-* `GC_PERF_TEST_PROBE_PATH`, a path used to probe for test executables,
-* `GC_PERF_TEST_CORE_RUN_PROBE_PATH`, a path used to probe for the CoreRun executable if running on CoreCLR,
-* `GC_PERF_TEST_CORECLR`, instructs the runner to use CoreCLR (and CoreRun) if set to 1.
-
-On Unixes, the test runner respects the same variables except for the final variable, which is assumed to
-always be 1 on non-Windows platforms.
\ No newline at end of file