Switch to perfolizer
This commit is contained in:
Родитель
b3ba083e44
Коммит
54a06102a6
|
@ -186,6 +186,7 @@
|
|||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Tost/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=tracelog/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=transpiler/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=tukey/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=uname/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unimodal/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=versioning/@EntryIndexedValue">True</s:Boolean>
|
||||
|
|
|
@ -8,5 +8,6 @@
|
|||
<clear />
|
||||
|
||||
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||
<add key="perfolizer-nightly" value="https://www.myget.org/F/perfolizer/api/v3/index.json" />
|
||||
</packageSources>
|
||||
</configuration>
|
|
@ -18,7 +18,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="4.5.1" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.2" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\BenchmarkDotNet\BenchmarkDotNet.csproj" />
|
||||
|
|
|
@ -3,6 +3,7 @@ using BenchmarkDotNet.Attributes;
|
|||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using Perfolizer.Mathematics.OutlierDetection;
|
||||
|
||||
namespace BenchmarkDotNet.Samples
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@ using System.Threading;
|
|||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using Perfolizer.Mathematics.OutlierDetection;
|
||||
|
||||
namespace BenchmarkDotNet.Samples
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Threading;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Mathematics.StatisticalTesting;
|
||||
using Perfolizer.Mathematics.SignificanceTesting;
|
||||
using Perfolizer.Mathematics.Thresholds;
|
||||
|
||||
namespace BenchmarkDotNet.Samples
|
||||
{
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using BenchmarkDotNet.Columns;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using BenchmarkDotNet.Running;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
using System.Linq;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Analysers
|
||||
{
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Mathematics.Multimodality;
|
||||
|
||||
namespace BenchmarkDotNet.Analysers
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ namespace BenchmarkDotNet.Analysers
|
|||
if (statistics == null || statistics.N < EngineResolver.DefaultMinWorkloadIterationCount)
|
||||
yield break;
|
||||
|
||||
double mValue = MathHelper.CalculateMValue(statistics);
|
||||
double mValue = MValueCalculator.Calculate(statistics.OriginalValues);
|
||||
if (mValue > 4.2)
|
||||
yield return Create("is multimodal", mValue, report, summary.Style.CultureInfo);
|
||||
else if (mValue > 3.2)
|
||||
|
|
|
@ -3,10 +3,10 @@ using System.Globalization;
|
|||
using System.Linq;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Analysers
|
||||
{
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
using System.Linq;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Analysers
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using BenchmarkDotNet.Mathematics.StatisticalTesting;
|
||||
using Perfolizer.Mathematics.SignificanceTesting;
|
||||
|
||||
namespace BenchmarkDotNet.Analysers
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using BenchmarkDotNet.Columns;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Mathematics.Common;
|
||||
|
||||
namespace BenchmarkDotNet.Attributes
|
||||
{
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
using System;
|
||||
using BenchmarkDotNet.Columns;
|
||||
using BenchmarkDotNet.Mathematics.StatisticalTesting;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Mathematics.SignificanceTesting;
|
||||
using Perfolizer.Mathematics.Thresholds;
|
||||
|
||||
namespace BenchmarkDotNet.Attributes
|
||||
{
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Tracing;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnosers;
|
||||
using Microsoft.Diagnostics.NETCore.Client;
|
||||
|
||||
namespace BenchmarkDotNet.Attributes
|
||||
{
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using BenchmarkDotNet.Environments;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using System;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Attributes
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Attributes
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Attributes
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using Perfolizer.Mathematics.OutlierDetection;
|
||||
|
||||
namespace BenchmarkDotNet.Attributes
|
||||
{
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="1.1.57604" />
|
||||
<PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.5.0" />
|
||||
<PackageReference Include="Perfolizer" Version="0.2.0" />
|
||||
<PackageReference Include="System.Management" Version="4.5.0" />
|
||||
<PackageReference Include="System.Reflection.Emit" Version="4.3.0" />
|
||||
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.3.0" />
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Environments;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using BenchmarkDotNet.Running;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using BenchmarkDotNet.Running;
|
||||
|
|
|
@ -5,6 +5,7 @@ using BenchmarkDotNet.Extensions;
|
|||
using BenchmarkDotNet.Mathematics;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Mathematics.Common;
|
||||
|
||||
namespace BenchmarkDotNet.Columns
|
||||
{
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
using System.Linq;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using BenchmarkDotNet.Running;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Columns
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Globalization;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Common;
|
||||
|
||||
namespace BenchmarkDotNet.Columns
|
||||
{
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using BenchmarkDotNet.Running;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Common;
|
||||
using Perfolizer.Horology;
|
||||
using Perfolizer.Mathematics.Common;
|
||||
using Perfolizer.Mathematics.Multimodality;
|
||||
|
||||
namespace BenchmarkDotNet.Columns
|
||||
{
|
||||
|
@ -66,7 +68,7 @@ namespace BenchmarkDotNet.Columns
|
|||
/// See http://www.brendangregg.com/FrequencyTrails/modes.html
|
||||
/// </summary>
|
||||
public static readonly IColumn MValue = new StatisticColumn("MValue", "Modal value, see http://www.brendangregg.com/FrequencyTrails/modes.html",
|
||||
MathHelper.CalculateMValue, Priority.Additional, UnitType.Dimensionless);
|
||||
s => MValueCalculator.Calculate(s.OriginalValues), Priority.Additional, UnitType.Dimensionless);
|
||||
|
||||
public static readonly IColumn Iterations = new StatisticColumn("Iterations", "Number of target iterations",
|
||||
s => s.N, Priority.Additional, UnitType.Dimensionless);
|
||||
|
|
|
@ -2,9 +2,10 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using BenchmarkDotNet.Mathematics.StatisticalTesting;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using BenchmarkDotNet.Running;
|
||||
using Perfolizer.Mathematics.SignificanceTesting;
|
||||
using Perfolizer.Mathematics.Thresholds;
|
||||
|
||||
namespace BenchmarkDotNet.Columns
|
||||
{
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Analysers;
|
||||
|
|
|
@ -10,6 +10,7 @@ using BenchmarkDotNet.Mathematics;
|
|||
using CommandLine;
|
||||
using CommandLine.Text;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Mathematics.OutlierDetection;
|
||||
|
||||
namespace BenchmarkDotNet.ConsoleArguments
|
||||
{
|
||||
|
|
|
@ -13,11 +13,9 @@ using BenchmarkDotNet.Exporters.Json;
|
|||
using BenchmarkDotNet.Exporters.Xml;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Filters;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Loggers;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using BenchmarkDotNet.Mathematics.StatisticalTesting;
|
||||
using BenchmarkDotNet.Portability;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using BenchmarkDotNet.Toolchains.CoreRt;
|
||||
|
@ -26,6 +24,10 @@ using BenchmarkDotNet.Toolchains.CsProj;
|
|||
using BenchmarkDotNet.Toolchains.DotNetCli;
|
||||
using BenchmarkDotNet.Toolchains.InProcess.Emit;
|
||||
using CommandLine;
|
||||
using Perfolizer.Horology;
|
||||
using Perfolizer.Mathematics.OutlierDetection;
|
||||
using Perfolizer.Mathematics.SignificanceTesting;
|
||||
using Perfolizer.Mathematics.Thresholds;
|
||||
|
||||
namespace BenchmarkDotNet.ConsoleArguments
|
||||
{
|
||||
|
|
|
@ -5,7 +5,6 @@ using System.Linq;
|
|||
using BenchmarkDotNet.Analysers;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Exporters;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Loggers;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using BenchmarkDotNet.Running;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using BenchmarkDotNet.Analysers;
|
||||
using BenchmarkDotNet.Columns;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Exporters;
|
||||
using BenchmarkDotNet.Loggers;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BenchmarkDotNet.Analysers;
|
||||
using BenchmarkDotNet.Columns;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Exporters;
|
||||
using BenchmarkDotNet.Loggers;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using BenchmarkDotNet.Disassemblers.Exporters;
|
||||
using Iced.Intel;
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BenchmarkDotNet.Diagnosers
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using BenchmarkDotNet.Diagnosers;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace BenchmarkDotNet.Disassemblers.Exporters
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
using BenchmarkDotNet.Diagnosers;
|
||||
using Iced.Intel;
|
||||
using Iced.Intel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BenchmarkDotNet.Disassemblers
|
||||
{
|
||||
|
|
|
@ -3,11 +3,11 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Characteristics;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Portability;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Engines
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Engines
|
||||
{
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using Perfolizer.Horology;
|
||||
using Perfolizer.Mathematics.OutlierDetection;
|
||||
|
||||
namespace BenchmarkDotNet.Engines
|
||||
{
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Characteristics;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Running;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Engines
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using BenchmarkDotNet.Environments;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Engines
|
||||
{
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
using System;
|
||||
using BenchmarkDotNet.Characteristics;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using Perfolizer.Horology;
|
||||
using Perfolizer.Mathematics.OutlierDetection;
|
||||
|
||||
namespace BenchmarkDotNet.Engines
|
||||
{
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System.Reflection;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Portability;
|
||||
using BenchmarkDotNet.Toolchains.DotNetCli;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Engines
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Linq;
|
|||
using BenchmarkDotNet.Mathematics;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Mathematics.OutlierDetection;
|
||||
|
||||
namespace BenchmarkDotNet.Engines
|
||||
{
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Loggers;
|
||||
using BenchmarkDotNet.Portability;
|
||||
using BenchmarkDotNet.Portability.Cpu;
|
||||
|
@ -11,6 +9,7 @@ using BenchmarkDotNet.Properties;
|
|||
using BenchmarkDotNet.Reports;
|
||||
using BenchmarkDotNet.Toolchains.DotNetCli;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Environments
|
||||
{
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
using System;
|
||||
using BenchmarkDotNet.Characteristics;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Environments
|
||||
{
|
||||
|
|
|
@ -3,12 +3,10 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Portability.Cpu;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Environments
|
||||
{
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Characteristics;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnosers;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Loggers;
|
||||
using BenchmarkDotNet.Reports;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Environments;
|
||||
using BenchmarkDotNet.Loggers;
|
||||
using BenchmarkDotNet.Reports;
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Exporters.Csv;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using BenchmarkDotNet.Loggers;
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
using System.Linq;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Environments;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Loggers;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using BenchmarkDotNet.Reports;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using BenchmarkDotNet.Mathematics.Histograms;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Horology;
|
||||
using Perfolizer.Mathematics.Histograms;
|
||||
using Perfolizer.Mathematics.Multimodality;
|
||||
|
||||
namespace BenchmarkDotNet.Extensions
|
||||
{
|
||||
|
@ -30,7 +31,7 @@ namespace BenchmarkDotNet.Extensions
|
|||
string errorPercent = (s.StandardError / s.Mean * 100).ToString("0.00", cultureInfo);
|
||||
var ci = s.ConfidenceInterval;
|
||||
string ciMarginPercent = (ci.Margin / s.Mean * 100).ToString("0.00", cultureInfo);
|
||||
double mValue = MathHelper.CalculateMValue(s);
|
||||
double mValue = MValueCalculator.Calculate(s.OriginalValues);
|
||||
|
||||
builder.Append("Mean = ");
|
||||
builder.Append(formatter(s.Mean));
|
||||
|
@ -96,7 +97,7 @@ namespace BenchmarkDotNet.Extensions
|
|||
|
||||
if (calcHistogram)
|
||||
{
|
||||
var histogram = HistogramBuilder.Adaptive.Build(s);
|
||||
var histogram = HistogramBuilder.Adaptive.Build(s.OriginalValues);
|
||||
builder.AppendLine("-------------------- Histogram --------------------");
|
||||
builder.AppendLine(histogram.ToString(formatter));
|
||||
builder.AppendLine("---------------------------------------------------");
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.Globalization;
|
|||
using System.IO;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using Perfolizer.Horology;
|
||||
using SimpleJson.Reflection;
|
||||
|
||||
namespace BenchmarkDotNet.Helpers
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using Perfolizer.Horology;
|
||||
using SimpleJson.Reflection;
|
||||
|
||||
namespace BenchmarkDotNet.Helpers
|
||||
|
@ -42,7 +42,7 @@ namespace BenchmarkDotNet.Helpers
|
|||
|
||||
switch (value) {
|
||||
case TimeInterval interval:
|
||||
return "new BenchmarkDotNet.Horology.TimeInterval(" + ToSourceCode(interval.Nanoseconds) + ")";
|
||||
return "new Perfolizer.Horology.TimeInterval(" + ToSourceCode(interval.Nanoseconds) + ")";
|
||||
case IntPtr ptr:
|
||||
return $"new System.IntPtr({ptr})";
|
||||
case IFormattable formattable:
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
namespace BenchmarkDotNet.Helpers
|
||||
{
|
||||
public class UnitPresentation
|
||||
{
|
||||
public static readonly UnitPresentation Default = new UnitPresentation(true, 0);
|
||||
public static readonly UnitPresentation Invisible = new UnitPresentation(false, 0);
|
||||
|
||||
public bool IsVisible { get; private set; }
|
||||
public int MinUnitWidth { get; private set; }
|
||||
|
||||
public UnitPresentation(bool isVisible, int minUnitWidth)
|
||||
{
|
||||
IsVisible = isVisible;
|
||||
MinUnitWidth = minUnitWidth;
|
||||
}
|
||||
|
||||
public static UnitPresentation FromVisibility(bool isVisible) => new UnitPresentation(isVisible, 0);
|
||||
|
||||
public static UnitPresentation FromWidth(int unitWidth) => new UnitPresentation(true, unitWidth);
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
using System;
|
||||
using BenchmarkDotNet.Portability;
|
||||
|
||||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
public static class Chronometer
|
||||
{
|
||||
public static readonly IClock Stopwatch = new StopwatchClock();
|
||||
public static readonly IClock DateTime = new DateTimeClock();
|
||||
public static readonly IClock WindowsClock = new WindowsClock();
|
||||
|
||||
public static readonly IClock BestClock;
|
||||
|
||||
public static Frequency Frequency => BestClock.Frequency;
|
||||
public static long GetTimestamp() => BestClock.GetTimestamp();
|
||||
public static StartedClock Start() => BestClock.Start();
|
||||
public static TimeInterval GetResolution() => BestClock.GetResolution();
|
||||
|
||||
static Chronometer()
|
||||
{
|
||||
if (RuntimeInformation.IsWindows() && WindowsClock.IsAvailable)
|
||||
BestClock = WindowsClock;
|
||||
else
|
||||
BestClock = Stopwatch;
|
||||
}
|
||||
|
||||
public static HardwareTimerKind HardwareTimerKind => GetHardwareTimerKind(BestClock.Frequency);
|
||||
|
||||
public static HardwareTimerKind GetHardwareTimerKind(Frequency frequency)
|
||||
{
|
||||
long freqKHz = (long) Math.Round(frequency / Frequency.KHz);
|
||||
if (14300 <= freqKHz && freqKHz <= 14400)
|
||||
return HardwareTimerKind.Hpet;
|
||||
if (3579500 <= frequency && frequency <= 3579600)
|
||||
return HardwareTimerKind.Acpi;
|
||||
if (freqKHz == 10000)
|
||||
return HardwareTimerKind.Unknown;
|
||||
if (5 <= freqKHz && freqKHz < 4000)
|
||||
return HardwareTimerKind.Tsc;
|
||||
if (freqKHz <= 4)
|
||||
return HardwareTimerKind.System;
|
||||
return HardwareTimerKind.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
public static class ClockExtensions
|
||||
{
|
||||
public static TimeInterval GetResolution(this IClock clock) => clock.Frequency.ToResolution();
|
||||
|
||||
public static StartedClock Start(this IClock clock) => new StartedClock(clock, clock.GetTimestamp());
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
using System;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
public struct ClockSpan
|
||||
{
|
||||
private readonly long startTimestamp, endTimestamp;
|
||||
private readonly Frequency frequency;
|
||||
|
||||
public ClockSpan(long startTimestamp, long endTimestamp, Frequency frequency)
|
||||
{
|
||||
this.startTimestamp = startTimestamp;
|
||||
this.endTimestamp = endTimestamp;
|
||||
this.frequency = frequency;
|
||||
}
|
||||
|
||||
[Pure] public double GetSeconds() => 1.0 * Math.Max(0, endTimestamp - startTimestamp) / frequency;
|
||||
[Pure] public double GetNanoseconds() => GetSeconds() * TimeUnit.Second.NanosecondAmount;
|
||||
[Pure] public long GetDateTimeTicks() => (long) Math.Round(GetSeconds() * TimeSpan.TicksPerSecond);
|
||||
[Pure] public TimeSpan GetTimeSpan() => new TimeSpan(GetDateTimeTicks());
|
||||
[Pure] public TimeInterval GetTimeValue() => new TimeInterval(GetNanoseconds());
|
||||
|
||||
public override string ToString() => $"ClockSpan({startTimestamp} ticks, {endTimestamp} ticks, {frequency.Hertz} Hz)";
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
internal class DateTimeClock : IClock
|
||||
{
|
||||
private const long TicksPerSecond = (long) 10 * 1000 * 1000;
|
||||
|
||||
public string Title => "DateTime";
|
||||
public bool IsAvailable => true;
|
||||
public Frequency Frequency => new Frequency(TicksPerSecond);
|
||||
public long GetTimestamp() => DateTime.UtcNow.Ticks;
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
using System.Globalization;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
[PublicAPI]
|
||||
public struct Frequency
|
||||
{
|
||||
[PublicAPI] public double Hertz { get; }
|
||||
|
||||
[PublicAPI] public Frequency(double hertz) => Hertz = hertz;
|
||||
|
||||
[PublicAPI] public Frequency(double value, FrequencyUnit unit) : this(value * unit.HertzAmount) { }
|
||||
|
||||
[PublicAPI] public static readonly Frequency Zero = new Frequency(0);
|
||||
[PublicAPI] public static readonly Frequency Hz = FrequencyUnit.Hz.ToFrequency();
|
||||
[PublicAPI] public static readonly Frequency KHz = FrequencyUnit.KHz.ToFrequency();
|
||||
[PublicAPI] public static readonly Frequency MHz = FrequencyUnit.MHz.ToFrequency();
|
||||
[PublicAPI] public static readonly Frequency GHz = FrequencyUnit.GHz.ToFrequency();
|
||||
|
||||
[PublicAPI, Pure] public TimeInterval ToResolution() => TimeInterval.Second / Hertz;
|
||||
|
||||
[PublicAPI, Pure] public double ToHz() => this / Hz;
|
||||
[PublicAPI, Pure] public double ToKHz() => this / KHz;
|
||||
[PublicAPI, Pure] public double ToMHz() => this / MHz;
|
||||
[PublicAPI, Pure] public double ToGHz() => this / GHz;
|
||||
|
||||
[PublicAPI, Pure] public static Frequency FromHz(double value) => Hz * value;
|
||||
[PublicAPI, Pure] public static Frequency FromKHz(double value) => KHz * value;
|
||||
[PublicAPI, Pure] public static Frequency FromMHz(double value) => MHz * value;
|
||||
[PublicAPI, Pure] public static Frequency FromGHz(double value) => GHz * value;
|
||||
|
||||
[PublicAPI, Pure] public static implicit operator Frequency(double value) => new Frequency(value);
|
||||
[PublicAPI, Pure] public static implicit operator double(Frequency property) => property.Hertz;
|
||||
|
||||
[PublicAPI, Pure] public static double operator /(Frequency a, Frequency b) => 1.0 * a.Hertz / b.Hertz;
|
||||
[PublicAPI, Pure] public static Frequency operator /(Frequency a, double k) => new Frequency(a.Hertz / k);
|
||||
[PublicAPI, Pure] public static Frequency operator /(Frequency a, int k) => new Frequency(a.Hertz / k);
|
||||
[PublicAPI, Pure] public static Frequency operator *(Frequency a, double k) => new Frequency(a.Hertz * k);
|
||||
[PublicAPI, Pure] public static Frequency operator *(Frequency a, int k) => new Frequency(a.Hertz * k);
|
||||
[PublicAPI, Pure] public static Frequency operator *(double k, Frequency a) => new Frequency(a.Hertz * k);
|
||||
[PublicAPI, Pure] public static Frequency operator *(int k, Frequency a) => new Frequency(a.Hertz * k);
|
||||
|
||||
[PublicAPI, Pure] public static bool TryParse(string s, FrequencyUnit unit, out Frequency freq)
|
||||
{
|
||||
bool success = double.TryParse(s, NumberStyles.Any, DefaultCultureInfo.Instance, out double result);
|
||||
freq = new Frequency(result, unit);
|
||||
return success;
|
||||
}
|
||||
|
||||
[PublicAPI, Pure] public static bool TryParseHz(string s, out Frequency freq) => TryParse(s, FrequencyUnit.Hz, out freq);
|
||||
[PublicAPI, Pure] public static bool TryParseKHz(string s, out Frequency freq) => TryParse(s, FrequencyUnit.KHz, out freq);
|
||||
[PublicAPI, Pure] public static bool TryParseMHz(string s, out Frequency freq) => TryParse(s, FrequencyUnit.MHz, out freq);
|
||||
[PublicAPI, Pure] public static bool TryParseGHz(string s, out Frequency freq) => TryParse(s, FrequencyUnit.GHz, out freq);
|
||||
|
||||
[PublicAPI, Pure] public override string ToString() => Hertz + " " + FrequencyUnit.Hz.Name;
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
public class FrequencyUnit
|
||||
{
|
||||
public string Name { get; }
|
||||
public string Description { get; }
|
||||
public long HertzAmount { get; }
|
||||
|
||||
private FrequencyUnit(string name, string description, long hertzAmount)
|
||||
{
|
||||
Name = name;
|
||||
Description = description;
|
||||
HertzAmount = hertzAmount;
|
||||
}
|
||||
|
||||
public static readonly FrequencyUnit Hz = new FrequencyUnit("Hz", "Hertz", 1);
|
||||
public static readonly FrequencyUnit KHz = new FrequencyUnit("KHz", "Kilohertz", 1000);
|
||||
public static readonly FrequencyUnit MHz = new FrequencyUnit("MHz", "Megahertz", 1000 * 1000);
|
||||
public static readonly FrequencyUnit GHz = new FrequencyUnit("GHz", "Gigahertz", 1000 * 1000 * 1000);
|
||||
public static readonly FrequencyUnit[] All = { Hz, KHz, MHz, GHz };
|
||||
|
||||
public Frequency ToFrequency(long value = 1) => new Frequency(value, this);
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
public enum HardwareTimerKind
|
||||
{
|
||||
/// <summary>
|
||||
/// System timer
|
||||
/// </summary>
|
||||
System,
|
||||
|
||||
/// <summary>
|
||||
/// Time Stamp Counter
|
||||
/// <seealso href="https://en.wikipedia.org/wiki/Time_Stamp_Counter"/>
|
||||
/// </summary>
|
||||
Tsc,
|
||||
|
||||
Acpi,
|
||||
|
||||
/// <summary>
|
||||
/// High Precision Event Timer
|
||||
/// <seealso href="https://en.wikipedia.org/wiki/High_Precision_Event_Timer"/>
|
||||
/// </summary>
|
||||
Hpet,
|
||||
|
||||
Unknown
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
public interface IClock
|
||||
{
|
||||
string Title { get; }
|
||||
bool IsAvailable { get; }
|
||||
Frequency Frequency { get; }
|
||||
long GetTimestamp();
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
public struct StartedClock
|
||||
{
|
||||
private readonly IClock clock;
|
||||
private readonly long startTimestamp;
|
||||
|
||||
public StartedClock(IClock clock, long startTimestamp)
|
||||
{
|
||||
this.clock = clock;
|
||||
this.startTimestamp = startTimestamp;
|
||||
}
|
||||
|
||||
public ClockSpan GetElapsed() => new ClockSpan(startTimestamp, clock.GetTimestamp(), clock.Frequency);
|
||||
|
||||
public override string ToString() => $"StartedClock({clock.Title}, {startTimestamp} ticks)";
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
internal class StopwatchClock : IClock
|
||||
{
|
||||
public string Title => "Stopwatch";
|
||||
public bool IsAvailable => true;
|
||||
public Frequency Frequency => new Frequency(Stopwatch.Frequency);
|
||||
public long GetTimestamp() => Stopwatch.GetTimestamp();
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
using System.Globalization;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
public struct TimeInterval
|
||||
{
|
||||
public double Nanoseconds { get; }
|
||||
|
||||
public TimeInterval(double nanoseconds) => Nanoseconds = nanoseconds;
|
||||
|
||||
public TimeInterval(double value, TimeUnit unit) : this(value * unit.NanosecondAmount) { }
|
||||
|
||||
public static readonly TimeInterval Nanosecond = TimeUnit.Nanosecond.ToInterval();
|
||||
public static readonly TimeInterval Microsecond = TimeUnit.Microsecond.ToInterval();
|
||||
public static readonly TimeInterval Millisecond = TimeUnit.Millisecond.ToInterval();
|
||||
public static readonly TimeInterval Second = TimeUnit.Second.ToInterval();
|
||||
public static readonly TimeInterval Minute = TimeUnit.Minute.ToInterval();
|
||||
public static readonly TimeInterval Hour = TimeUnit.Hour.ToInterval();
|
||||
public static readonly TimeInterval Day = TimeUnit.Day.ToInterval();
|
||||
|
||||
[Pure] public Frequency ToFrequency() => new Frequency(Second / this);
|
||||
|
||||
[Pure] public double ToNanoseconds() => this / Nanosecond;
|
||||
[Pure] public double ToMicroseconds() => this / Microsecond;
|
||||
[Pure] public double ToMilliseconds() => this / Millisecond;
|
||||
[Pure] public double ToSeconds() => this / Second;
|
||||
[Pure] public double ToMinutes() => this / Minute;
|
||||
[Pure] public double ToHours() => this / Hour;
|
||||
[Pure] public double ToDays() => this / Day;
|
||||
|
||||
[Pure] public static TimeInterval FromNanoseconds(double value) => Nanosecond * value;
|
||||
[Pure] public static TimeInterval FromMicroseconds(double value) => Microsecond * value;
|
||||
[Pure] public static TimeInterval FromMilliseconds(double value) => Millisecond * value;
|
||||
[Pure] public static TimeInterval FromSeconds(double value) => Second * value;
|
||||
[Pure] public static TimeInterval FromMinutes(double value) => Minute * value;
|
||||
[Pure] public static TimeInterval FromHours(double value) => Hour * value;
|
||||
[Pure] public static TimeInterval FromDays(double value) => Day * value;
|
||||
|
||||
[Pure] public static double operator /(TimeInterval a, TimeInterval b) => 1.0 * a.Nanoseconds / b.Nanoseconds;
|
||||
[Pure] public static TimeInterval operator /(TimeInterval a, double k) => new TimeInterval(a.Nanoseconds / k);
|
||||
[Pure] public static TimeInterval operator /(TimeInterval a, int k) => new TimeInterval(a.Nanoseconds / k);
|
||||
[Pure] public static TimeInterval operator *(TimeInterval a, double k) => new TimeInterval(a.Nanoseconds * k);
|
||||
[Pure] public static TimeInterval operator *(TimeInterval a, int k) => new TimeInterval(a.Nanoseconds * k);
|
||||
[Pure] public static TimeInterval operator *(double k, TimeInterval a) => new TimeInterval(a.Nanoseconds * k);
|
||||
[Pure] public static TimeInterval operator *(int k, TimeInterval a) => new TimeInterval(a.Nanoseconds * k);
|
||||
[Pure] public static bool operator <(TimeInterval a, TimeInterval b) => a.Nanoseconds < b.Nanoseconds;
|
||||
[Pure] public static bool operator >(TimeInterval a, TimeInterval b) => a.Nanoseconds > b.Nanoseconds;
|
||||
[Pure] public static bool operator <=(TimeInterval a, TimeInterval b) => a.Nanoseconds <= b.Nanoseconds;
|
||||
[Pure] public static bool operator >=(TimeInterval a, TimeInterval b) => a.Nanoseconds >= b.Nanoseconds;
|
||||
|
||||
[Pure, NotNull]
|
||||
public string ToString(
|
||||
[CanBeNull] CultureInfo cultureInfo,
|
||||
[CanBeNull] string format = "N4",
|
||||
[CanBeNull] UnitPresentation unitPresentation = null)
|
||||
{
|
||||
return ToString(null, cultureInfo, format, unitPresentation);
|
||||
}
|
||||
|
||||
[Pure, NotNull]
|
||||
public string ToString(
|
||||
[CanBeNull] TimeUnit timeUnit,
|
||||
[CanBeNull] CultureInfo cultureInfo,
|
||||
[CanBeNull] string format = "N4",
|
||||
[CanBeNull] UnitPresentation unitPresentation = null)
|
||||
{
|
||||
timeUnit = timeUnit ?? TimeUnit.GetBestTimeUnit(Nanoseconds);
|
||||
cultureInfo = cultureInfo ?? DefaultCultureInfo.Instance;
|
||||
format = format ?? "N4";
|
||||
unitPresentation = unitPresentation ?? UnitPresentation.Default;
|
||||
double unitValue = TimeUnit.Convert(Nanoseconds, TimeUnit.Nanosecond, timeUnit);
|
||||
if (unitPresentation.IsVisible)
|
||||
{
|
||||
string unitName = timeUnit.Name.PadLeft(unitPresentation.MinUnitWidth);
|
||||
return $"{unitValue.ToString(format, cultureInfo)} {unitName}";
|
||||
}
|
||||
|
||||
return unitValue.ToString(format, cultureInfo);
|
||||
}
|
||||
|
||||
[Pure] public override string ToString() => ToString(DefaultCultureInfo.Instance);
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
|
||||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
internal static class TimeSpanExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Time in the following format: {th}:{mm}:{ss} ({ts} sec)
|
||||
///
|
||||
/// where
|
||||
/// {th}: total hours (two digits)
|
||||
/// {mm}: minutes (two digits)
|
||||
/// {ss}: seconds (two digits)
|
||||
/// {ts}: total seconds
|
||||
/// </summary>
|
||||
/// <example>TimeSpan.FromSeconds(2362) -> "00:39:22 (2362 sec)"</example>
|
||||
/// <param name="time"></param>
|
||||
/// <param name="cultureInfo">CultureInfo that will be used for formatting</param>
|
||||
/// <returns></returns>
|
||||
public static string ToFormattedTotalTime(this TimeSpan time, CultureInfo cultureInfo)
|
||||
{
|
||||
long totalHours = time.Ticks / TimeSpan.TicksPerHour;
|
||||
string hhMmSs = $"{totalHours:00}:{time:mm\\:ss}";
|
||||
string totalSecs = $"{time.TotalSeconds.ToString("0.##", cultureInfo)} sec";
|
||||
return $"{hhMmSs} ({totalSecs})";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
public class TimeUnit : IEquatable<TimeUnit>
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public string Description { get; }
|
||||
public long NanosecondAmount { get; }
|
||||
|
||||
private TimeUnit(string name, string description, long nanosecondAmount)
|
||||
{
|
||||
Name = name;
|
||||
Description = description;
|
||||
NanosecondAmount = nanosecondAmount;
|
||||
}
|
||||
|
||||
public TimeInterval ToInterval(long value = 1) => new TimeInterval(value, this);
|
||||
|
||||
[PublicAPI] public static readonly TimeUnit Nanosecond = new TimeUnit("ns", "Nanosecond", 1);
|
||||
[PublicAPI] public static readonly TimeUnit Microsecond = new TimeUnit("\u03BCs", "Microsecond", 1000);
|
||||
[PublicAPI] public static readonly TimeUnit Millisecond = new TimeUnit("ms", "Millisecond", 1000 * 1000);
|
||||
[PublicAPI] public static readonly TimeUnit Second = new TimeUnit("s", "Second", 1000 * 1000 * 1000);
|
||||
[PublicAPI] public static readonly TimeUnit Minute = new TimeUnit("m", "Minute", Second.NanosecondAmount * 60);
|
||||
[PublicAPI] public static readonly TimeUnit Hour = new TimeUnit("h", "Hour", Minute.NanosecondAmount * 60);
|
||||
[PublicAPI] public static readonly TimeUnit Day = new TimeUnit("d", "Day", Hour.NanosecondAmount * 24);
|
||||
[PublicAPI] public static readonly TimeUnit[] All = { Nanosecond, Microsecond, Millisecond, Second, Minute, Hour, Day };
|
||||
|
||||
/// <summary>
|
||||
/// This method chooses the best time unit for representing a set of time measurements.
|
||||
/// </summary>
|
||||
/// <param name="values">The list of time measurements in nanoseconds.</param>
|
||||
/// <returns>Best time unit.</returns>
|
||||
public static TimeUnit GetBestTimeUnit(params double[] values)
|
||||
{
|
||||
if (values.Length == 0)
|
||||
return Nanosecond;
|
||||
// Use the largest unit to display the smallest recorded measurement without loss of precision.
|
||||
double minValue = values.Min();
|
||||
foreach (var timeUnit in All)
|
||||
if (minValue < timeUnit.NanosecondAmount * 1000)
|
||||
return timeUnit;
|
||||
return All.Last();
|
||||
}
|
||||
|
||||
public static double Convert(double value, TimeUnit from, TimeUnit to) =>
|
||||
value * from.NanosecondAmount / (to ?? GetBestTimeUnit(value)).NanosecondAmount;
|
||||
|
||||
public bool Equals(TimeUnit other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
return false;
|
||||
if (ReferenceEquals(this, other))
|
||||
return true;
|
||||
return Equals(Name, other.Name) && string.Equals(Description, other.Description) && NanosecondAmount == other.NanosecondAmount;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
return false;
|
||||
if (ReferenceEquals(this, obj))
|
||||
return true;
|
||||
if (obj.GetType() != this.GetType())
|
||||
return false;
|
||||
return Equals((TimeUnit) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hashCode = (Name != null ? Name.GetHashCode() : 0);
|
||||
hashCode = (hashCode * 397) ^ (Description != null ? Description.GetHashCode() : 0);
|
||||
hashCode = (hashCode * 397) ^ NanosecondAmount.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator ==(TimeUnit left, TimeUnit right) => Equals(left, right);
|
||||
|
||||
public static bool operator !=(TimeUnit left, TimeUnit right) => !Equals(left, right);
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
using System.Runtime.ExceptionServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using RuntimeInformation = BenchmarkDotNet.Portability.RuntimeInformation;
|
||||
|
||||
namespace BenchmarkDotNet.Horology
|
||||
{
|
||||
internal class WindowsClock : IClock
|
||||
{
|
||||
private static readonly bool GlobalIsAvailable;
|
||||
private static readonly long GlobalFrequency;
|
||||
|
||||
static WindowsClock() => GlobalIsAvailable = Initialize(out GlobalFrequency);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool QueryPerformanceCounter(out long value);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool QueryPerformanceFrequency(out long value);
|
||||
|
||||
[HandleProcessCorruptedStateExceptions] // #276
|
||||
[SecurityCritical]
|
||||
private static bool Initialize(out long qpf)
|
||||
{
|
||||
if (!RuntimeInformation.IsWindows())
|
||||
{
|
||||
qpf = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return QueryPerformanceFrequency(out qpf) && QueryPerformanceCounter(out _);
|
||||
}
|
||||
catch
|
||||
{
|
||||
qpf = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public string Title => "Windows";
|
||||
public bool IsAvailable => GlobalIsAvailable;
|
||||
public Frequency Frequency => new Frequency(GlobalFrequency);
|
||||
|
||||
public long GetTimestamp()
|
||||
{
|
||||
QueryPerformanceCounter(out long value);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using BenchmarkDotNet.Characteristics;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using Perfolizer.Horology;
|
||||
using Perfolizer.Mathematics.OutlierDetection;
|
||||
|
||||
namespace BenchmarkDotNet.Jobs
|
||||
{
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using BenchmarkDotNet.Characteristics;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Toolchains;
|
||||
using BenchmarkDotNet.Toolchains.InProcess.Emit;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Jobs
|
||||
{
|
||||
|
|
|
@ -5,11 +5,12 @@ using System.Linq;
|
|||
using BenchmarkDotNet.Analysers;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Environments;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Mathematics;
|
||||
using BenchmarkDotNet.Running;
|
||||
using BenchmarkDotNet.Toolchains;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Horology;
|
||||
using Perfolizer.Mathematics.OutlierDetection;
|
||||
|
||||
namespace BenchmarkDotNet.Jobs
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
using BenchmarkDotNet.Analysers;
|
||||
using BenchmarkDotNet.Characteristics;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using Perfolizer.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Jobs
|
||||
{
|
||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.CodeAnalysis.Operations;
|
||||
|
||||
namespace BenchmarkDotNet.Loggers
|
||||
{
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics
|
||||
{
|
||||
public static class BinomialCoefficientHelper
|
||||
{
|
||||
public const int MaxAcceptableN = 65;
|
||||
|
||||
private static long[,] pascalTriangle;
|
||||
|
||||
public static long GetBinomialCoefficient(int n, int k)
|
||||
{
|
||||
const int maxN = MaxAcceptableN;
|
||||
if (n < 0 || n > maxN)
|
||||
throw new ArgumentOutOfRangeException(nameof(n));
|
||||
if (k < 0 || k > n)
|
||||
return 0;
|
||||
|
||||
if (pascalTriangle == null)
|
||||
{
|
||||
checked
|
||||
{
|
||||
pascalTriangle = new long[maxN + 1, maxN + 1];
|
||||
for (int i = 0; i <= maxN; i++)
|
||||
{
|
||||
pascalTriangle[i, 0] = 1;
|
||||
for (int j = 1; j <= i; j++)
|
||||
pascalTriangle[i, j] = pascalTriangle[i - 1, j - 1] + pascalTriangle[i - 1, j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pascalTriangle[n, k];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,257 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
// ReSharper disable CommentTypo, CompareOfFloatsByEqualityOperator
|
||||
namespace BenchmarkDotNet.Mathematics.ChangePointDetection
|
||||
{
|
||||
/// <summary>
|
||||
/// The ED-PELT algorithm for changepoint detection.
|
||||
///
|
||||
/// <remarks>
|
||||
/// The implementation is based on the following papers:
|
||||
/// <list type="bullet">
|
||||
/// <item>
|
||||
/// <b>[Haynes2017]</b> Haynes, Kaylea, Paul Fearnhead, and Idris A. Eckley.
|
||||
/// "A computationally efficient nonparametric approach for changepoint detection."
|
||||
/// Statistics and Computing 27, no. 5 (2017): 1293-1305.
|
||||
/// https://doi.org/10.1007/s11222-016-9687-5
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <b>[Killick2012]</b> Killick, Rebecca, Paul Fearnhead, and Idris A. Eckley.
|
||||
/// "Optimal detection of changepoints with a linear computational cost."
|
||||
/// Journal of the American Statistical Association 107, no. 500 (2012): 1590-1598.
|
||||
/// https://arxiv.org/pdf/1101.1438.pdf
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
/// </summary>
|
||||
public class EdPeltChangePointDetector
|
||||
{
|
||||
public static readonly EdPeltChangePointDetector Instance = new EdPeltChangePointDetector();
|
||||
|
||||
/// <summary>
|
||||
/// For given array of `double` values, detects locations of changepoints that
|
||||
/// splits original series of values into "statistically homogeneous" segments.
|
||||
/// Such points correspond to moments when statistical properties of the distribution are changing.
|
||||
///
|
||||
/// This method supports nonparametric distributions and has O(N*log(N)) algorithmic complexity.
|
||||
/// </summary>
|
||||
/// <param name="data">An array of double values</param>
|
||||
/// <param name="minDistance">Minimum distance between changepoints</param>
|
||||
/// <returns>
|
||||
/// Returns an `int[]` array with 0-based indexes of changepoint.
|
||||
/// Changepoints correspond to the end of the detected segments.
|
||||
/// For example, changepoints for { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2 } are { 5, 11 }.
|
||||
/// </returns>
|
||||
public int[] GetChangePointIndexes(double[] data, int minDistance = 1)
|
||||
{
|
||||
// We will use `n` as the number of elements in the `data` array
|
||||
int n = data.Length;
|
||||
|
||||
// Checking corner cases
|
||||
if (n <= 2)
|
||||
return Array.Empty<int>();
|
||||
|
||||
if (minDistance < 1 || minDistance > n)
|
||||
throw new ArgumentOutOfRangeException(nameof(minDistance), $"{minDistance} should be in range from 1 to data.Length");
|
||||
|
||||
// The penalty which we add to the final cost for each additional changepoint
|
||||
// Here we use the Modified Bayesian Information Criterion
|
||||
double penalty = 3 * Math.Log(n);
|
||||
|
||||
// `k` is the number of quantiles that we use to approximate an integral during the segment cost evaluation
|
||||
// We use `k=Ceiling(4*log(n))` as suggested in the Section 4.3 "Choice of K in ED-PELT" in [Haynes2017]
|
||||
// `k` can't be greater than `n`, so we should always use the `Min` function here (important for n <= 8)
|
||||
int k = Math.Min(n, (int) Math.Ceiling(4 * Math.Log(n)));
|
||||
|
||||
// We should precalculate sums for empirical CDF, it will allow fast evaluating of the segment cost
|
||||
var partialSums = GetPartialSums(data, k);
|
||||
|
||||
// Since we use the same values of `partialSums`, `k`, `n` all the time,
|
||||
// we introduce a shortcut `Cost(tau1, tau2)` for segment cost evaluation.
|
||||
// Hereinafter, we use `tau` to name variables that are changepoint candidates.
|
||||
double Cost(int tau1, int tau2) => GetSegmentCost(partialSums, tau1, tau2, k, n);
|
||||
|
||||
// We will use dynamic programming to find the best solution; `bestCost` is the cost array.
|
||||
// `bestCost[i]` is the cost for subarray `data[0..i-1]`.
|
||||
// It's a 1-based array (`data[0]`..`data[n-1]` correspond to `bestCost[1]`..`bestCost[n]`)
|
||||
var bestCost = new double[n + 1];
|
||||
bestCost[0] = -penalty;
|
||||
for (int currentTau = minDistance; currentTau < 2 * minDistance; currentTau++)
|
||||
bestCost[currentTau] = Cost(0, currentTau);
|
||||
|
||||
// `previousChangePointIndex` is an array of references to previous changepoints. If the current segment ends at
|
||||
// the position `i`, the previous segment ends at the position `previousChangePointIndex[i]`. It's a 1-based
|
||||
// array (`data[0]`..`data[n-1]` correspond to the `previousChangePointIndex[1]`..`previousChangePointIndex[n]`)
|
||||
var previousChangePointIndex = new int[n + 1];
|
||||
|
||||
// We use PELT (Pruned Exact Linear Time) approach which means that instead of enumerating all possible previous
|
||||
// tau values, we use a whitelist of "good" tau values that can be used in the optimal solution. If we are 100%
|
||||
// sure that some of the tau values will not help us to form the optimal solution, such values should be
|
||||
// removed. See [Killick2012] for details.
|
||||
var previousTaus = new int[n + 1]; // The maximum number of the previous tau values is n + 1
|
||||
previousTaus[0] = 0;
|
||||
previousTaus[1] = minDistance;
|
||||
var costForPreviousTau = new double[n + 1];
|
||||
int previousTausCount = 2; // The counter of previous tau values. Defines the size of `previousTaus` and `costForPreviousTau`.
|
||||
|
||||
// Following the dynamic programming approach, we enumerate all tau positions. For each `currentTau`, we pretend
|
||||
// that it's the end of the last segment and trying to find the end of the previous segment.
|
||||
for (int currentTau = 2 * minDistance; currentTau < n + 1; currentTau++)
|
||||
{
|
||||
// For each previous tau, we should calculate the cost of taking this tau as the end of the previous
|
||||
// segment. This cost equals the cost for the `previousTau` plus cost of the new segment (from `previousTau`
|
||||
// to `currentTau`) plus penalty for the new changepoint.
|
||||
for (int i = 0; i < previousTausCount; i++)
|
||||
{
|
||||
int previousTau = previousTaus[i];
|
||||
costForPreviousTau[i] = bestCost[previousTau] + Cost(previousTau, currentTau) + penalty;
|
||||
}
|
||||
|
||||
// Now we should choose the tau that provides the minimum possible cost.
|
||||
int bestPreviousTauIndex = WhichMin(costForPreviousTau, previousTausCount);
|
||||
bestCost[currentTau] = costForPreviousTau[bestPreviousTauIndex];
|
||||
previousChangePointIndex[currentTau] = previousTaus[bestPreviousTauIndex];
|
||||
|
||||
// Prune phase: we remove "useless" tau values that will not help to achieve minimum cost in the future
|
||||
double currentBestCost = bestCost[currentTau];
|
||||
int newPreviousTausCount = 0;
|
||||
for (int i = 0; i < previousTausCount; i++)
|
||||
if (costForPreviousTau[i] < currentBestCost + penalty)
|
||||
previousTaus[newPreviousTausCount++] = previousTaus[i];
|
||||
|
||||
// We add a new tau value that is located on the `minDistance` distance from the next `currentTau` value
|
||||
previousTaus[newPreviousTausCount] = currentTau - minDistance + 1;
|
||||
previousTausCount = newPreviousTausCount + 1;
|
||||
}
|
||||
|
||||
// Here we collect the result list of changepoint indexes `changePointIndexes` using `previousChangePointIndex`
|
||||
var changePointIndexes = new List<int>();
|
||||
int currentIndex = previousChangePointIndex[n]; // The index of the end of the last segment is `n`
|
||||
while (currentIndex != 0)
|
||||
{
|
||||
changePointIndexes.Add(currentIndex - 1); // 1-based indexes should be be transformed to 0-based indexes
|
||||
currentIndex = previousChangePointIndex[currentIndex];
|
||||
}
|
||||
|
||||
changePointIndexes.Reverse(); // The result changepoints should be sorted in ascending order.
|
||||
return changePointIndexes.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partial sums for empirical CDF (formula (2.1) from Section 2.1 "Model" in [Haynes2017])
|
||||
/// <code>
|
||||
/// partialSums'[i, tau] = (count(data[j] < t) * 2 + count(data[j] == t) * 1) for j=0..tau-1
|
||||
/// where t is the i-th quantile value (see Section 3.1 "Discrete approximation" in [Haynes2017] for details)
|
||||
/// </code>
|
||||
/// In order to get better performance, we present
|
||||
/// a two-dimensional array <c>partialSums'[k, n + 1]</c> as a single-dimensional array <c>partialSums[k * (n + 1)]</c>.
|
||||
/// We assume that <c>partialSums'[i, tau] = partialSums[i * (n + 1) + tau]</c>
|
||||
/// <remarks>
|
||||
/// <list type="bullet">
|
||||
/// <item>
|
||||
/// We use doubled sum values in order to use <c>int[,]</c> instead of <c>double[,]</c> (it provides noticeable
|
||||
/// performance boost). Thus, multipliers for <c>count(data[j] < t)</c> and <c>count(data[j] == t)</c> are
|
||||
/// 2 and 1 instead of 1 and 0.5 from the [Haynes2017].
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// Note that these quantiles are not uniformly distributed: tails of the <c>data</c> distribution contain more
|
||||
/// quantile values than the center of the distribution
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
/// </summary>
|
||||
private static int[] GetPartialSums(double[] data, int k)
|
||||
{
|
||||
int n = data.Length;
|
||||
var partialSums = new int[k * (n + 1)];
|
||||
var sortedData = new double[data.Length];
|
||||
Array.Copy(data, sortedData, data.Length);
|
||||
Array.Sort(sortedData);
|
||||
|
||||
int offset = 0;
|
||||
for (int i = 0; i < k; i++)
|
||||
{
|
||||
double z = -1 + (2 * i + 1.0) / k; // Values from (-1+1/k) to (1-1/k) with step = 2/k
|
||||
double p = 1.0 / (1 + Math.Pow(2 * n - 1, -z)); // Values from 0.0 to 1.0
|
||||
double t = sortedData[(int) Math.Truncate((n - 1) * p)]; // Quantile value, formula (2.1) in [Haynes2017]
|
||||
|
||||
for (int tau = 1; tau <= n; tau++)
|
||||
{
|
||||
// `currentPartialSumsValue` is a temp variable to keep the future value of `partialSums[offset + tau]` (or `partialSums'[i, tau]`)
|
||||
int currentPartialSumsValue = partialSums[offset + tau - 1];
|
||||
if (data[tau - 1] < t)
|
||||
currentPartialSumsValue += 2; // We use doubled value (2) instead of original 1.0
|
||||
if (data[tau - 1] == t)
|
||||
currentPartialSumsValue += 1; // We use doubled value (1) instead of original 0.5
|
||||
|
||||
partialSums[offset + tau] = currentPartialSumsValue;
|
||||
}
|
||||
|
||||
offset += n + 1;
|
||||
}
|
||||
|
||||
return partialSums;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the cost of the (tau1; tau2] segment.
|
||||
/// </summary>
|
||||
private static double GetSegmentCost(int[] partialSums, int tau1, int tau2, int k, int n)
|
||||
{
|
||||
double sum = 0;
|
||||
int offset = tau1; // offset of partialSums'[i, tau1] in the single-dimenstional `partialSums` array
|
||||
int tauDiff = tau2 - tau1;
|
||||
for (int i = 0; i < k; i++)
|
||||
{
|
||||
// actualSum is (count(data[j] < t) * 2 + count(data[j] == t) * 1) for j=tau1..tau2-1
|
||||
int actualSum = partialSums[offset + tauDiff] - partialSums[offset]; // partialSums'[i, tau2] - partialSums'[i, tau1]
|
||||
|
||||
// We skip these two cases (correspond to fit = 0 or fit = 1) because of invalid Math.Log values
|
||||
if (actualSum != 0 && actualSum != tauDiff * 2)
|
||||
{
|
||||
// Empirical CDF $\hat{F}_i(t)$ (Section 2.1 "Model" in [Haynes2017])
|
||||
double fit = actualSum * 0.5 / tauDiff;
|
||||
|
||||
// Segment cost $\mathcal{L}_{np}$ (Section 2.2 "Nonparametric maximum likelihood" in [Haynes2017])
|
||||
double lnp = tauDiff * (fit * Math.Log(fit) + (1 - fit) * Math.Log(1 - fit));
|
||||
sum += lnp;
|
||||
}
|
||||
|
||||
offset += n + 1;
|
||||
}
|
||||
|
||||
double c = -Math.Log(2 * n - 1); // Constant from Lemma 3.1 in [Haynes2017]
|
||||
return 2.0 * c / k * sum; // See Section 3.1 "Discrete approximation" in [Haynes2017]
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the index of the minimum element in the given range.
|
||||
/// </summary>
|
||||
/// <param name="source">An array of <see cref="T:System.Double"></see> values to determine the minimum element of</param>
|
||||
/// <param name="length">The actual number of values that will be used for search (only values form the 0..(length-1) will be used)</param>
|
||||
/// <returns>The index of the minimum element in range 0..(length-1)</returns>
|
||||
/// <exception cref="InvalidOperationException"><paramref name="source">source</paramref> contains no elements</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="length">length</paramref> is not positive or less than <paramref name="source">source</paramref>.Length</exception>
|
||||
private static int WhichMin(double[] source, int length)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
throw new InvalidOperationException($"{nameof(source)} should contain elements");
|
||||
if (length <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), length, $"{nameof(length)} should be positive");
|
||||
if (length > source.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), length, $"{nameof(length)} should be greater or equal to {nameof(source)}.Length");
|
||||
|
||||
double minValue = source[0];
|
||||
int minIndex = 0;
|
||||
for (int i = 1; i < length; i++)
|
||||
if (source[i] < minValue)
|
||||
{
|
||||
minValue = source[i];
|
||||
minIndex = i;
|
||||
}
|
||||
|
||||
return minIndex;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,169 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics
|
||||
{
|
||||
public enum ConfidenceLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// 50.0% confidence interval
|
||||
/// </summary>
|
||||
[PublicAPI] L50,
|
||||
|
||||
/// <summary>
|
||||
/// 70.0% confidence interval
|
||||
/// </summary>
|
||||
[PublicAPI] L70,
|
||||
|
||||
/// <summary>
|
||||
/// 75.0% confidence interval
|
||||
/// </summary>
|
||||
[PublicAPI] L75,
|
||||
|
||||
/// <summary>
|
||||
/// 80.0% confidence interval
|
||||
/// </summary>
|
||||
[PublicAPI] L80,
|
||||
|
||||
/// <summary>
|
||||
/// 85.0% confidence interval
|
||||
/// </summary>
|
||||
[PublicAPI] L85,
|
||||
|
||||
/// <summary>
|
||||
/// 90.0% confidence interval
|
||||
/// </summary>
|
||||
[PublicAPI] L90,
|
||||
|
||||
/// <summary>
|
||||
/// 92.0% confidence interval
|
||||
/// </summary>
|
||||
[PublicAPI] L92,
|
||||
|
||||
/// <summary>
|
||||
/// 95.0% confidence interval
|
||||
/// </summary>
|
||||
[PublicAPI] L95,
|
||||
|
||||
/// <summary>
|
||||
/// 96.0% confidence interval
|
||||
/// </summary>
|
||||
[PublicAPI] L96,
|
||||
|
||||
/// <summary>
|
||||
/// 97.0% confidence interval
|
||||
/// </summary>
|
||||
[PublicAPI] L97,
|
||||
|
||||
/// <summary>
|
||||
/// 98.0% confidence interval
|
||||
/// </summary>
|
||||
[PublicAPI] L98,
|
||||
|
||||
/// <summary>
|
||||
/// 99.0% confidence interval
|
||||
/// </summary>
|
||||
[PublicAPI] L99,
|
||||
|
||||
/// <summary>
|
||||
/// 99.9% confidence interval
|
||||
/// </summary>
|
||||
[PublicAPI] L999
|
||||
}
|
||||
|
||||
public static class ConfidenceLevelExtensions
|
||||
{
|
||||
private static readonly Dictionary<ConfidenceLevel, (int value, int digits)> ConfidenceLevelDetails = CreateConfidenceLevelMapping();
|
||||
|
||||
/// <summary>
|
||||
/// Calculates Z value (z-star) for confidence interval
|
||||
/// </summary>
|
||||
/// <param name="level">ConfidenceLevel for a confidence interval</param>
|
||||
/// <param name="n">Sample size (n >= 3)</param>
|
||||
public static double GetZValue(this ConfidenceLevel level, int n)
|
||||
{
|
||||
if (n <= 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(n), "n should be >= 2");
|
||||
return MathHelper.InverseStudent(1 - level.ToPercent(), n - 1);
|
||||
}
|
||||
|
||||
public static string ToPercentStr(this ConfidenceLevel level)
|
||||
{
|
||||
string s = level.ToString().Substring(1);
|
||||
if (s.Length > 2)
|
||||
s = s.Substring(0, 2) + "." + s.Substring(2);
|
||||
return s + "%";
|
||||
}
|
||||
|
||||
[PublicAPI] public static double ToPercent(this ConfidenceLevel level)
|
||||
{
|
||||
(int value, int digits) = ConfidenceLevelDetails[level];
|
||||
|
||||
return value / Math.Pow(10, digits);
|
||||
}
|
||||
|
||||
private static Dictionary<ConfidenceLevel, (int value, int length)> CreateConfidenceLevelMapping()
|
||||
=> Enum.GetValues(typeof(ConfidenceLevel))
|
||||
.Cast<ConfidenceLevel>()
|
||||
.ToDictionary(
|
||||
confidenceLevel => confidenceLevel,
|
||||
confidenceLevel =>
|
||||
{
|
||||
string textRepresentation = confidenceLevel.ToString().Substring(1);
|
||||
|
||||
return (int.Parse(textRepresentation), textRepresentation.Length);
|
||||
});
|
||||
}
|
||||
|
||||
public struct ConfidenceInterval
|
||||
{
|
||||
[PublicAPI] public int N { get; }
|
||||
[PublicAPI] public double Mean { get; }
|
||||
[PublicAPI] public double StandardError { get; }
|
||||
|
||||
[PublicAPI] public ConfidenceLevel Level { get; }
|
||||
[PublicAPI] public double Margin { get; }
|
||||
|
||||
[PublicAPI] public double Lower { get; }
|
||||
[PublicAPI] public double Upper { get; }
|
||||
|
||||
public ConfidenceInterval(double mean, double standardError, int n, ConfidenceLevel level = ConfidenceLevel.L999)
|
||||
{
|
||||
N = n;
|
||||
Mean = mean;
|
||||
StandardError = standardError;
|
||||
Level = level;
|
||||
Margin = n <= 2 ? double.NaN : standardError * level.GetZValue(n);
|
||||
Lower = mean - Margin;
|
||||
Upper = mean + Margin;
|
||||
}
|
||||
|
||||
public bool Contains(double value) => Lower - 1e-9 < value && value < Upper + 1e-9;
|
||||
|
||||
private string GetLevelHint(bool showLevel = true) => showLevel ? $" (CI {Level.ToPercentStr()})" : "";
|
||||
|
||||
public override string ToString() => ToString(DefaultCultureInfo.Instance);
|
||||
|
||||
public string ToString(CultureInfo cultureInfo, string format = "0.##", bool showLevel = true)
|
||||
{
|
||||
return ToString(x => x.ToString(format, cultureInfo), showLevel);
|
||||
}
|
||||
|
||||
public string ToString(Func<double, string> formatter, bool showLevel = true)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append('[');
|
||||
builder.Append(formatter(Lower));
|
||||
builder.Append("; ");
|
||||
builder.Append(formatter(Upper));
|
||||
builder.Append("]");
|
||||
builder.Append(GetLevelHint(showLevel));
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics.Histograms
|
||||
{
|
||||
public class AdaptiveHistogramBuilder : IHistogramBuilder
|
||||
{
|
||||
[PublicAPI, Pure]
|
||||
public Histogram Build(Statistics s, BinSizeRule? rule = null)
|
||||
{
|
||||
double binSize = s.GetOptimalBinSize(rule);
|
||||
if (Math.Abs(binSize) < 1e-9)
|
||||
binSize = 1;
|
||||
return BuildWithFixedBinSize(s.SortedValues, binSize);
|
||||
}
|
||||
|
||||
private const double Resolution = 0.0001;
|
||||
|
||||
// TODO: Optimize
|
||||
[PublicAPI, Pure]
|
||||
public Histogram BuildWithFixedBinSize(IEnumerable<double> values, double binSize)
|
||||
{
|
||||
const double eps = 1e-9;
|
||||
const double margin = 0.1;
|
||||
const double adaptiveFactor = 0.02;
|
||||
|
||||
if (binSize < eps)
|
||||
throw new ArgumentException($"binSize ({binSize.ToString("0.##", DefaultCultureInfo.Instance)}) should be a positive number", nameof(binSize));
|
||||
if (binSize < Resolution)
|
||||
binSize = Resolution;
|
||||
binSize = NiceCeiling(binSize);
|
||||
|
||||
var list = values.ToList();
|
||||
if (list.IsEmpty())
|
||||
throw new ArgumentException("Values should be non-empty", nameof(values));
|
||||
|
||||
list.Sort();
|
||||
if (list.Last() - list.First() < binSize)
|
||||
{
|
||||
double center = (list.First() + list.Last()) / 2;
|
||||
double lower = center - binSize / 2;
|
||||
double upper = center + binSize / 2;
|
||||
return new Histogram(binSize, new[] { new HistogramBin(lower, upper, list.ToArray()) });
|
||||
}
|
||||
|
||||
var points = new List<double> { NiceFloor(list.Min() - binSize / 2), NiceCeiling(list.Max() + binSize / 2) };
|
||||
int processedPointCount = 0;
|
||||
while (true)
|
||||
{
|
||||
if (points.Count > 10 * list.Count)
|
||||
{
|
||||
var errorMessage = new StringBuilder();
|
||||
errorMessage.AppendLine("Failed to run AdaptiveHistogramBuilder.BuildWithFixedBinSize");
|
||||
errorMessage.AppendLine("BinSize: " + binSize.ToString("N12", DefaultCultureInfo.Instance));
|
||||
errorMessage.AppendLine("Values: ");
|
||||
foreach (double value in list)
|
||||
errorMessage.AppendLine(" " + value.ToString("N12", DefaultCultureInfo.Instance));
|
||||
throw new InvalidOperationException(errorMessage.ToString());
|
||||
}
|
||||
|
||||
int pointIndex = -1;
|
||||
for (int i = processedPointCount; i < points.Count - 1; i++)
|
||||
{
|
||||
double adaptiveBinSize = (points[i] + points[i + 1]) / 2.0 * adaptiveFactor;
|
||||
double maxSize = Math.Max(binSize * (1.0 + 2 * margin), adaptiveBinSize);
|
||||
if (points[i + 1] - points[i] > maxSize)
|
||||
{
|
||||
pointIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pointIndex == -1)
|
||||
break;
|
||||
|
||||
double lower = points[pointIndex];
|
||||
double upper = points[pointIndex + 1];
|
||||
|
||||
int bestIndex1 = -1;
|
||||
int bestIndex2 = -1;
|
||||
int bestCount = -1;
|
||||
double bestDist = double.MaxValue;
|
||||
|
||||
bool Inside(double x) => x > lower - eps && x < upper - eps;
|
||||
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
if (Inside(list[i]))
|
||||
{
|
||||
int j = i;
|
||||
while (j < list.Count && Inside(list[j]) && list[j] - list[i] < binSize)
|
||||
j++;
|
||||
int count = j - i;
|
||||
double dist = list[j - 1] - list[i];
|
||||
if (count > bestCount || count == bestCount && dist < bestDist)
|
||||
{
|
||||
bestCount = count;
|
||||
bestIndex1 = i;
|
||||
bestIndex2 = j - 1;
|
||||
bestDist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestIndex1 != -1)
|
||||
{
|
||||
double center = (list[bestIndex1] + list[bestIndex2]) / 2.0;
|
||||
double adaptiveBinSize = Math.Max(binSize, center * adaptiveFactor);
|
||||
double left = NiceFloor(center - adaptiveBinSize / 2);
|
||||
double right = NiceFloor(Math.Min(center + adaptiveBinSize / 2, upper));
|
||||
|
||||
if (left > lower + binSize * margin)
|
||||
points.Insert(pointIndex + 1, left);
|
||||
else if (right < upper - binSize * margin && right > lower + binSize * margin)
|
||||
{
|
||||
points.Insert(pointIndex + 1, right);
|
||||
processedPointCount++;
|
||||
}
|
||||
else
|
||||
processedPointCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
points.Insert(pointIndex + 1, NiceFloor(lower + binSize));
|
||||
processedPointCount++;
|
||||
}
|
||||
}
|
||||
|
||||
var bins = new List<HistogramBin>(points.Count - 1);
|
||||
int counter = 0;
|
||||
for (int i = 0; i < points.Count - 1; i++)
|
||||
{
|
||||
var bin = new List<double>();
|
||||
double lower = points[i];
|
||||
double upper = points[i + 1];
|
||||
|
||||
while (counter < list.Count && (list[counter] < upper || i == points.Count - 1))
|
||||
bin.Add(list[counter++]);
|
||||
|
||||
bins.Add(new HistogramBin(lower, upper, bin.ToArray()));
|
||||
}
|
||||
|
||||
// Trim
|
||||
while (bins.Any() && bins.First().IsEmpty)
|
||||
bins.RemoveAt(0);
|
||||
while (bins.Any() && bins.Last().IsEmpty)
|
||||
bins.RemoveAt(bins.Count - 1);
|
||||
|
||||
// Join small bins to neighbors
|
||||
counter = 0;
|
||||
double lastValue = 0;
|
||||
while (counter < bins.Count)
|
||||
{
|
||||
if (bins[counter].HasAny)
|
||||
lastValue = Math.Max(lastValue, bins[counter].Values.Last());
|
||||
double adaptiveThreshold = Math.Max(binSize / 2, lastValue * adaptiveFactor);
|
||||
if (bins[counter].Gap < adaptiveThreshold)
|
||||
{
|
||||
double leftGap = counter > 0 ? bins[counter - 1].Gap : double.MaxValue;
|
||||
double rightGap = counter < bins.Count - 1 ? bins[counter + 1].Gap : double.MaxValue;
|
||||
if (leftGap < rightGap && counter > 0)
|
||||
{
|
||||
bins[counter - 1] = HistogramBin.Union(bins[counter - 1], bins[counter]);
|
||||
bins.RemoveAt(counter);
|
||||
}
|
||||
else if (counter < bins.Count - 1)
|
||||
{
|
||||
bins[counter] = HistogramBin.Union(bins[counter], bins[counter + 1]);
|
||||
bins.RemoveAt(counter + 1);
|
||||
}
|
||||
else
|
||||
counter++;
|
||||
}
|
||||
else
|
||||
counter++;
|
||||
}
|
||||
|
||||
return new Histogram(binSize, bins.ToArray());
|
||||
}
|
||||
|
||||
private static double NiceFloor(double value) => Math.Floor(value / Resolution) * Resolution;
|
||||
private static double NiceCeiling(double value) => Math.Ceiling(value / Resolution) * Resolution;
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
namespace BenchmarkDotNet.Mathematics.Histograms
|
||||
{
|
||||
public enum BinSizeRule
|
||||
{
|
||||
FreedmanDiaconis,
|
||||
|
||||
Scott,
|
||||
|
||||
Scott2,
|
||||
|
||||
SquareRoot,
|
||||
|
||||
Sturges,
|
||||
|
||||
Rice
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics.Histograms
|
||||
{
|
||||
[PublicAPI]
|
||||
public class Histogram
|
||||
{
|
||||
[PublicAPI]
|
||||
public double BinSize { get; }
|
||||
|
||||
[PublicAPI, NotNull]
|
||||
public HistogramBin[] Bins { get; }
|
||||
|
||||
[PublicAPI, Pure]
|
||||
public string ToString(Func<double, string> formatter, char binSymbol = '@', bool full = false)
|
||||
{
|
||||
var lower = new string[Bins.Length];
|
||||
var upper = new string[Bins.Length];
|
||||
for (int i = 0; i < Bins.Length; i++)
|
||||
{
|
||||
lower[i] = formatter(Bins[i].Lower);
|
||||
upper[i] = formatter(Bins[i].Upper);
|
||||
}
|
||||
|
||||
int lowerWidth = lower.Max(it => it.Length);
|
||||
int upperWidth = upper.Max(it => it.Length);
|
||||
|
||||
var builder = new StringBuilder();
|
||||
for (int i = 0; i < Bins.Length; i++)
|
||||
{
|
||||
string intervalStr = $"[{lower[i].PadLeft(lowerWidth)} ; {upper[i].PadLeft(upperWidth)})";
|
||||
string barStr = full
|
||||
? string.Join(", ", Bins[i].Values.Select(formatter))
|
||||
: new string(binSymbol, Bins[i].Count);
|
||||
builder.AppendLine($"{intervalStr} | {barStr}");
|
||||
}
|
||||
|
||||
return builder.ToString().Trim();
|
||||
}
|
||||
|
||||
public override string ToString() => ToString(x => x.ToString("0.000", DateTimeFormatInfo.CurrentInfo));
|
||||
|
||||
internal Histogram(double binSize, [NotNull] HistogramBin[] bins)
|
||||
{
|
||||
BinSize = binSize;
|
||||
Bins = bins;
|
||||
}
|
||||
|
||||
// For unit tests
|
||||
[Pure, NotNull]
|
||||
internal static Histogram BuildManual(double binSize, [NotNull] double[][] bins)
|
||||
{
|
||||
var histogramBins = bins.Select(bin => new HistogramBin(bin.Any() ? bin.Min() : 0, bin.Any() ? bin.Max() : 0, bin)).ToArray();
|
||||
return new Histogram(binSize, histogramBins);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics.Histograms
|
||||
{
|
||||
public class HistogramBin
|
||||
{
|
||||
public double Lower { get; }
|
||||
public double Upper { get; }
|
||||
public double[] Values { get; }
|
||||
|
||||
public int Count => Values.Length;
|
||||
public double Gap => Upper - Lower;
|
||||
public bool IsEmpty => Count == 0;
|
||||
public bool HasAny => Count > 0;
|
||||
|
||||
public HistogramBin(double lower, double upper, double[] values)
|
||||
{
|
||||
Lower = lower;
|
||||
Upper = upper;
|
||||
Values = values;
|
||||
}
|
||||
|
||||
public static HistogramBin Union(HistogramBin bin1, HistogramBin bin2) => new HistogramBin(
|
||||
Math.Min(bin1.Lower, bin2.Lower),
|
||||
Math.Max(bin1.Upper, bin2.Upper),
|
||||
bin1.Values.Union(bin2.Values).OrderBy(value => value).ToArray());
|
||||
|
||||
public override string ToString() => ToString(DefaultCultureInfo.Instance);
|
||||
|
||||
[PublicAPI] public string ToString(CultureInfo cultureInfo)
|
||||
{
|
||||
var unit = TimeUnit.GetBestTimeUnit(Values);
|
||||
var builder = new StringBuilder();
|
||||
builder.Append('[');
|
||||
builder.Append(TimeInterval.FromNanoseconds(Lower).ToString(unit, cultureInfo));
|
||||
builder.Append(';');
|
||||
builder.Append(TimeInterval.FromNanoseconds(Upper).ToString(unit, cultureInfo));
|
||||
builder.Append(' ');
|
||||
builder.Append('{');
|
||||
for (var i = 0; i < Values.Length; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
builder.Append("; ");
|
||||
builder.Append(TimeInterval.FromNanoseconds(Values[i]).ToString(unit, cultureInfo));
|
||||
}
|
||||
builder.Append('}');
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics.Histograms
|
||||
{
|
||||
[PublicAPI]
|
||||
public static class HistogramBuilder
|
||||
{
|
||||
[PublicAPI] public static readonly IHistogramBuilder Simple = new SimpleHistogramBuilder();
|
||||
[PublicAPI] public static readonly IHistogramBuilder Adaptive = new AdaptiveHistogramBuilder();
|
||||
|
||||
[PublicAPI] public static readonly IHistogramBuilder[] AllBuilders = { Simple, Adaptive };
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics.Histograms
|
||||
{
|
||||
[PublicAPI]
|
||||
public static class HistogramExtensions
|
||||
{
|
||||
[PublicAPI, Pure]
|
||||
public static int GetBinCount(this Histogram histogram) => histogram.Bins.Length;
|
||||
|
||||
[PublicAPI, Pure, NotNull]
|
||||
public static IEnumerable<double> GetAllValues([NotNull] this Histogram histogram) => histogram.Bins.SelectMany(bin => bin.Values);
|
||||
|
||||
public static Func<double, string> CreateNanosecondFormatter(this Histogram histogram, CultureInfo cultureInfo = null, string format = "0.000")
|
||||
{
|
||||
var timeUnit = TimeUnit.GetBestTimeUnit(histogram.Bins.SelectMany(bin => bin.Values).ToArray());
|
||||
return value => TimeInterval.FromNanoseconds(value).ToString(timeUnit, cultureInfo, format);
|
||||
}
|
||||
|
||||
[PublicAPI, Pure]
|
||||
public static double GetOptimalBinSize([NotNull] this Statistics s, BinSizeRule? rule = null)
|
||||
{
|
||||
const BinSizeRule defaultRule = BinSizeRule.Scott2;
|
||||
switch (rule ?? defaultRule)
|
||||
{
|
||||
case BinSizeRule.FreedmanDiaconis:
|
||||
return 2 * s.InterquartileRange / Math.Pow(s.N, 1.0 / 3);
|
||||
case BinSizeRule.Scott:
|
||||
return 3.5 * s.StandardDeviation / Math.Pow(s.N, 1.0 / 3);
|
||||
case BinSizeRule.Scott2:
|
||||
return 3.5 * s.StandardDeviation / Math.Pow(s.N, 1.0 / 3) / 2.0;
|
||||
case BinSizeRule.SquareRoot:
|
||||
return (s.Max - s.Min) / Math.Sqrt(s.N);
|
||||
case BinSizeRule.Sturges:
|
||||
return (s.Max - s.Min) / (Math.Ceiling(Math.Log(s.N, 2)) + 1);
|
||||
case BinSizeRule.Rice:
|
||||
return (s.Max - s.Min) / (2 * Math.Pow(s.N, 1.0 / 3));
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(rule), rule, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics.Histograms
|
||||
{
|
||||
public interface IHistogramBuilder
|
||||
{
|
||||
[PublicAPI, Pure, NotNull]
|
||||
Histogram Build(Statistics s, BinSizeRule? rule = null);
|
||||
|
||||
[PublicAPI, Pure, NotNull]
|
||||
Histogram BuildWithFixedBinSize(IEnumerable<double> values, double binSize);
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics.Histograms
|
||||
{
|
||||
internal class SimpleHistogramBuilder : IHistogramBuilder
|
||||
{
|
||||
[PublicAPI, Pure]
|
||||
public Histogram Build(Statistics s, BinSizeRule? rule = null)
|
||||
{
|
||||
double binSize = s.GetOptimalBinSize(rule);
|
||||
return BuildWithFixedBinSize(s.SortedValues, binSize);
|
||||
}
|
||||
|
||||
[PublicAPI, Pure]
|
||||
public Histogram BuildWithFixedBinSize(IEnumerable<double> values, double binSize)
|
||||
{
|
||||
if (binSize < 1e-9)
|
||||
throw new ArgumentException($"binSize ({binSize.ToString("0.##", DefaultCultureInfo.Instance)}) should be a positive number", nameof(binSize));
|
||||
|
||||
var list = values.ToList();
|
||||
if (list.IsEmpty())
|
||||
throw new ArgumentException("Values should be non-empty", nameof(values));
|
||||
|
||||
list.Sort();
|
||||
|
||||
int firstBin = GetBinIndex(list.First(), binSize);
|
||||
int lastBin = GetBinIndex(list.Last(), binSize);
|
||||
int binCount = lastBin - firstBin + 1;
|
||||
|
||||
var bins = new HistogramBin[binCount];
|
||||
int counter = 0;
|
||||
for (int i = 0; i < bins.Length; i++)
|
||||
{
|
||||
var bin = new List<double>();
|
||||
double lower = (firstBin + i) * binSize;
|
||||
double upper = (firstBin + i + 1) * binSize;
|
||||
|
||||
while (counter < list.Count && (list[counter] < upper || i == bins.Length - 1))
|
||||
bin.Add(list[counter++]);
|
||||
|
||||
bins[i] = new HistogramBin(lower, upper, bin.ToArray());
|
||||
}
|
||||
|
||||
return new Histogram(binSize, bins);
|
||||
}
|
||||
|
||||
private static int GetBinIndex(double value, double binSize) => (int) Math.Floor(value / binSize);
|
||||
|
||||
}
|
||||
}
|
|
@ -1,192 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Mathematics.Histograms;
|
||||
using JetBrains.Annotations;
|
||||
using static System.Math;
|
||||
using static System.Math;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics
|
||||
{
|
||||
public static class MathHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// ACM Algorithm 209: Gauss
|
||||
///
|
||||
/// Calculates $(1/\sqrt{2\pi}) \int_{-\infty}^x e^{-u^2 / 2} du$
|
||||
/// by means of polynomial approximations due to A. M. Murray of Aberdeen University;
|
||||
///
|
||||
/// See: http://dl.acm.org/citation.cfm?id=367664
|
||||
/// </summary>
|
||||
/// <param name="x">-infinity..+infinity</param>
|
||||
/// <returns>Area under the Standard Normal Curve from -infinity to x</returns>
|
||||
[PublicAPI]
|
||||
public static double Gauss(double x)
|
||||
{
|
||||
double z;
|
||||
if (Abs(x) < 1e-9)
|
||||
z = 0.0;
|
||||
else
|
||||
{
|
||||
double y = Abs(x) / 2;
|
||||
if (y >= 3.0)
|
||||
z = 1.0;
|
||||
else if (y < 1.0)
|
||||
{
|
||||
double w = y * y;
|
||||
z = ((((((((0.000124818987 * w - 0.001075204047) * w + 0.005198775019) * w - 0.019198292004) * w +
|
||||
0.059054035642) * w - 0.151968751364) * w + 0.319152932694) * w - 0.531923007300) * w +
|
||||
0.797884560593) * y * 2.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
y = y - 2.0;
|
||||
z = (((((((((((((-0.000045255659 * y + 0.000152529290) * y - 0.000019538132) * y - 0.000676904986) *
|
||||
y + 0.001390604284) * y - 0.000794620820) * y - 0.002034254874) * y + 0.006549791214) *
|
||||
y - 0.010557625006) * y + 0.011630447319) * y - 0.009279453341) * y + 0.005353579108) * y -
|
||||
0.002141268741) * y + 0.000535310849) * y + 0.999936657524;
|
||||
}
|
||||
}
|
||||
|
||||
return x > 0.0 ? (z + 1.0) / 2 : (1.0 - z) / 2;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ACM Algorithm 395: Student's t-distribution
|
||||
///
|
||||
/// Evaluates the two-tail probability P(t|n) that t is exceeded
|
||||
/// in magnitude for Student's t-distribution with n degrees of freedom.
|
||||
///
|
||||
/// http://dl.acm.org/citation.cfm?id=355599
|
||||
/// </summary>
|
||||
/// <param name="t">t-value, t > 0</param>
|
||||
/// <param name="n">Degree of freedom, n >= 1</param>
|
||||
/// <returns>2-tail p-value</returns>
|
||||
public static double StudentTwoTail(double t, double n)
|
||||
{
|
||||
if (t < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(t), "t should be >= 0");
|
||||
if (n < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(n), "n should be >= 1");
|
||||
t = t.Sqr();
|
||||
double y = t / n;
|
||||
double b = y + 1.0;
|
||||
int nn = (int) Round(n);
|
||||
if (Abs(n - nn) > 1e-9 || n >= 20 || t < n && n > 200)
|
||||
{
|
||||
if (y > 1.0e-6)
|
||||
y = Log(b);
|
||||
double a = n - 0.5;
|
||||
b = 48.0 * a.Sqr();
|
||||
y = a * y;
|
||||
y = (((((-0.4 * y - 3.3) * y - 24.0) * y - 85.5) / (0.8 * y.Sqr() + 100.0 + b) + y + 3.0) / b + 1.0) * Sqrt(y);
|
||||
return 2 * Gauss(-y);
|
||||
}
|
||||
|
||||
{
|
||||
double z = 1;
|
||||
|
||||
double a;
|
||||
if (n < 20 && t < 4.0)
|
||||
{
|
||||
y = Sqrt(y);
|
||||
a = y;
|
||||
if (nn == 1)
|
||||
a = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = Sqrt(b);
|
||||
y = a * nn;
|
||||
int j = 0;
|
||||
while (Abs(a - z) > 0)
|
||||
{
|
||||
j += 2;
|
||||
z = a;
|
||||
y *= (j - 1) / (b * j);
|
||||
a += y / (nn + j);
|
||||
}
|
||||
|
||||
nn += 2;
|
||||
z = 0;
|
||||
y = 0;
|
||||
a = -a;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
nn -= 2;
|
||||
if (nn > 1)
|
||||
a = (nn - 1) / (b * nn) * a + y;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
a = nn == 0 ? a / Sqrt(b) : (Atan(y) + a / b) * 2 / PI;
|
||||
return z - a;
|
||||
}
|
||||
}
|
||||
|
||||
public static double StudentOneTail(double t, double n) => t > 0
|
||||
? 1 - StudentTwoTail(t, n) / 2
|
||||
: 1 - StudentOneTail(-t, n);
|
||||
|
||||
// TODO: Optimize
|
||||
public static double InverseStudent(double p, double n)
|
||||
{
|
||||
double lower = 0.0;
|
||||
double upper = 1000.0;
|
||||
while (upper - lower > 1e-9)
|
||||
{
|
||||
double t = (lower + upper) / 2;
|
||||
double p2 = StudentTwoTail(t, n);
|
||||
if (p2 < p)
|
||||
upper = t;
|
||||
else
|
||||
lower = t;
|
||||
}
|
||||
|
||||
return (lower + upper) / 2;
|
||||
}
|
||||
|
||||
// See http://www.brendangregg.com/FrequencyTrails/modes.html
|
||||
[PublicAPI]
|
||||
public static double CalculateMValue([NotNull] Statistics originalStatistics)
|
||||
{
|
||||
try
|
||||
{
|
||||
var s = new Statistics(originalStatistics.WithoutOutliers());
|
||||
|
||||
double mValue = 0;
|
||||
|
||||
double binSize = s.GetOptimalBinSize();
|
||||
if (Abs(binSize) < 1e-9)
|
||||
binSize = 1;
|
||||
while (true)
|
||||
{
|
||||
var histogram = HistogramBuilder.Adaptive.BuildWithFixedBinSize(s.SortedValues, binSize);
|
||||
var x = new List<int> { 0 };
|
||||
x.AddRange(histogram.Bins.Select(bin => bin.Count));
|
||||
x.Add(0);
|
||||
|
||||
int sum = 0;
|
||||
for (int i = 1; i < x.Count; i++)
|
||||
sum += Abs(x[i] - x[i - 1]);
|
||||
mValue = Max(mValue, sum * 1.0 / x.Max());
|
||||
|
||||
if (binSize > s.Max - s.Min)
|
||||
break;
|
||||
binSize *= 2.0;
|
||||
}
|
||||
|
||||
return mValue;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return 1; // In case of any bugs, we return 1 because it's an invalid value (mvalue is always >= 2)
|
||||
}
|
||||
}
|
||||
|
||||
public static int Clamp(int value, int min, int max) => Min(Max(value, min), max);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
using System.Collections.Generic;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Mathematics.Common;
|
||||
using Perfolizer.Mathematics.OutlierDetection;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics
|
||||
{
|
||||
|
@ -136,20 +138,14 @@ namespace BenchmarkDotNet.Mathematics
|
|||
{
|
||||
switch (outlierMode)
|
||||
{
|
||||
#pragma warning disable 618
|
||||
case OutlierMode.None:
|
||||
case OutlierMode.DontRemove:
|
||||
return false;
|
||||
case OutlierMode.OnlyUpper:
|
||||
case OutlierMode.RemoveUpper:
|
||||
return value > upperFence;
|
||||
case OutlierMode.OnlyLower:
|
||||
case OutlierMode.RemoveLower:
|
||||
return value < lowerFence;
|
||||
case OutlierMode.All:
|
||||
case OutlierMode.RemoveAll:
|
||||
return value < lowerFence || value > upperFence;
|
||||
#pragma warning restore 618
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(outlierMode), outlierMode, null);
|
||||
}
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics
|
||||
{
|
||||
/// <summary>
|
||||
/// The enum is design to remove some outliers from the distribution.
|
||||
/// </summary>
|
||||
public enum OutlierMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Don't remove outliers.
|
||||
/// </summary>
|
||||
[Obsolete("Use DontRemoveOutliers")]
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Remove only upper outliers (which is bigger than upperFence).
|
||||
/// </summary>
|
||||
[Obsolete("Use RemoveUpperOutliers")]
|
||||
OnlyUpper,
|
||||
|
||||
/// <summary>
|
||||
/// Remove only lower outliers (which is smaller than lowerFence).
|
||||
/// </summary>
|
||||
[Obsolete("Use RemoveUpperOutliers")]
|
||||
OnlyLower,
|
||||
|
||||
/// <summary>
|
||||
/// Remove all outliers.
|
||||
/// </summary>
|
||||
[Obsolete("Use RemoveAllOutliers")]
|
||||
All,
|
||||
|
||||
/// <summary>
|
||||
/// Don't remove outliers.
|
||||
/// </summary>
|
||||
DontRemove,
|
||||
|
||||
/// <summary>
|
||||
/// Remove only upper outliers (which is bigger than upperFence).
|
||||
/// </summary>
|
||||
RemoveUpper,
|
||||
|
||||
/// <summary>
|
||||
/// Remove only lower outliers (which is smaller than lowerFence).
|
||||
/// </summary>
|
||||
RemoveLower,
|
||||
|
||||
/// <summary>
|
||||
/// Remove all outliers.
|
||||
/// </summary>
|
||||
RemoveAll
|
||||
}
|
||||
}
|
|
@ -2,10 +2,9 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Mathematics.QuantileEstimators;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics
|
||||
{
|
||||
|
@ -30,22 +29,14 @@ namespace BenchmarkDotNet.Mathematics
|
|||
if (percentile < 0 || percentile > 100)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(percentile), percentile,
|
||||
"The percentile arg should be in range of 0 - 100.");
|
||||
nameof(percentile), percentile,
|
||||
"The percentile arg should be in range of 0 - 100.");
|
||||
}
|
||||
|
||||
if (sortedValues.Count == 0)
|
||||
return 0;
|
||||
|
||||
// DONTTOUCH: the following code was taken from http://stackoverflow.com/a/8137526 and it is proven
|
||||
// to work in the same way the excel's counterpart does.
|
||||
// So it's better to leave it as it is unless you do not want to reimplement it from scratch:)
|
||||
double realIndex = percentile / 100.0 * (sortedValues.Count - 1);
|
||||
int index = (int)realIndex;
|
||||
double frac = realIndex - index;
|
||||
if (index + 1 < sortedValues.Count)
|
||||
return sortedValues[index] * (1 - frac) + sortedValues[index + 1] * frac;
|
||||
return sortedValues[index];
|
||||
return SimpleQuantileEstimator.Instance.GetQuantileFromSorted(sortedValues, percentile / 100.0);
|
||||
}
|
||||
|
||||
[PublicAPI] public double Percentile(int percentile) => Percentile(SortedValues, percentile);
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics
|
||||
{
|
||||
internal static class RandomExtensions
|
||||
{
|
||||
// See https://stackoverflow.com/questions/218060/random-gaussian-variables
|
||||
public static double NextGaussian(this Random random, double mean = 0, double stdDev = 1)
|
||||
{
|
||||
double stdDevFactor = Math.Sqrt(-2.0 * Math.Log(random.NextDouble())) * Math.Sin(2.0 * Math.PI * random.NextDouble());
|
||||
return mean + stdDev * stdDevFactor;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Mathematics.StatisticalTesting;
|
||||
using JetBrains.Annotations;
|
||||
using Perfolizer.Mathematics.SignificanceTesting;
|
||||
using Perfolizer.Mathematics.Thresholds;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics
|
||||
{
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
using System;
|
||||
using BenchmarkDotNet.Extensions;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics.StatisticalTesting
|
||||
{
|
||||
public class AbsoluteThreshold : Threshold
|
||||
{
|
||||
private readonly double value;
|
||||
|
||||
public AbsoluteThreshold(double value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public override double GetValue(Statistics x) => value;
|
||||
|
||||
public override bool IsZero() => Math.Abs(value) < 1e-9;
|
||||
public override string ToString() => value.ToString("0.##", DefaultCultureInfo.Instance);
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
using System;
|
||||
using BenchmarkDotNet.Helpers;
|
||||
using BenchmarkDotNet.Horology;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics.StatisticalTesting
|
||||
{
|
||||
public class AbsoluteTimeThreshold : AbsoluteThreshold, IEquatable<AbsoluteTimeThreshold>
|
||||
{
|
||||
private readonly TimeInterval timeInterval;
|
||||
|
||||
public AbsoluteTimeThreshold(TimeInterval timeInterval) : base(timeInterval.Nanoseconds) => this.timeInterval = timeInterval;
|
||||
|
||||
public override string ToString() => timeInterval.ToString(DefaultCultureInfo.Instance, format: "0.##");
|
||||
|
||||
public bool Equals(AbsoluteTimeThreshold other) => other != null && timeInterval.Equals(other.timeInterval);
|
||||
|
||||
public override bool Equals(object obj) => obj is AbsoluteTimeThreshold other && Equals(other);
|
||||
|
||||
public override int GetHashCode() => timeInterval.GetHashCode();
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
namespace BenchmarkDotNet.Mathematics.StatisticalTesting
|
||||
{
|
||||
public enum EquivalenceTestConclusion
|
||||
{
|
||||
Base,
|
||||
Same,
|
||||
Faster,
|
||||
Slower,
|
||||
Unknown
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
namespace BenchmarkDotNet.Mathematics.StatisticalTesting
|
||||
{
|
||||
public class EquivalenceTestResult
|
||||
{
|
||||
public Threshold Threshold { get; }
|
||||
public EquivalenceTestConclusion Conclusion { get; }
|
||||
|
||||
public EquivalenceTestResult(Threshold threshold, EquivalenceTestConclusion conclusion)
|
||||
{
|
||||
Threshold = threshold;
|
||||
Conclusion = conclusion;
|
||||
}
|
||||
|
||||
public string H0 => Threshold.IsZero()
|
||||
? "True difference in means is greater than zero"
|
||||
: $"True difference in means > {Threshold}";
|
||||
|
||||
public string H1 => Threshold.IsZero()
|
||||
? "True difference in means is zero"
|
||||
: $"True difference in means <= {Threshold}";
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace BenchmarkDotNet.Mathematics.StatisticalTesting
|
||||
{
|
||||
public interface IOneSidedTest<out T> where T : OneSidedTestResult
|
||||
{
|
||||
[CanBeNull]
|
||||
T IsGreater([NotNull] double[] x, [NotNull] double[] y, Threshold threshold = null);
|
||||
}
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче