diff --git a/src/BenchmarkDotNet/Environments/HostEnvironmentInfo.cs b/src/BenchmarkDotNet/Environments/HostEnvironmentInfo.cs index cd0232b715..a2539462f0 100644 --- a/src/BenchmarkDotNet/Environments/HostEnvironmentInfo.cs +++ b/src/BenchmarkDotNet/Environments/HostEnvironmentInfo.cs @@ -6,6 +6,7 @@ using BenchmarkDotNet.Loggers; using BenchmarkDotNet.Portability; using BenchmarkDotNet.Portability.Cpu; +using BenchmarkDotNet.Portability.Memory; using BenchmarkDotNet.Properties; using BenchmarkDotNet.Toolchains.DotNetCli; using JetBrains.Annotations; @@ -41,6 +42,11 @@ public class HostEnvironmentInfo : BenchmarkEnvironmentInfo /// public Lazy CpuInfo { get; protected set; } + // + /// Provides total and free memory, Could be expensive + /// + public Lazy MemoryInfo { get; protected set; } + public string JitModules { get; protected set; } /// @@ -78,6 +84,7 @@ protected HostEnvironmentInfo() BenchmarkDotNetVersion = GetBenchmarkDotNetVersion(); OsVersion = new Lazy(RuntimeInformation.GetOsVersion); CpuInfo = new Lazy(RuntimeInformation.GetCpuInfo); + MemoryInfo = new Lazy(RuntimeInformation.GetMemoryInfo); ChronometerFrequency = Chronometer.Frequency; HardwareTimerKind = Chronometer.HardwareTimerKind; JitModules = RuntimeInformation.GetJitModulesInfo(); @@ -98,9 +105,13 @@ public override IEnumerable ToFormattedString() yield return $"{BenchmarkDotNetCaption}=v{BenchmarkDotNetVersion}, OS={OsVersion.Value}, VM={vmName}"; yield return CpuInfoFormatter.Format(CpuInfo.Value); + if (HardwareTimerKind != HardwareTimerKind.Unknown) yield return $"Frequency={ChronometerFrequency}, Resolution={ChronometerResolution}, Timer={HardwareTimerKind.ToString().ToUpper()}"; + if (MemoryInfo.Value != null) + yield return MemoryInfoFormatter.Format(MemoryInfo.Value); + if (RuntimeInformation.IsNetCore && IsDotNetCliInstalled()) yield return $".NET Core SDK={DotNetSdkVersion.Value}"; } diff --git a/src/BenchmarkDotNet/Portability/Cpu/SysctlCpuInfoProvider.cs b/src/BenchmarkDotNet/Portability/Cpu/SysctlCpuInfoProvider.cs index 893dc74c13..238bb31a15 100644 --- a/src/BenchmarkDotNet/Portability/Cpu/SysctlCpuInfoProvider.cs +++ b/src/BenchmarkDotNet/Portability/Cpu/SysctlCpuInfoProvider.cs @@ -5,7 +5,8 @@ namespace BenchmarkDotNet.Portability.Cpu { /// - /// CPU information from output of the `sysctl -a` command. + /// CPU information from output of the `sysctl -a` command. + /// It is cached by SysctlInfoProvider for reuse in memory and CPU /// MacOSX only. /// internal static class SysctlCpuInfoProvider @@ -17,7 +18,7 @@ private static CpuInfo Load() { if (RuntimeInformation.IsMacOSX()) { - string content = ProcessHelper.RunAndReadOutput("sysctl", "-a"); + string content = SysctlInfoProvider.SysctlInfo.Value; return SysctlCpuInfoParser.ParseOutput(content); } return null; diff --git a/src/BenchmarkDotNet/Portability/Memory/MemoryInfo.cs b/src/BenchmarkDotNet/Portability/Memory/MemoryInfo.cs new file mode 100644 index 0000000000..7a9fa38b73 --- /dev/null +++ b/src/BenchmarkDotNet/Portability/Memory/MemoryInfo.cs @@ -0,0 +1,14 @@ +namespace BenchmarkDotNet.Portability.Memory +{ + public class MemoryInfo + { + public MemoryInfo(long totalMemory, long freePhysicalMemory) + { + TotalMemory = totalMemory; + FreePhysicalMemory = freePhysicalMemory; + } + + public long TotalMemory { get; set; } + public long FreePhysicalMemory { get; set; } + } +} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Portability/Memory/MemoryInfoFormatter.cs b/src/BenchmarkDotNet/Portability/Memory/MemoryInfoFormatter.cs new file mode 100644 index 0000000000..e8b9735165 --- /dev/null +++ b/src/BenchmarkDotNet/Portability/Memory/MemoryInfoFormatter.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BenchmarkDotNet.Portability.Memory +{ + public class MemoryInfoFormatter + { + public static string Format(MemoryInfo memoryInfo) + { + string totalMemory = $"Total Memory={Math.Round((memoryInfo.TotalMemory) / (1024.0 * 1024.0), 2)} GB"; + string freeMemory = $"Available Memory={Math.Round(memoryInfo.FreePhysicalMemory / (1024.0 * 1024.0), 2)} GB"; + + return $"{totalMemory}, {freeMemory}"; + } + } +} diff --git a/src/BenchmarkDotNet/Portability/Memory/ProcMemoryInfoKeyNames.cs b/src/BenchmarkDotNet/Portability/Memory/ProcMemoryInfoKeyNames.cs new file mode 100644 index 0000000000..31e36b8ad8 --- /dev/null +++ b/src/BenchmarkDotNet/Portability/Memory/ProcMemoryInfoKeyNames.cs @@ -0,0 +1,10 @@ +namespace BenchmarkDotNet.Portability.Memory +{ + internal static class ProcMemoryInfoKeyNames + { + internal const string MemTotal = "MemTotal"; + internal const string MemAvailable = "MemAvailable"; + internal const string MemFree = "MemFree"; + internal const string Cached = "Cached"; + } +} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Portability/Memory/ProcMemoryInfoParser.cs b/src/BenchmarkDotNet/Portability/Memory/ProcMemoryInfoParser.cs new file mode 100644 index 0000000000..b8e1091543 --- /dev/null +++ b/src/BenchmarkDotNet/Portability/Memory/ProcMemoryInfoParser.cs @@ -0,0 +1,55 @@ +using BenchmarkDotNet.Helpers; +using JetBrains.Annotations; + +namespace BenchmarkDotNet.Portability.Memory +{ + internal static class ProcMemoryInfoParser + { + [CanBeNull] + internal static MemoryInfo ParseOutput([CanBeNull] string content) + { + var memoryInfoContent = SectionsHelper.ParseSections(content, ':'); + long TotalMemory = 0L; + long FreePhysicalMemory = 0L; + bool isValid = memoryInfoContent.Count > 0; + + foreach (var memory in memoryInfoContent) + { + if (memory.TryGetValue(ProcMemoryInfoKeyNames.MemTotal, out string totalMemoryValue) && + long.TryParse(totalMemoryValue.Replace("kB", string.Empty), out long totalMemory)) + { + TotalMemory += totalMemory; + } + else + { + isValid = false; + } + + if (memory.TryGetValue(ProcMemoryInfoKeyNames.MemAvailable, out string availablePhysicalMemoryValue) && + long.TryParse(availablePhysicalMemoryValue.Replace("kB", string.Empty), out long availablePhysicalMemory)) + { + FreePhysicalMemory += availablePhysicalMemory; + } + else + { + // Fallback for kernels < 3.14 where proc/meminfo does not provide "MemAvailable" + // calculated as Free + cached + if (memory.TryGetValue(ProcMemoryInfoKeyNames.MemFree, out string freePhysicalMemoryValue) && + long.TryParse(freePhysicalMemoryValue.Replace("kB", string.Empty), out long freePhysicalMemory) && + memory.TryGetValue(ProcMemoryInfoKeyNames.Cached, out string cachedMemoryValue) && + long.TryParse(cachedMemoryValue.Replace("kB", string.Empty), out long cachedMemory)) + { + FreePhysicalMemory += (freePhysicalMemory + cachedMemory); + } + else + { + isValid = false; + } + } + } + + var memoryInfo = isValid ? new MemoryInfo(TotalMemory, FreePhysicalMemory) : null; + return memoryInfo; + } + } +} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Portability/Memory/ProcMemoryInfoProvider.cs b/src/BenchmarkDotNet/Portability/Memory/ProcMemoryInfoProvider.cs new file mode 100644 index 0000000000..12e5b5eae7 --- /dev/null +++ b/src/BenchmarkDotNet/Portability/Memory/ProcMemoryInfoProvider.cs @@ -0,0 +1,28 @@ +using System; +using System.Linq; +using BenchmarkDotNet.Helpers; +using BenchmarkDotNet.Horology; +using JetBrains.Annotations; + +namespace BenchmarkDotNet.Portability.Memory +{ + /// + /// Memory information from output of the `cat /proc/meminfo` command. + /// Linux only. + /// + internal static class ProcMemoryInfoProvider + { + internal static readonly Lazy ProcMemoryInfo = new Lazy(Load); + + [CanBeNull] + private static MemoryInfo Load() + { + if (RuntimeInformation.IsLinux()) + { + string content = ProcessHelper.RunAndReadOutput("cat", "/proc/meminfo"); + return ProcMemoryInfoParser.ParseOutput(content); + } + return null; + } + } +} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Portability/Memory/SysctlMemoryInfoParser.cs b/src/BenchmarkDotNet/Portability/Memory/SysctlMemoryInfoParser.cs new file mode 100644 index 0000000000..f73910296c --- /dev/null +++ b/src/BenchmarkDotNet/Portability/Memory/SysctlMemoryInfoParser.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using BenchmarkDotNet.Helpers; +using JetBrains.Annotations; +#if !NETCOREAPP2_1 +using BenchmarkDotNet.Extensions; +#endif + +namespace BenchmarkDotNet.Portability.Memory +{ + internal static class SysctlMemoryInfoParser + { + [CanBeNull] + [SuppressMessage("ReSharper", "StringLiteralTypo")] + internal static MemoryInfo ParseOutput([CanBeNull] string systlContent, [CanBeNull] string vmStatContent) + { + var sysctl = SectionsHelper.ParseSection(systlContent, ':'); + var vmstat = SectionsHelper.ParseSection(vmStatContent, ':'); + long? TotalMemory = null; + long? FreePhysicalMemory = null; + + if (sysctl.TryGetValue("hw.memsize", out string totalMemoryValue) && long.TryParse(totalMemoryValue, out long totalMemory)) + { + // hw.memsize returns in bytes + TotalMemory = (long)(totalMemory/1024.0); + } + + // Available Memory = Free + Inactive + if (vmstat.TryGetValue("Pages free", out string freeMemoryValue) && long.TryParse(freeMemoryValue.Replace(".",string.Empty), out long freeMemory)) + { + // Pages are in 4K units + FreePhysicalMemory = freeMemory * 4; + } + if (vmstat.TryGetValue("Pages inactive", out string inactiveMemoryValue) && long.TryParse(inactiveMemoryValue.Replace(".", string.Empty), out long inactiveMemory)) + { + // Pages are in 4K units + FreePhysicalMemory += inactiveMemory * 4; + } + + if (TotalMemory.HasValue && FreePhysicalMemory.HasValue) + { + return new MemoryInfo(TotalMemory.Value, FreePhysicalMemory.Value); + } + else + { + return null; + } + } + } +} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Portability/Memory/SysctlMemoryInfoProvider.cs b/src/BenchmarkDotNet/Portability/Memory/SysctlMemoryInfoProvider.cs new file mode 100644 index 0000000000..5cf6b5e0ab --- /dev/null +++ b/src/BenchmarkDotNet/Portability/Memory/SysctlMemoryInfoProvider.cs @@ -0,0 +1,29 @@ +using System; +using BenchmarkDotNet.Helpers; +using BenchmarkDotNet.Portability.Cpu; +using JetBrains.Annotations; + +namespace BenchmarkDotNet.Portability.Memory +{ + /// + /// Memory information from output of the `sysctl -a` command. + /// It is cached by SysctlInfoProvider for reuse in memory and CPU + /// MacOSX only. + /// + internal static class SysctlMemoryInfoProvider + { + internal static readonly Lazy SysctlMemoryInfo = new Lazy(Load); + + [CanBeNull] + private static MemoryInfo Load() + { + if (RuntimeInformation.IsMacOSX()) + { + string sysctlContent = SysctlInfoProvider.SysctlInfo.Value; + string vmsStatContent = ProcessHelper.RunAndReadOutput("vm_stat"); + return SysctlMemoryInfoParser.ParseOutput(sysctlContent, vmsStatContent); + } + return null; + } + } +} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Portability/Memory/WmicMemoryInfoKeyNames.cs b/src/BenchmarkDotNet/Portability/Memory/WmicMemoryInfoKeyNames.cs new file mode 100644 index 0000000000..d2297f259e --- /dev/null +++ b/src/BenchmarkDotNet/Portability/Memory/WmicMemoryInfoKeyNames.cs @@ -0,0 +1,8 @@ +namespace BenchmarkDotNet.Portability.Memory +{ + internal static class WmicMemoryInfoKeyNames + { + internal const string FreePhysicalMemory = "FreePhysicalMemory"; + internal const string TotalVisibleMemorySize = "TotalVisibleMemorySize"; + } +} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Portability/Memory/WmicMemoryInfoParser.cs b/src/BenchmarkDotNet/Portability/Memory/WmicMemoryInfoParser.cs new file mode 100644 index 0000000000..69db0b3e98 --- /dev/null +++ b/src/BenchmarkDotNet/Portability/Memory/WmicMemoryInfoParser.cs @@ -0,0 +1,43 @@ +using BenchmarkDotNet.Helpers; +using JetBrains.Annotations; + +namespace BenchmarkDotNet.Portability.Memory +{ + internal static class WmicMemoryInfoParser + { + [CanBeNull] + internal static MemoryInfo ParseOutput([CanBeNull] string content) + { + var memoryInfoContent = SectionsHelper.ParseSections(content, '='); + long TotalMemory = 0L; + long FreePhysicalMemory = 0L; + bool isValid = memoryInfoContent.Count > 0; + + foreach (var memory in memoryInfoContent) + { + if (memory.TryGetValue(WmicMemoryInfoKeyNames.TotalVisibleMemorySize, out string totalMemoryValue) && + long.TryParse(totalMemoryValue, out long totalMemory)) + { + TotalMemory += totalMemory; + } + else + { + isValid = false; + } + + if (memory.TryGetValue(WmicMemoryInfoKeyNames.FreePhysicalMemory, out string freePhysicalMemoryValue) && + long.TryParse(freePhysicalMemoryValue, out long freePhysicalMemory)) + { + FreePhysicalMemory += freePhysicalMemory; + } + else + { + isValid = false; + } + } + + var memoryInfo = isValid ? new MemoryInfo(TotalMemory, FreePhysicalMemory) : null; + return memoryInfo; + } + } +} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Portability/Memory/wmicMemoryInfoProvider.cs b/src/BenchmarkDotNet/Portability/Memory/wmicMemoryInfoProvider.cs new file mode 100644 index 0000000000..d8589f9672 --- /dev/null +++ b/src/BenchmarkDotNet/Portability/Memory/wmicMemoryInfoProvider.cs @@ -0,0 +1,30 @@ +using BenchmarkDotNet.Helpers; +using JetBrains.Annotations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BenchmarkDotNet.Portability.Memory +{ + /// + /// Memory information from output of the `wmic OS get TotalVisibleMemorySize, FreePhysicalMemory /Format:List` command. + /// Windows only. + /// + internal static class WmicMemoryInfoProvider + { + internal static readonly Lazy WmicMemoryInfo = new Lazy(Load); + + [CanBeNull] + private static MemoryInfo Load() + { + if (RuntimeInformation.IsWindows()) + { + string content = ProcessHelper.RunAndReadOutput("wmic", "OS get TotalVisibleMemorySize, FreePhysicalMemory /Format:List"); + return WmicMemoryInfoParser.ParseOutput(content); + } + return null; + } + } +} diff --git a/src/BenchmarkDotNet/Portability/RuntimeInformation.cs b/src/BenchmarkDotNet/Portability/RuntimeInformation.cs index 6625b74473..f5efa3100b 100644 --- a/src/BenchmarkDotNet/Portability/RuntimeInformation.cs +++ b/src/BenchmarkDotNet/Portability/RuntimeInformation.cs @@ -13,6 +13,7 @@ using BenchmarkDotNet.Extensions; using BenchmarkDotNet.Helpers; using BenchmarkDotNet.Portability.Cpu; +using BenchmarkDotNet.Portability.Memory; using JetBrains.Annotations; using Microsoft.Win32; using RuntimeEnvironment = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment; @@ -155,6 +156,20 @@ internal static CpuInfo GetCpuInfo() return null; } + public static bool IsVistaAndAbove() => Version.Parse(RuntimeEnvironment.OperatingSystemVersion).Major >= 6; + + internal static MemoryInfo GetMemoryInfo() + { + if (IsWindows()) + return WmicMemoryInfoProvider.WmicMemoryInfo.Value; + if (IsLinux()) + return ProcMemoryInfoProvider.ProcMemoryInfo.Value; + if (IsMacOSX()) + return SysctlMemoryInfoProvider.SysctlMemoryInfo.Value; + + return null; + } + private static string GetNetCoreVersion() { var assembly = typeof(GCSettings).GetTypeInfo().Assembly; @@ -225,7 +240,7 @@ internal static Runtime GetCurrentRuntime() return Runtime.Core; if (IsCoreRT) return Runtime.CoreRT; - + throw new NotSupportedException("Unknown .NET Framework"); // todo: adam sitnik fix it } @@ -363,7 +378,7 @@ internal static ICollection GetAntivirusProducts() foreach (var o in data) { - var av = (ManagementObject) o; + var av = (ManagementObject)o; if (av != null) { string name = av["displayName"].ToString(); diff --git a/src/BenchmarkDotNet/Portability/SysctlInfoProvider.cs b/src/BenchmarkDotNet/Portability/SysctlInfoProvider.cs new file mode 100644 index 0000000000..7bd6873908 --- /dev/null +++ b/src/BenchmarkDotNet/Portability/SysctlInfoProvider.cs @@ -0,0 +1,34 @@ +using System; +using BenchmarkDotNet.Helpers; +using JetBrains.Annotations; + +namespace BenchmarkDotNet.Portability +{ + /// + /// CPU information from output of the `sysctl -a` command. + /// MacOSX only. + /// + internal static class SysctlInfoProvider + { + internal static readonly Lazy SysctlInfo = new Lazy(Load); + private static string sysctlInfo = null; + + [CanBeNull] + private static string Load() + { + // Check if value is already computed + if (sysctlInfo != null) + { + return sysctlInfo; + } + + if (RuntimeInformation.IsMacOSX()) + { + string content = ProcessHelper.RunAndReadOutput("sysctl", "-a"); + sysctlInfo = content; + return content; + } + return null; + } + } +} \ No newline at end of file diff --git a/tests/BenchmarkDotNet.Tests/BenchmarkDotNet.Tests.csproj b/tests/BenchmarkDotNet.Tests/BenchmarkDotNet.Tests.csproj index 773b56979c..f290126da6 100644 --- a/tests/BenchmarkDotNet.Tests/BenchmarkDotNet.Tests.csproj +++ b/tests/BenchmarkDotNet.Tests/BenchmarkDotNet.Tests.csproj @@ -39,5 +39,6 @@ + \ No newline at end of file diff --git a/tests/BenchmarkDotNet.Tests/Builders/HostEnvironmentInfoBuilder.cs b/tests/BenchmarkDotNet.Tests/Builders/HostEnvironmentInfoBuilder.cs index a550842277..4befe4d8d4 100644 --- a/tests/BenchmarkDotNet.Tests/Builders/HostEnvironmentInfoBuilder.cs +++ b/tests/BenchmarkDotNet.Tests/Builders/HostEnvironmentInfoBuilder.cs @@ -3,6 +3,7 @@ using BenchmarkDotNet.Horology; using BenchmarkDotNet.Portability; using BenchmarkDotNet.Portability.Cpu; +using BenchmarkDotNet.Portability.Memory; namespace BenchmarkDotNet.Tests.Builders { @@ -31,6 +32,8 @@ public class HostEnvironmentInfoBuilder maxFrequency: Frequency.FromMHz(3100), minFrequency: Frequency.FromMHz(3100)); + private MemoryInfo memoryInfo = new MemoryInfo(8309008, 2883320); + private VirtualMachineHypervisor virtualMachineHypervisor = HyperV.Default; public HostEnvironmentInfoBuilder WithVMHypervisor(VirtualMachineHypervisor hypervisor) @@ -55,7 +58,7 @@ public HostEnvironmentInfo Build() { return new MockHostEnvironmentInfo(architecture, benchmarkDotNetVersion, chronometerFrequency, configuration, dotNetSdkVersion, hardwareTimerKind, hasAttachedDebugger, hasRyuJit, isConcurrentGC, isServerGC, - jitInfo, jitModules, osVersion, cpuInfo, runtimeVersion, virtualMachineHypervisor); + jitInfo, jitModules, osVersion, cpuInfo, memoryInfo, runtimeVersion, virtualMachineHypervisor); } } @@ -64,7 +67,7 @@ internal class MockHostEnvironmentInfo : HostEnvironmentInfo public MockHostEnvironmentInfo( string architecture, string benchmarkDotNetVersion, Frequency chronometerFrequency, string configuration, string dotNetSdkVersion, HardwareTimerKind hardwareTimerKind, bool hasAttachedDebugger, bool hasRyuJit, bool isConcurrentGC, bool isServerGC, - string jitInfo, string jitModules, string osVersion, CpuInfo cpuInfo, + string jitInfo, string jitModules, string osVersion, CpuInfo cpuInfo, MemoryInfo memoryInfo, string runtimeVersion, VirtualMachineHypervisor virtualMachineHypervisor) { Architecture = architecture; @@ -81,6 +84,7 @@ public MockHostEnvironmentInfo( JitModules = jitModules; OsVersion = new Lazy(() => osVersion); CpuInfo = new Lazy(() => cpuInfo); + MemoryInfo = new Lazy(() => memoryInfo); RuntimeVersion = runtimeVersion; VirtualMachineHypervisor = new Lazy(() => virtualMachineHypervisor); } diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/CommonExporterApprovalTests.Exporters.Invariant.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/CommonExporterApprovalTests.Exporters.Invariant.approved.txt index 3f11a30a3f..c28a03b1f4 100644 --- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/CommonExporterApprovalTests.Exporters.Invariant.approved.txt +++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/CommonExporterApprovalTests.Exporters.Invariant.approved.txt @@ -5,6 +5,7 @@ AsciiDocExporter BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC +Total Memory=7.92 GB, Available Memory=2.75 GB [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION Job=LongRun IterationCount=100 LaunchCount=3 @@ -37,6 +38,7 @@ HtmlExporter BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC +Total Memory=7.92 GB, Available Memory=2.75 GB [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -360,6 +362,7 @@ MarkdownExporter-default
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -377,6 +380,7 @@ MarkdownExporter-atlassian
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -393,6 +397,7 @@ MarkdownExporter-console
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -410,6 +415,7 @@ MarkdownExporter-github
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -427,6 +433,7 @@ MarkdownExporter-stackoverflow
     BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
     MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
     Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+    Total Memory=7.92 GB, Available Memory=2.75 GB
       [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
     Job=LongRun  IterationCount=100  LaunchCount=3  
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/CommonExporterApprovalTests.Exporters.en-US.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/CommonExporterApprovalTests.Exporters.en-US.approved.txt
index 3f11a30a3f..c28a03b1f4 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/CommonExporterApprovalTests.Exporters.en-US.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/CommonExporterApprovalTests.Exporters.en-US.approved.txt
@@ -5,6 +5,7 @@ AsciiDocExporter
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -37,6 +38,7 @@ HtmlExporter
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -360,6 +362,7 @@ MarkdownExporter-default
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -377,6 +380,7 @@ MarkdownExporter-atlassian
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -393,6 +397,7 @@ MarkdownExporter-console
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -410,6 +415,7 @@ MarkdownExporter-github
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -427,6 +433,7 @@ MarkdownExporter-stackoverflow
     BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
     MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
     Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+    Total Memory=7.92 GB, Available Memory=2.75 GB
       [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
     Job=LongRun  IterationCount=100  LaunchCount=3  
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/CommonExporterApprovalTests.Exporters.ru-RU.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/CommonExporterApprovalTests.Exporters.ru-RU.approved.txt
index 3f11a30a3f..28629d8e11 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/CommonExporterApprovalTests.Exporters.ru-RU.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/CommonExporterApprovalTests.Exporters.ru-RU.approved.txt
@@ -5,6 +5,7 @@ AsciiDocExporter
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7,92 GB, Available Memory=2,75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -37,6 +38,7 @@ HtmlExporter
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7,92 GB, Available Memory=2,75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -360,6 +362,7 @@ MarkdownExporter-default
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7,92 GB, Available Memory=2,75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -377,6 +380,7 @@ MarkdownExporter-atlassian
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7,92 GB, Available Memory=2,75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -393,6 +397,7 @@ MarkdownExporter-console
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7,92 GB, Available Memory=2,75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -410,6 +415,7 @@ MarkdownExporter-github
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7,92 GB, Available Memory=2,75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 Job=LongRun  IterationCount=100  LaunchCount=3  
@@ -427,6 +433,7 @@ MarkdownExporter-stackoverflow
     BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
     MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
     Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+    Total Memory=7,92 GB, Available Memory=2,75 GB
       [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
     Job=LongRun  IterationCount=100  LaunchCount=3  
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.Invalid_MethodAndJobBaselines.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.Invalid_MethodAndJobBaselines.approved.txt
index 08031c1968..490909a7c6 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.Invalid_MethodAndJobBaselines.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.Invalid_MethodAndJobBaselines.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.Invalid_TwoJobBaselines.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.Invalid_TwoJobBaselines.approved.txt
index 55ac1a1dcc..63f52778cf 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.Invalid_TwoJobBaselines.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.Invalid_TwoJobBaselines.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.Invalid_TwoMethodBaselines.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.Invalid_TwoMethodBaselines.approved.txt
index c56e41fd25..4d5a0a0a4a 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.Invalid_TwoMethodBaselines.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.Invalid_TwoMethodBaselines.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.JobBaseline_MethodsJobs.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.JobBaseline_MethodsJobs.approved.txt
index fe2279c03d..17a01b403a 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.JobBaseline_MethodsJobs.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.JobBaseline_MethodsJobs.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.JobBaseline_MethodsParamsJobs.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.JobBaseline_MethodsParamsJobs.approved.txt
index a45c5a4c26..1718058d8e 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.JobBaseline_MethodsParamsJobs.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.JobBaseline_MethodsParamsJobs.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_Methods.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_Methods.approved.txt
index 138a114572..630940701a 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_Methods.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_Methods.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_MethodsJobs.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_MethodsJobs.approved.txt
index 7e196cdaf4..3611b6e783 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_MethodsJobs.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_MethodsJobs.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_MethodsParams.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_MethodsParams.approved.txt
index ac1b9cd829..8a6ea857b5 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_MethodsParams.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_MethodsParams.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_MethodsParamsJobs.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_MethodsParamsJobs.approved.txt
index 276704d992..8c6f783969 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_MethodsParamsJobs.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.MethodBaseline_MethodsParamsJobs.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs.approved.txt
index 6e9365ba77..da83d03861 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByAll.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByAll.approved.txt
index a9a7e1ef0e..4f596eb7d5 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByAll.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByAll.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByCategory.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByCategory.approved.txt
index 4e9b01ab2b..2f7ca26258 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByCategory.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByCategory.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByJob.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByJob.approved.txt
index 597e9fce79..26cd7d9a07 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByJob.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByJob.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByMethod.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByMethod.approved.txt
index 63ddcdeb23..8756463e86 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByMethod.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByMethod.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByParams.approved.txt b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByParams.approved.txt
index 87abf2722f..9770530c75 100644
--- a/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByParams.approved.txt
+++ b/tests/BenchmarkDotNet.Tests/Exporters/ApprovedFiles/MarkdownExporterApprovalTests.GroupExporterTest.NoBaseline_MethodsParamsJobs_GroupByParams.approved.txt
@@ -3,6 +3,7 @@
 BenchmarkDotNet=v0.10.x-mock, OS=Microsoft Windows NT 10.0.x.mock, VM=Hyper-V
 MockIntel Core i7-6700HQ CPU 2.60GHz (Max: 3.10GHz), 1 CPU, 8 logical and 4 physical cores
 Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
+Total Memory=7.92 GB, Available Memory=2.75 GB
   [Host] : Clr 4.0.x.mock, 64mock RyuJIT-v4.6.x.mock CONFIGURATION
 
 
diff --git a/tests/BenchmarkDotNet.Tests/Portability/Cpu/ProcCpuInfoParserTests.cs b/tests/BenchmarkDotNet.Tests/Portability/Cpu/ProcCpuInfoParserTests.cs
index 78138380d6..5a12b43118 100644
--- a/tests/BenchmarkDotNet.Tests/Portability/Cpu/ProcCpuInfoParserTests.cs
+++ b/tests/BenchmarkDotNet.Tests/Portability/Cpu/ProcCpuInfoParserTests.cs
@@ -37,7 +37,7 @@ public void MalformedTest()
         [Fact]
         public void TwoProcessorWithDifferentCoresCountTest()
         {
-            string cpuInfo = TestHelper.ReadTestFile("ProcCpuInfoProcessorWithDifferentCoresCount.txt");
+            string cpuInfo = TestHelper.ReadTestFile("ProcCpuInfoProcessorWithDifferentCoresCount.txt", "Cpu");
             var parser = ProcCpuInfoParser.ParseOutput(cpuInfo);
             Assert.Equal("Unknown processor with 2 cores and hyper threading, Unknown processor with 4 cores", parser.ProcessorName);
             Assert.Equal(2, parser.PhysicalProcessorCount);
@@ -52,7 +52,7 @@ public void TwoProcessorWithDifferentCoresCountTest()
         [Fact]
         public void RealOneProcessorTwoCoresTest()
         {
-            string cpuInfo = TestHelper.ReadTestFile("ProcCpuInfoRealOneProcessorTwoCores.txt");
+            string cpuInfo = TestHelper.ReadTestFile("ProcCpuInfoRealOneProcessorTwoCores.txt", "Cpu");
             var parser = ProcCpuInfoParser.ParseOutput(cpuInfo);
             Assert.Equal("Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz", parser.ProcessorName);
             Assert.Equal(1, parser.PhysicalProcessorCount);
@@ -66,7 +66,7 @@ public void RealOneProcessorTwoCoresTest()
         [Fact]
         public void RealOneProcessorFourCoresTest()
         {
-            string cpuInfo = TestHelper.ReadTestFile("ProcCpuInfoRealOneProcessorFourCores.txt");
+            string cpuInfo = TestHelper.ReadTestFile("ProcCpuInfoRealOneProcessorFourCores.txt", "Cpu");
             var parser = ProcCpuInfoParser.ParseOutput(cpuInfo);
             Assert.Equal("Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz", parser.ProcessorName);
             Assert.Equal(1, parser.PhysicalProcessorCount);
diff --git a/tests/BenchmarkDotNet.Tests/Portability/Cpu/SysctlCpuInfoParserTests.cs b/tests/BenchmarkDotNet.Tests/Portability/Cpu/SysctlCpuInfoParserTests.cs
index a1d23f7ca8..04e9e23867 100644
--- a/tests/BenchmarkDotNet.Tests/Portability/Cpu/SysctlCpuInfoParserTests.cs
+++ b/tests/BenchmarkDotNet.Tests/Portability/Cpu/SysctlCpuInfoParserTests.cs
@@ -31,7 +31,7 @@ public void MalformedTest()
         [Fact]
         public void RealOneProcessorFourCoresTest()
         {
-            string cpuInfo = TestHelper.ReadTestFile("SysctlRealOneProcessorFourCores.txt");
+            string cpuInfo = TestHelper.ReadTestFile("SysctlRealOneProcessorFourCores.txt", "Cpu");
             var parser = SysctlCpuInfoParser.ParseOutput(cpuInfo);
             Assert.Equal("Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz", parser.ProcessorName);
             Assert.Equal(1, parser.PhysicalProcessorCount);
diff --git a/tests/BenchmarkDotNet.Tests/Portability/Memory/ProcMemoryInfoParserTests.cs b/tests/BenchmarkDotNet.Tests/Portability/Memory/ProcMemoryInfoParserTests.cs
new file mode 100644
index 0000000000..f61a6b18d9
--- /dev/null
+++ b/tests/BenchmarkDotNet.Tests/Portability/Memory/ProcMemoryInfoParserTests.cs
@@ -0,0 +1,42 @@
+using BenchmarkDotNet.Horology;
+using BenchmarkDotNet.Portability.Memory;
+using BenchmarkDotNet.Tests.Environments;
+using Xunit;
+
+namespace BenchmarkDotNet.Tests.Portability.Memory
+{
+    public class ProcMemoryInfoParserTests
+    {
+        [Fact]
+        public void EmptyTest()
+        {
+            var memoryInfo = ProcMemoryInfoParser.ParseOutput(string.Empty);
+            Assert.Null(memoryInfo);
+        }
+
+        [Fact]
+        public void MalformedTest()
+        {
+            var memoryInfo = ProcMemoryInfoParser.ParseOutput("malformedkey: malformedvalue\n\nmalformedkey2: malformedvalue2");
+            Assert.Null(memoryInfo);
+        }
+
+        [Fact]
+        public void RealMemoryTestWithAvaibleMemory()
+        {            
+            string MemoryInfo = TestHelper.ReadTestFile("ProcMemoryWithMemAvailable.txt", "Memory");
+            var parsedMemoryInfo = ProcMemoryInfoParser.ParseOutput(MemoryInfo);
+            Assert.Equal(6204328L, parsedMemoryInfo.FreePhysicalMemory);
+            Assert.Equal(32904420L, parsedMemoryInfo.TotalMemory);
+        }
+
+        [Fact]
+        public void RealMemoryTestWithoutAvailableMemory()
+        {
+            string MemoryInfo = TestHelper.ReadTestFile("ProcMemoryWithoutMemAvailable.txt", "Memory");
+            var parsedMemoryInfo = ProcMemoryInfoParser.ParseOutput(MemoryInfo);
+            Assert.Equal(4259532L, parsedMemoryInfo.FreePhysicalMemory);
+            Assert.Equal(32904420L, parsedMemoryInfo.TotalMemory);
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/BenchmarkDotNet.Tests/Portability/Memory/SysctlMemoryInfoParserTests.cs b/tests/BenchmarkDotNet.Tests/Portability/Memory/SysctlMemoryInfoParserTests.cs
new file mode 100644
index 0000000000..2c08eab0d9
--- /dev/null
+++ b/tests/BenchmarkDotNet.Tests/Portability/Memory/SysctlMemoryInfoParserTests.cs
@@ -0,0 +1,33 @@
+using BenchmarkDotNet.Horology;
+using BenchmarkDotNet.Portability.Memory;
+using Xunit;
+
+namespace BenchmarkDotNet.Tests.Portability.Memory
+{
+    public class SysctlMemoryInfoParserTests
+    {
+        [Fact]
+        public void EmptyTest()
+        {            
+            Assert.Null(SysctlMemoryInfoParser.ParseOutput(string.Empty, null));
+            Assert.Null(SysctlMemoryInfoParser.ParseOutput(null, string.Empty));            
+        }
+
+        [Fact]
+        public void MalformedTest()
+        {
+            var memoryInfo = SysctlMemoryInfoParser.ParseOutput("malformedkey:malformedvalue\n\nmalformedkey2=malformedvalue2", "malformedkey:malformedvalue\n\nmalformedkey2=malformedvalue2");
+            Assert.Null(memoryInfo);
+        }
+
+        [Fact]
+        public void RealMemoryTest()
+        {
+            string sysctlMemoryInfo = TestHelper.ReadTestFile("SysctlMemory.txt", "Memory");
+            string vmstatMemoryInfo = TestHelper.ReadTestFile("VmStatMemory.txt", "Memory");
+            var parsedMemoyInfo = SysctlMemoryInfoParser.ParseOutput(sysctlMemoryInfo, vmstatMemoryInfo);
+            Assert.Equal(327388, parsedMemoyInfo?.FreePhysicalMemory);
+            Assert.Equal(16777216, parsedMemoyInfo?.TotalMemory);
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/BenchmarkDotNet.Tests/Portability/Memory/TestFiles/ProcMemoryWithMemAvailable.txt b/tests/BenchmarkDotNet.Tests/Portability/Memory/TestFiles/ProcMemoryWithMemAvailable.txt
new file mode 100644
index 0000000000..3d4bece3fd
--- /dev/null
+++ b/tests/BenchmarkDotNet.Tests/Portability/Memory/TestFiles/ProcMemoryWithMemAvailable.txt
@@ -0,0 +1,48 @@
+MemTotal:       32904420 kB
+MemFree:          415612 kB
+MemAvailable:    6204328 kB
+Buffers:         1270516 kB
+Cached:          3843920 kB
+SwapCached:         1136 kB
+Active:         27942284 kB
+Inactive:        3192896 kB
+Active(anon):   23296324 kB
+Inactive(anon):  2192128 kB
+Active(file):    4645960 kB
+Inactive(file):  1000768 kB
+Unevictable:         232 kB
+Mlocked:             232 kB
+SwapTotal:       7999484 kB
+SwapFree:        7974908 kB
+Dirty:              1232 kB
+Writeback:             0 kB
+AnonPages:      26020568 kB
+Mapped:          2779036 kB
+Shmem:            969228 kB
+Slab:             841104 kB
+SReclaimable:     611448 kB
+SUnreclaim:       229656 kB
+KernelStack:       28480 kB
+PageTables:       153144 kB
+NFS_Unstable:          0 kB
+Bounce:                0 kB
+WritebackTmp:          0 kB
+CommitLimit:    24451692 kB
+Committed_AS:   40689380 kB
+VmallocTotal:   34359738367 kB
+VmallocUsed:           0 kB
+VmallocChunk:          0 kB
+HardwareCorrupted:     0 kB
+AnonHugePages:         0 kB
+ShmemHugePages:        0 kB
+ShmemPmdMapped:        0 kB
+CmaTotal:              0 kB
+CmaFree:               0 kB
+HugePages_Total:       0
+HugePages_Free:        0
+HugePages_Rsvd:        0
+HugePages_Surp:        0
+Hugepagesize:       2048 kB
+DirectMap4k:     3029980 kB
+DirectMap2M:    29440000 kB
+DirectMap1G:     1048576 kB
\ No newline at end of file
diff --git a/tests/BenchmarkDotNet.Tests/Portability/Memory/TestFiles/ProcMemoryWithoutMemAvailable.txt b/tests/BenchmarkDotNet.Tests/Portability/Memory/TestFiles/ProcMemoryWithoutMemAvailable.txt
new file mode 100644
index 0000000000..be94424e1a
--- /dev/null
+++ b/tests/BenchmarkDotNet.Tests/Portability/Memory/TestFiles/ProcMemoryWithoutMemAvailable.txt
@@ -0,0 +1,47 @@
+MemTotal:       32904420 kB
+MemFree:          415612 kB
+Buffers:         1270516 kB
+Cached:          3843920 kB
+SwapCached:         1136 kB
+Active:         27942284 kB
+Inactive:        3192896 kB
+Active(anon):   23296324 kB
+Inactive(anon):  2192128 kB
+Active(file):    4645960 kB
+Inactive(file):  1000768 kB
+Unevictable:         232 kB
+Mlocked:             232 kB
+SwapTotal:       7999484 kB
+SwapFree:        7974908 kB
+Dirty:              1232 kB
+Writeback:             0 kB
+AnonPages:      26020568 kB
+Mapped:          2779036 kB
+Shmem:            969228 kB
+Slab:             841104 kB
+SReclaimable:     611448 kB
+SUnreclaim:       229656 kB
+KernelStack:       28480 kB
+PageTables:       153144 kB
+NFS_Unstable:          0 kB
+Bounce:                0 kB
+WritebackTmp:          0 kB
+CommitLimit:    24451692 kB
+Committed_AS:   40689380 kB
+VmallocTotal:   34359738367 kB
+VmallocUsed:           0 kB
+VmallocChunk:          0 kB
+HardwareCorrupted:     0 kB
+AnonHugePages:         0 kB
+ShmemHugePages:        0 kB
+ShmemPmdMapped:        0 kB
+CmaTotal:              0 kB
+CmaFree:               0 kB
+HugePages_Total:       0
+HugePages_Free:        0
+HugePages_Rsvd:        0
+HugePages_Surp:        0
+Hugepagesize:       2048 kB
+DirectMap4k:     3029980 kB
+DirectMap2M:    29440000 kB
+DirectMap1G:     1048576 kB
\ No newline at end of file
diff --git a/tests/BenchmarkDotNet.Tests/Portability/Memory/TestFiles/SysctlMemory.txt b/tests/BenchmarkDotNet.Tests/Portability/Memory/TestFiles/SysctlMemory.txt
new file mode 100644
index 0000000000..5c0a601b77
--- /dev/null
+++ b/tests/BenchmarkDotNet.Tests/Portability/Memory/TestFiles/SysctlMemory.txt
@@ -0,0 +1,118 @@
+hw.ncpu: 8
+hw.byteorder: 1234
+hw.memsize: 17179869184
+hw.activecpu: 8
+hw.physicalcpu: 4
+hw.physicalcpu_max: 4
+hw.logicalcpu: 8
+hw.logicalcpu_max: 8
+hw.cputype: 7
+hw.cpusubtype: 8
+hw.cpu64bit_capable: 1
+hw.cpufamily: 280134364
+hw.cacheconfig: 8 2 2 8 0 0 0 0 0 0
+hw.cachesize: 17179869184 32768 262144 6291456 0 0 0 0 0 0
+hw.pagesize: 4096
+hw.pagesize32: 4096
+hw.busfrequency: 100000000
+hw.busfrequency_min: 100000000
+hw.busfrequency_max: 100000000
+hw.cpufrequency: 2200000000
+hw.cpufrequency_min: 2200000000
+hw.cpufrequency_max: 2200000000
+hw.cachelinesize: 64
+hw.l1icachesize: 32768
+hw.l1dcachesize: 32768
+hw.l2cachesize: 262144
+hw.l3cachesize: 6291456
+hw.tbfrequency: 1000000000
+hw.packages: 1
+hw.optional.floatingpoint: 1
+hw.optional.mmx: 1
+hw.optional.sse: 1
+hw.optional.sse2: 1
+hw.optional.sse3: 1
+hw.optional.supplementalsse3: 1
+hw.optional.sse4_1: 1
+hw.optional.sse4_2: 1
+hw.optional.x86_64: 1
+hw.optional.aes: 1
+hw.optional.avx1_0: 1
+hw.optional.rdrand: 1
+hw.optional.f16c: 1
+hw.optional.enfstrg: 1
+hw.optional.fma: 1
+hw.optional.avx2_0: 1
+hw.optional.bmi1: 1
+hw.optional.bmi2: 1
+hw.optional.rtm: 0
+hw.optional.hle: 0
+hw.optional.adx: 1
+hw.optional.mpx: 0
+hw.optional.sgx: 0
+hw.optional.avx512f: 0
+hw.optional.avx512cd: 0
+hw.optional.avx512dq: 0
+hw.optional.avx512bw: 0
+hw.optional.avx512vl: 0
+hw.optional.avx512ifma: 0
+hw.optional.avx512vbmi: 0
+hw.targettype: Mac
+hw.cputhreadtype: 1
+machdep.cpu.max_basic: 13
+machdep.cpu.max_ext: 2147483656
+machdep.cpu.vendor: GenuineIntel
+machdep.cpu.brand_string: Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
+machdep.cpu.family: 6
+machdep.cpu.model: 70
+machdep.cpu.extmodel: 4
+machdep.cpu.extfamily: 0
+machdep.cpu.stepping: 1
+machdep.cpu.feature_bits: 9221959987971750911
+machdep.cpu.leaf7_feature_bits: 10155
+machdep.cpu.extfeature_bits: 142473169152
+machdep.cpu.signature: 263777
+machdep.cpu.brand: 0
+machdep.cpu.features: FPU VME DE PSE TSC MSR PAE MCE CX8 APIC SEP MTRR PGE MCA CMOV PAT PSE36 CLFSH DS ACPI MMX FXSR SSE SSE2 SS HTT TM PBE SSE3 PCLMULQDQ DTES64 MON DSCPL VMX EST TM2 SSSE3 FMA CX16 TPR PDCM SSE4.1 SSE4.2 x2APIC MOVBE POPCNT AES PCID XSAVE OSXSAVE SEGLIM64 TSCTMR AVX1.0 RDRAND F16C
+machdep.cpu.leaf7_features: SMEP ERMS RDWRFSGS TSC_THREAD_OFFSET BMI1 AVX2 BMI2 INVPCID FPU_CSDS
+machdep.cpu.extfeatures: SYSCALL XD 1GBPAGE EM64T LAHF LZCNT RDTSCP TSCI
+machdep.cpu.logical_per_package: 16
+machdep.cpu.cores_per_package: 8
+machdep.cpu.microcode_version: 19
+machdep.cpu.processor_flag: 5
+machdep.cpu.mwait.linesize_min: 64
+machdep.cpu.mwait.linesize_max: 64
+machdep.cpu.mwait.extensions: 3
+machdep.cpu.mwait.sub_Cstates: 270624
+machdep.cpu.thermal.sensor: 1
+machdep.cpu.thermal.dynamic_acceleration: 1
+machdep.cpu.thermal.invariant_APIC_timer: 1
+machdep.cpu.thermal.thresholds: 2
+machdep.cpu.thermal.ACNT_MCNT: 1
+machdep.cpu.thermal.core_power_limits: 1
+machdep.cpu.thermal.fine_grain_clock_mod: 1
+machdep.cpu.thermal.package_thermal_intr: 1
+machdep.cpu.thermal.hardware_feedback: 0
+machdep.cpu.thermal.energy_policy: 1
+machdep.cpu.xsave.extended_state: 7 832 832 0
+machdep.cpu.xsave.extended_state1: 1 0 0 0
+machdep.cpu.arch_perf.version: 3
+machdep.cpu.arch_perf.number: 4
+machdep.cpu.arch_perf.width: 48
+machdep.cpu.arch_perf.events_number: 7
+machdep.cpu.arch_perf.events: 0
+machdep.cpu.arch_perf.fixed_number: 3
+machdep.cpu.arch_perf.fixed_width: 48
+machdep.cpu.cache.linesize: 64
+machdep.cpu.cache.L2_associativity: 8
+machdep.cpu.cache.size: 256
+machdep.cpu.tlb.inst.large: 8
+machdep.cpu.tlb.data.small: 64
+machdep.cpu.tlb.data.small_level1: 64
+machdep.cpu.tlb.shared: 1024
+machdep.cpu.address_bits.physical: 39
+machdep.cpu.address_bits.virtual: 48
+machdep.cpu.core_count: 4
+machdep.cpu.thread_count: 8
+machdep.cpu.tsc_ccc.numerator: 0
+machdep.cpu.tsc_ccc.denominator: 0
\ No newline at end of file
diff --git a/tests/BenchmarkDotNet.Tests/Portability/Memory/TestFiles/VmStatMemory.txt b/tests/BenchmarkDotNet.Tests/Portability/Memory/TestFiles/VmStatMemory.txt
new file mode 100644
index 0000000000..95d2084339
--- /dev/null
+++ b/tests/BenchmarkDotNet.Tests/Portability/Memory/TestFiles/VmStatMemory.txt
@@ -0,0 +1,12 @@
+Mach Virtual Memory Statistics: (page size of 4096 bytes) 
+Pages free:                     5538. 
+Pages active:                 142583. 
+Pages inactive:                76309. 
+Pages wired down:              37531. 
+"Translation faults":        4427933. 
+Pages copy-on-write:           54807. 
+Pages zero filled:           3086159. 
+Pages reactivated:              6533. 
+Pageins:                       46357. 
+Pageouts:                       4453. 
+Object cache: 66465 hits of 76770 lookups (86% hit rate)
\ No newline at end of file
diff --git a/tests/BenchmarkDotNet.Tests/Portability/Memory/WmicMemoryInfoParserTests.cs b/tests/BenchmarkDotNet.Tests/Portability/Memory/WmicMemoryInfoParserTests.cs
new file mode 100644
index 0000000000..3d3bb9969a
--- /dev/null
+++ b/tests/BenchmarkDotNet.Tests/Portability/Memory/WmicMemoryInfoParserTests.cs
@@ -0,0 +1,39 @@
+using BenchmarkDotNet.Horology;
+using BenchmarkDotNet.Portability.Memory;
+using Xunit;
+
+namespace BenchmarkDotNet.Tests.Portability.Memory
+{
+    public class WmicMemoryInfoParserTests
+    {
+        [Fact]
+        public void EmptyTest()
+        {
+            var memoryInfo = WmicMemoryInfoParser.ParseOutput(string.Empty);
+            Assert.Null(memoryInfo);
+        }
+
+        [Fact]
+        public void MalformedTest()
+        {
+            var memoryInfo = WmicMemoryInfoParser.ParseOutput("malformedkey=malformedvalue\n\nmalformedkey2=malformedvalue2");
+            Assert.Null(memoryInfo);           
+        }
+
+        [Fact]
+        public void RealMemoryTest()
+        {
+            string memoryInfo = @"
+
+FreePhysicalMemory=2597508
+TotalVisibleMemorySize=8309008
+
+
+
+";
+            var parsedMemoryInfo = WmicMemoryInfoParser.ParseOutput(memoryInfo);
+            Assert.Equal(8309008, parsedMemoryInfo.TotalMemory);
+            Assert.Equal(2597508, parsedMemoryInfo.FreePhysicalMemory);
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/BenchmarkDotNet.Tests/Portability/Cpu/TestHelper.cs b/tests/BenchmarkDotNet.Tests/Portability/TestHelper.cs
similarity index 75%
rename from tests/BenchmarkDotNet.Tests/Portability/Cpu/TestHelper.cs
rename to tests/BenchmarkDotNet.Tests/Portability/TestHelper.cs
index cd37a55826..3ce30f0931 100644
--- a/tests/BenchmarkDotNet.Tests/Portability/Cpu/TestHelper.cs
+++ b/tests/BenchmarkDotNet.Tests/Portability/TestHelper.cs
@@ -1,14 +1,14 @@
 using System.IO;
 using System.Reflection;
 
-namespace BenchmarkDotNet.Tests.Portability.Cpu
+namespace BenchmarkDotNet.Tests.Portability
 {
     public static class TestHelper
     {
-        public static string ReadTestFile(string name)
+        public static string ReadTestFile(string name, string deviceType)
         {
             var assembly = typeof(TestHelper).GetTypeInfo().Assembly;
-            string resourceName = $"{typeof(TestHelper).Namespace}.TestFiles.{name}";
+            string resourceName = $"{typeof(TestHelper).Namespace}.{deviceType}.TestFiles.{name}";
 
             using (var stream = assembly.GetManifestResourceStream(resourceName))
             using (var reader = new StreamReader(stream))