This commit is contained in:
Andrey Akinshin 2020-03-08 15:14:05 +03:00
Родитель b3ba083e44
Коммит 54a06102a6
171 изменённых файлов: 162 добавлений и 4130 удалений

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

@ -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] &lt; 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] &lt; 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);
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше