update to netcoreapp1.1 in order to get universal cross platform memory diagnoser

This commit is contained in:
Adam Sitnik 2016-11-13 17:39:48 +01:00
Родитель 1022827bbb
Коммит 1e2d381b6a
12 изменённых файлов: 52 добавлений и 71 удалений

Просмотреть файл

@ -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