update to netcoreapp1.1 in order to get universal cross platform memory diagnoser
This commit is contained in:
Родитель
1022827bbb
Коммит
1e2d381b6a
|
@ -13,7 +13,7 @@
|
|||
"Microsoft.FSharp.Core.netcore": "1.0.0-*",
|
||||
"Microsoft.NETCore.App": {
|
||||
"type": "platform",
|
||||
"version": "1.0.0"
|
||||
"version": "1.1.0-preview1-001100-00"
|
||||
},
|
||||
"BenchmarkDotNet": {
|
||||
"target": "project"
|
||||
|
@ -31,7 +31,7 @@
|
|||
}
|
||||
},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"netcoreapp1.1": {
|
||||
"imports": [
|
||||
"portable-net45+win8",
|
||||
"dnxcore50",
|
||||
|
|
|
@ -33,14 +33,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"netcoreapp1.0": {
|
||||
"netcoreapp1.1": {
|
||||
"buildOptions": {
|
||||
"define": [ "CORE" ]
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"type": "platform",
|
||||
"version": "1.0.0"
|
||||
"version": "1.1.0-preview1-001100-00"
|
||||
},
|
||||
"System.ComponentModel.EventBasedAsync": "4.0.11"
|
||||
}
|
||||
|
|
|
@ -52,16 +52,12 @@ namespace BenchmarkDotNet.Diagnosers
|
|||
|
||||
public string GetValue(Summary summary, Benchmark benchmark)
|
||||
{
|
||||
#if CORE
|
||||
return "?";
|
||||
#else
|
||||
if (RuntimeInformation.IsMono())
|
||||
return "?";
|
||||
if (!results.ContainsKey(benchmark))
|
||||
return "N/A";
|
||||
|
||||
return results[benchmark].BytesAllocatedPerOperation.ToString("N0", HostEnvironmentInfo.MainCultureInfo);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using BenchmarkDotNet.Portability;
|
||||
|
||||
namespace BenchmarkDotNet.Engines
|
||||
|
@ -7,6 +8,8 @@ namespace BenchmarkDotNet.Engines
|
|||
{
|
||||
internal const string ResultsLinePrefix = "GC: ";
|
||||
|
||||
private static readonly Func<long> getAllocatedBytesForCurrentThread = GetAllocatedBytesForCurrentThread();
|
||||
|
||||
private GcStats(int gen0Collections, int gen1Collections, int gen2Collections, long allocatedBytes, long totalOperations)
|
||||
{
|
||||
Gen0Collections = gen0Collections;
|
||||
|
@ -50,7 +53,7 @@ namespace BenchmarkDotNet.Engines
|
|||
|
||||
internal static GcStats ReadInitial(bool isDiagnosticsEnabled)
|
||||
{
|
||||
// this might force GC.Collect, so we want to do this before collecting collections counts
|
||||
// this will force GC.Collect, so we want to do this before collecting collections counts
|
||||
long allocatedBytes = GetAllocatedBytes(isDiagnosticsEnabled);
|
||||
|
||||
return new GcStats(
|
||||
|
@ -68,7 +71,7 @@ namespace BenchmarkDotNet.Engines
|
|||
GC.CollectionCount(1),
|
||||
GC.CollectionCount(2),
|
||||
|
||||
// this might force GC.Collect, so we want to do this after collecting collections counts
|
||||
// this will force GC.Collect, so we want to do this after collecting collections counts
|
||||
// to exclude this single full forced collection from results
|
||||
GetAllocatedBytes(isDiagnosticsEnabled),
|
||||
0);
|
||||
|
@ -79,22 +82,34 @@ namespace BenchmarkDotNet.Engines
|
|||
|
||||
private static long GetAllocatedBytes(bool isDiagnosticsEnabled)
|
||||
{
|
||||
#if NETCOREAPP11 // when MS releases new version of .NET Runtime to nuget.org
|
||||
return GC.GetAllocatedBytesForCurrentThread(); // https://github.com/dotnet/corefx/pull/12489
|
||||
#elif CLASSIC
|
||||
if (!isDiagnosticsEnabled || RuntimeInformation.IsMono()) // Monitoring is not available in Mono, see http://stackoverflow.com/questions/40234948/how-to-get-the-number-of-allocated-bytes-
|
||||
if (!isDiagnosticsEnabled
|
||||
|| RuntimeInformation.IsMono()) // Monitoring is not available in Mono, see http://stackoverflow.com/questions/40234948/how-to-get-the-number-of-allocated-bytes-
|
||||
return 0;
|
||||
|
||||
// "This instance Int64 property returns the number of bytes that have been allocated by a specific
|
||||
// AppDomain. The number is accurate as of the last garbage collection." - CLR via C#
|
||||
// so we enforce GC.Collect here just to make sure we get accurate results
|
||||
GC.Collect();
|
||||
#if CORE
|
||||
return getAllocatedBytesForCurrentThread.Invoke();
|
||||
#elif CLASSIC
|
||||
|
||||
return AppDomain.CurrentDomain.MonitoringTotalAllocatedMemorySize;
|
||||
#else
|
||||
return 0; // currently for .NET Core
|
||||
#endif
|
||||
}
|
||||
|
||||
private static Func<long> GetAllocatedBytesForCurrentThread()
|
||||
{
|
||||
// for some versions of .NET Core this method is internal,
|
||||
// for some public and for others public and exposed ;)
|
||||
var method = typeof(GC).GetTypeInfo().GetMethod("GetAllocatedBytesForCurrentThread",
|
||||
BindingFlags.Public | BindingFlags.Static)
|
||||
?? typeof(GC).GetTypeInfo().GetMethod("GetAllocatedBytesForCurrentThread",
|
||||
BindingFlags.NonPublic | BindingFlags.Static);
|
||||
|
||||
return () => (long)method.Invoke(null, null);
|
||||
}
|
||||
|
||||
internal string ToOutputLine()
|
||||
=> $"{ResultsLinePrefix} {Gen0Collections} {Gen1Collections} {Gen2Collections} {AllocatedBytes} {TotalOperations}";
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using BenchmarkDotNet.Characteristics;
|
||||
using BenchmarkDotNet.Environments;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Loggers;
|
||||
using BenchmarkDotNet.Portability;
|
||||
|
@ -12,7 +10,7 @@ namespace BenchmarkDotNet.Toolchains.Core
|
|||
{
|
||||
public class CoreToolchain : Toolchain
|
||||
{
|
||||
private const string TargetFrameworkMoniker = "netcoreapp1.0";
|
||||
private const string TargetFrameworkMoniker = "netcoreapp1.1";
|
||||
|
||||
public static readonly IToolchain Instance = new CoreToolchain();
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace BenchmarkDotNet.Toolchains.DotNetCli
|
|||
|
||||
// don't forget to call, otherwise logger will not get any events
|
||||
process.BeginErrorReadLine();
|
||||
process.BeginOutputReadLine();
|
||||
|
||||
process.WaitForExit((int)timeout.TotalMilliseconds);
|
||||
|
||||
|
|
|
@ -51,34 +51,18 @@
|
|||
"System.Threading.Tasks.Extensions": "4.0.0"
|
||||
}
|
||||
},
|
||||
"netstandard1.5": {
|
||||
"netcoreapp1.1": {
|
||||
"buildOptions": {
|
||||
"define": [ "CORE" ]
|
||||
},
|
||||
"dependencies": {
|
||||
"System.Linq": "4.1.0",
|
||||
"System.Resources.ResourceManager": "4.0.1",
|
||||
"Microsoft.CSharp": "4.0.1",
|
||||
"Microsoft.Win32.Primitives": "4.0.1",
|
||||
"System.Console": "4.0.0",
|
||||
"System.Text.RegularExpressions": "4.1.0",
|
||||
"System.Threading": "4.0.11",
|
||||
"System.Reflection": "4.1.0",
|
||||
"System.Reflection.Primitives": "4.0.1",
|
||||
"System.Reflection.TypeExtensions": "4.1.0",
|
||||
"System.Threading.Tasks.Extensions": "4.0.0",
|
||||
"System.Threading.Thread": "4.0.0",
|
||||
"System.Diagnostics.Process": "4.1.0",
|
||||
"System.IO.FileSystem": "4.0.1",
|
||||
"System.Runtime.InteropServices.RuntimeInformation": "4.0.0",
|
||||
"Microsoft.NETCore.App": {
|
||||
"type": "platform",
|
||||
"version": "1.1.0-preview1-001100-00"
|
||||
},
|
||||
"System.Runtime.Serialization.Primitives": "4.1.1",
|
||||
"System.Diagnostics.Tools": "4.0.1",
|
||||
"System.Runtime.InteropServices": "4.1.0",
|
||||
"Microsoft.DotNet.InternalAbstractions": "1.0.0",
|
||||
"System.Reflection.Extensions": "4.0.1",
|
||||
"System.Diagnostics.Debug": "4.0.11",
|
||||
"System.Xml.XPath.XmlDocument": "4.0.1",
|
||||
"System.Collections.Concurrent": "4.0.12"
|
||||
"System.Xml.XPath.XmlDocument": "4.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"netstandard1.5": {
|
||||
"netcoreapp1.1": {
|
||||
"buildOptions": {
|
||||
"define": [ "CORE" ]
|
||||
},
|
||||
|
|
|
@ -2,32 +2,21 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Columns;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnosers;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Environments;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Running;
|
||||
using BenchmarkDotNet.Tests.Loggers;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using BenchmarkDotNet.Reports;
|
||||
|
||||
namespace BenchmarkDotNet.IntegrationTests
|
||||
{
|
||||
public class MemoryDiagnoserTests
|
||||
{
|
||||
private const string SkipAllocationsTests
|
||||
#if CORE
|
||||
= "Not supported for .NET Core yet";
|
||||
#else
|
||||
= null;
|
||||
#endif
|
||||
|
||||
private readonly ITestOutputHelper output;
|
||||
|
||||
public MemoryDiagnoserTests(ITestOutputHelper outputHelper)
|
||||
|
@ -40,19 +29,17 @@ namespace BenchmarkDotNet.IntegrationTests
|
|||
[Benchmark]public void Empty() { }
|
||||
[Benchmark]public byte[] EightBytes() => new byte[8];
|
||||
[Benchmark]public byte[] SixtyFourBytes() => new byte[64];
|
||||
[Benchmark]public byte[] ThousandBytes() => new byte[1000];
|
||||
}
|
||||
|
||||
[Fact(Skip = SkipAllocationsTests)]
|
||||
[Fact]
|
||||
public void MemoryDiagnoserIsAccurate()
|
||||
{
|
||||
double objectAllocationOverhead = IntPtr.Size * 3; // pointer to method table + object header word + pointer to the object
|
||||
AssertAllocations(typeof(AccurateAllocations), 100, new Dictionary<string, Predicate<double>>
|
||||
long objectAllocationOverhead = IntPtr.Size * 3; // pointer to method table + object header word + pointer to the object
|
||||
AssertAllocations(typeof(AccurateAllocations), 200, new Dictionary<string, Predicate<long>>
|
||||
{
|
||||
{ "Empty", allocatedBytes => allocatedBytes == 0 },
|
||||
{ "EightBytes", allocatedBytes => allocatedBytes == 8 + objectAllocationOverhead },
|
||||
{ "SixtyFourBytes", allocatedBytes => allocatedBytes == 64 + objectAllocationOverhead },
|
||||
{ "ThousandBytes", allocatedBytes => allocatedBytes == 1000 + objectAllocationOverhead }
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -74,10 +61,10 @@ namespace BenchmarkDotNet.IntegrationTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact(Skip = SkipAllocationsTests)]
|
||||
[Fact]
|
||||
public void MemoryDiagnoserDoesNotIncludeAllocationsFromSetupAndCleanup()
|
||||
{
|
||||
AssertAllocations(typeof(AllocatingSetupAndCleanup), 5, new Dictionary<string, Predicate<double>>
|
||||
AssertAllocations(typeof(AllocatingSetupAndCleanup), 100, new Dictionary<string, Predicate<long>>
|
||||
{
|
||||
{ "AllocateNothing", allocatedBytes => allocatedBytes == 0 }
|
||||
});
|
||||
|
@ -88,17 +75,17 @@ namespace BenchmarkDotNet.IntegrationTests
|
|||
[Benchmark]public void EmptyMethod() { }
|
||||
}
|
||||
|
||||
[Fact(Skip = SkipAllocationsTests)]
|
||||
[Fact]
|
||||
public void EngineShouldNotInterfereAllocationResults()
|
||||
{
|
||||
AssertAllocations(typeof(NoAllocationsAtAll), 100, new Dictionary<string, Predicate<double>>
|
||||
AssertAllocations(typeof(NoAllocationsAtAll), 100, new Dictionary<string, Predicate<long>>
|
||||
{
|
||||
{ "EmptyMethod", allocatedBytes => allocatedBytes == 0 }
|
||||
});
|
||||
}
|
||||
|
||||
private void AssertAllocations(Type benchmarkType, int targetCount,
|
||||
Dictionary<string, Predicate<double>> benchmarksAllocationsValidators)
|
||||
Dictionary<string, Predicate<long>> benchmarksAllocationsValidators)
|
||||
{
|
||||
var memoryDiagnoser = MemoryDiagnoser.Default;
|
||||
var config = CreateConfig(memoryDiagnoser, targetCount);
|
||||
|
@ -140,10 +127,10 @@ namespace BenchmarkDotNet.IntegrationTests
|
|||
private static T[] GetColumns<T>(MemoryDiagnoser memoryDiagnoser)
|
||||
=> memoryDiagnoser.GetColumnProvider().GetColumns(null).OfType<T>().ToArray();
|
||||
|
||||
private static void AssertParsed(string text, Predicate<double> condition)
|
||||
private static void AssertParsed(string text, Predicate<long> condition)
|
||||
{
|
||||
double value;
|
||||
if (double.TryParse(text, NumberStyles.Number, HostEnvironmentInfo.MainCultureInfo, out value))
|
||||
long value;
|
||||
if (long.TryParse(text, NumberStyles.Number, HostEnvironmentInfo.MainCultureInfo, out value))
|
||||
{
|
||||
Assert.True(condition(value), $"Failed for value {value}");
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
"allowUnsafe": true
|
||||
},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"netcoreapp1.1": {
|
||||
"buildOptions": {
|
||||
"define": [ "CORE" ]
|
||||
},
|
||||
|
@ -33,7 +33,7 @@
|
|||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"type": "platform",
|
||||
"version": "1.0.0"
|
||||
"version": "1.1.0-preview1-001100-00"
|
||||
},
|
||||
"System.ComponentModel.EventBasedAsync": "4.0.11"
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
"copyToOutput": [ "xunit.runner.json" ]
|
||||
},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"netcoreapp1.1": {
|
||||
"imports": [
|
||||
"dnxcore50",
|
||||
"portable-net45+win8",
|
||||
|
@ -29,7 +29,7 @@
|
|||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"type": "platform",
|
||||
"version": "1.0.0"
|
||||
"version": "1.1.0-preview1-001100-00"
|
||||
},
|
||||
"System.ComponentModel.EventBasedAsync": "4.0.11"
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ echo -----------------------------
|
|||
echo Running Core tests
|
||||
echo -----------------------------
|
||||
|
||||
call dotnet test "BenchmarkDotNet.IntegrationTests/" --configuration Release --framework netcoreapp1.0 2> failedCoreTests.txt
|
||||
call dotnet test "BenchmarkDotNet.IntegrationTests/" --configuration Release --framework netcoreapp1.1 2> failedCoreTests.txt
|
||||
|
||||
if NOT %ERRORLEVEL% == 0 (
|
||||
echo CORE tests has failed
|
||||
|
|
Загрузка…
Ссылка в новой задаче