diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..28649eb --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,3 @@ +FROM denoland/deno:bin-2.0.0 AS deno +FROM mcr.microsoft.com/devcontainers/typescript-node:20 +COPY --from=deno /deno /usr/local/bin/deno diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..410d4e1 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,43 @@ +{ + "name": "Deno", + "build": { + "dockerfile": "Dockerfile" + }, + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "yarn install", + + // Configure tool-specific properties. + "customizations": { + "vscode": { + "extensions": [ + "justjavac.vscode-deno-extensionpack" + ] + } + }, + "runArgs": [ + "--privileged", + "--cap-add=ALL", + "--security-opt", + "seccomp=unconfined", + "--env", + "COMPlus_PerfMapEnabled=1", + "--env", + "COMPlus_EnableEventLog=1", + "--env", + "COMPlus_ZapDisable=1" + ], + "features": { + "ghcr.io/devcontainers/features/dotnet:2": {}, + "ghcr.io/devcontainers-extra/features/haskell:2": {} + } + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.gitignore b/.gitignore index ec6cb9f..5af09b4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,117 @@ +## LaTeX build files +**/tex/**/*.aux +**/tex/**/*.bbl +**/tex/**/*.blg +**/tex/**/*.fdb_latexmk +**/tex/**/*.fls +**/tex/**/*.log +**/tex/**/*.out +**/tex/**/*.toc +**/tex/**/*.synctex.* + +## Haskell +dist +dist-* +cabal-dev +*.o +*.hi +*.hie +*.chi +*.chs.h +*.dyn_o +*.dyn_hi +.hpc +.hsenv +.cabal-sandbox/ +cabal.sandbox.config +*.prof +*.aux +*.hp +*.eventlog +.stack-work/ +cabal.project.local +cabal.project.local~ +.HTF/ +.ghc.environment.* + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.svclog +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml +*.azurePubxml + +# NuGet Packages Directory +packages/ +!packages/repositories.config + +**/tmp/* !.gitkeep - -tmp/ -src/tmp - -node_modules/ - -obj/ -out/ \ No newline at end of file diff --git a/C#/Console/Console.csproj b/C#/Console/Console.csproj new file mode 100644 index 0000000..585f01f --- /dev/null +++ b/C#/Console/Console.csproj @@ -0,0 +1,14 @@ + + + + + + + + Exe + net9.0 + enable + enable + + + diff --git a/C#/Console/Program.cs b/C#/Console/Program.cs new file mode 100644 index 0000000..4976139 --- /dev/null +++ b/C#/Console/Program.cs @@ -0,0 +1,3 @@ +using LevenshteinRatio; + +Console.WriteLine(Levenshtein.Ratio("exampel", "example")); diff --git a/C#/LevenshteinRatio.Bench/BenchmarkDotNet.Artifacts/results/LevenshteinBenchmark-report-github.md b/C#/LevenshteinRatio.Bench/BenchmarkDotNet.Artifacts/results/LevenshteinBenchmark-report-github.md new file mode 100644 index 0000000..56c3895 --- /dev/null +++ b/C#/LevenshteinRatio.Bench/BenchmarkDotNet.Artifacts/results/LevenshteinBenchmark-report-github.md @@ -0,0 +1,18 @@ +``` + +BenchmarkDotNet v0.14.0, Debian GNU/Linux 12 (bookworm) (container) +AMD Ryzen 5 5600X, 1 CPU, 12 logical and 6 physical cores +.NET SDK 9.0.201 + [Host] : .NET 9.0.3 (9.0.325.11113), X64 RyuJIT AVX2 + DefaultJob : .NET 9.0.3 (9.0.325.11113), X64 RyuJIT AVX2 + + +``` +| Method | Mean | Error | StdDev | +|---------------------------- |-----------------:|---------------:|---------------:| +| ShortIdenticalStrings | 1.410 ns | 0.0510 ns | 0.0793 ns | +| ShortDifferentStrings | 112.147 ns | 1.4472 ns | 1.3537 ns | +| ShortSimilarStrings | 193.013 ns | 1.8653 ns | 1.7448 ns | +| LongIdenticalStrings | 1.097 ns | 0.0221 ns | 0.0196 ns | +| LongDifferentStrings | 3,234,542.032 ns | 34,662.1297 ns | 32,422.9776 ns | +| LongPartiallySimilarStrings | 3,233,473.960 ns | 18,980.6706 ns | 16,825.8701 ns | diff --git a/C#/LevenshteinRatio.Bench/BenchmarkDotNet.Artifacts/results/LevenshteinBenchmark-report.csv b/C#/LevenshteinRatio.Bench/BenchmarkDotNet.Artifacts/results/LevenshteinBenchmark-report.csv new file mode 100644 index 0000000..7923ce7 --- /dev/null +++ b/C#/LevenshteinRatio.Bench/BenchmarkDotNet.Artifacts/results/LevenshteinBenchmark-report.csv @@ -0,0 +1,7 @@ +Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,LargeAddressAware,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Mean,Error,StdDev +ShortIdenticalStrings,DefaultJob,False,Default,Default,Default,Default,Default,Default,111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,1.410 ns,0.0510 ns,0.0793 ns +ShortDifferentStrings,DefaultJob,False,Default,Default,Default,Default,Default,Default,111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,112.147 ns,1.4472 ns,1.3537 ns +ShortSimilarStrings,DefaultJob,False,Default,Default,Default,Default,Default,Default,111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,193.013 ns,1.8653 ns,1.7448 ns +LongIdenticalStrings,DefaultJob,False,Default,Default,Default,Default,Default,Default,111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,1.097 ns,0.0221 ns,0.0196 ns +LongDifferentStrings,DefaultJob,False,Default,Default,Default,Default,Default,Default,111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"3,234,542.032 ns","34,662.1297 ns","32,422.9776 ns" +LongPartiallySimilarStrings,DefaultJob,False,Default,Default,Default,Default,Default,Default,111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"3,233,473.960 ns","18,980.6706 ns","16,825.8701 ns" diff --git a/C#/LevenshteinRatio.Bench/BenchmarkDotNet.Artifacts/results/LevenshteinBenchmark-report.html b/C#/LevenshteinRatio.Bench/BenchmarkDotNet.Artifacts/results/LevenshteinBenchmark-report.html new file mode 100644 index 0000000..930ae63 --- /dev/null +++ b/C#/LevenshteinRatio.Bench/BenchmarkDotNet.Artifacts/results/LevenshteinBenchmark-report.html @@ -0,0 +1,35 @@ + + + + +LevenshteinBenchmark-20250319-165843 + + + + +

+BenchmarkDotNet v0.14.0, Debian GNU/Linux 12 (bookworm) (container)
+AMD Ryzen 5 5600X, 1 CPU, 12 logical and 6 physical cores
+.NET SDK 9.0.201
+  [Host]     : .NET 9.0.3 (9.0.325.11113), X64 RyuJIT AVX2
+  DefaultJob : .NET 9.0.3 (9.0.325.11113), X64 RyuJIT AVX2
+
+
+ + + + + + + + + + +
Method Mean Error StdDev
ShortIdenticalStrings1.410 ns0.0510 ns0.0793 ns
ShortDifferentStrings112.147 ns1.4472 ns1.3537 ns
ShortSimilarStrings193.013 ns1.8653 ns1.7448 ns
LongIdenticalStrings1.097 ns0.0221 ns0.0196 ns
LongDifferentStrings3,234,542.032 ns34,662.1297 ns32,422.9776 ns
LongPartiallySimilarStrings3,233,473.960 ns18,980.6706 ns16,825.8701 ns
+ + diff --git a/C#/LevenshteinRatio.Bench/LevenshteinRatio.Bench.csproj b/C#/LevenshteinRatio.Bench/LevenshteinRatio.Bench.csproj new file mode 100644 index 0000000..143a1c5 --- /dev/null +++ b/C#/LevenshteinRatio.Bench/LevenshteinRatio.Bench.csproj @@ -0,0 +1,19 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + + + + + + diff --git a/C#/LevenshteinRatio.Bench/Program.cs b/C#/LevenshteinRatio.Bench/Program.cs new file mode 100644 index 0000000..a4f0423 --- /dev/null +++ b/C#/LevenshteinRatio.Bench/Program.cs @@ -0,0 +1,44 @@ +using System; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Exporters; +using BenchmarkDotNet.Running; +using LevenshteinRatio; +using BenchmarkDotNet.Exporters.Json; + +[PerfCollectProfiler] +public class LevenshteinBenchmark +{ + private static readonly string LongStringA = new string('a', 1000); + private static readonly string LongStringB = new string('b', 1000); + private static readonly string LongStringC = new string('a', 500) + new string('b', 500); + + [Benchmark] + public void ShortIdenticalStrings() => Levenshtein.Ratio("test", "test"); + + [Benchmark] + public void ShortDifferentStrings() => Levenshtein.Ratio("test", "abcd"); + + [Benchmark] + public void ShortSimilarStrings() => Levenshtein.Ratio("kitten", "sitting"); + + [Benchmark] + public void LongIdenticalStrings() => Levenshtein.Ratio(LongStringA, LongStringA); + + [Benchmark] + public void LongDifferentStrings() => Levenshtein.Ratio(LongStringA, LongStringB); + + [Benchmark] + public void LongPartiallySimilarStrings() => Levenshtein.Ratio(LongStringC, LongStringA); + + public static void Main(string[] args) { + var config = ManualConfig + .Create(DefaultConfig.Instance); + .AddExporter(MarkdownExporter.GitHub) + .AddExporter(JsonExporter.Full) + .AddExporter(JsonExporter.Brief) + .WithArtifactsPath(@"./res"); + + var summary = BenchmarkRunner.Run(config); + } +} diff --git a/C#/LevenshteinRatio.Bench/perfcollect b/C#/LevenshteinRatio.Bench/perfcollect new file mode 100644 index 0000000..f83a950 --- /dev/null +++ b/C#/LevenshteinRatio.Bench/perfcollect @@ -0,0 +1,2186 @@ +#!/bin/bash + +############################################################################################################# +# .NET Performance Data Collection Script +############################################################################################################# + +############################################################################################################# +# +# ***** HOW TO USE THIS SCRIPT ***** +# +# This script can be used to collect and view performance data collected with perf_event on Linux. + +# It's job is to make it simple to collect performance traces. +# +# How to collect a performance trace: +# 1. Prior to starting the .NET process, set the environment variable COMPlus_PerfMapEnabled=1. +# This tells the runtime to emit information that enables perf_event to resolve JIT-compiled code symbols. +# +# 2. Setup your system to reproduce the performance issue you'd like to capture. Data collection can be +# started on already running processes. +# +# 3. [Usage #1] use "collect" command +# - Run this script: sudo ./perfcollect collect samplePerfTrace. This will start data collection. +# - Let the repro run as long as you need to capture the performance problem. +# - Hit CTRL+C to stop collection. +# +# [Usage #2] use "start" and "stop" command +# - Run this script: sudo ./perfcollect start samplePerfTrace. This will start data colletion. +# - Let the repro run as long as you need to capture the performance problem. +# - Run: sudo ./perfcollect stop samplePerfTrace. This will stop collection. +# +# 4. When collection is stopped, the script will create a trace.zip file matching the name specified on the +# command line. This file will contain the trace, JIT-compiled symbol information, and all debugging +# symbols for binaries referenced by this trace that were available on the machine at collection time. +# +# How to view a performance trace: +# 1. Run this script: ./perfcollect view samplePerfTrace.trace.zip +# This will extract the trace, place and register all symbol files and JIT-compiled symbol information +# and start the perf_event viewer. By default, you will be looking at a callee view - stacks are ordered +# top down. For a caller or bottom up view, specify '-graphtype caller'. +############################################################################################################# + +###################################### +## FOR DEBUGGING ONLY +###################################### +# set -x + +###################################### +## Collection Options +## NOTE: These values represent the collection defaults. +###################################### + +# Set when we parse command line arguments to determine if we should enable specific collection options. +collect_cpu=1 +collect_threadTime=0 +collect_offcpu=0 +collect_system=0 + +###################################### +## .NET Event Categories +###################################### + +# Separate GCCollectOnly list because our LTTng implementation doesn't set tracepoint verbosity. +# Once tracepoint verbosity is set, we can set verbosity and collapse this with DotNETRuntime_GCKeyword. +declare -a DotNETRuntime_GCKeyword_GCCollectOnly=( + DotNETRuntime:GCStart + DotNETRuntime:GCStart_V1 + DotNETRuntime:GCStart_V2 + DotNETRuntime:GCEnd + DotNETRuntime:GCEnd_V1 + DotNETRuntime:GCRestartEEEnd + DotNETRuntime:GCRestartEEEnd_V1 + DotNETRuntime:GCHeapStats + DotNETRuntime:GCHeapStats_V1 + DotNETRuntime:GCCreateSegment + DotNETRuntime:GCCreateSegment_V1 + DotNETRuntime:GCFreeSegment + DotNETRuntime:GCFreeSegment_V1 + DotNETRuntime:GCRestartEEBegin + DotNETRuntime:GCRestartEEBegin_V1 + DotNETRuntime:GCSuspendEEEnd + DotNETRuntime:GCSuspendEEEnd_V1 + DotNETRuntime:GCSuspendEEBegin + DotNETRuntime:GCSuspendEEBegin_V1 + DotNETRuntime:GCCreateConcurrentThread + DotNETRuntime:GCTerminateConcurrentThread + DotNETRuntime:GCFinalizersEnd + DotNETRuntime:GCFinalizersEnd_V1 + DotNETRuntime:GCFinalizersBegin + DotNETRuntime:GCFinalizersBegin_V1 + DotNETRuntime:GCMarkStackRoots + DotNETRuntime:GCMarkFinalizeQueueRoots + DotNETRuntime:GCMarkHandles + DotNETRuntime:GCMarkOlderGenerationRoots + DotNETRuntime:FinalizeObject + DotNETRuntime:GCTriggered + DotNETRuntime:IncreaseMemoryPressure + DotNETRuntime:DecreaseMemoryPressure + DotNETRuntime:GCMarkWithType + DotNETRuntime:GCPerHeapHistory_V3 + DotNETRuntime:GCGlobalHeapHistory_V2 + DotNETRuntime:GCCreateConcurrentThread_V1 + DotNETRuntime:GCTerminateConcurrentThread_V1 +) + + +declare -a DotNETRuntime_GCKeyword=( + DotNETRuntime:GCStart + DotNETRuntime:GCStart_V1 + DotNETRuntime:GCStart_V2 + DotNETRuntime:GCEnd + DotNETRuntime:GCEnd_V1 + DotNETRuntime:GCRestartEEEnd + DotNETRuntime:GCRestartEEEnd_V1 + DotNETRuntime:GCHeapStats + DotNETRuntime:GCHeapStats_V1 + DotNETRuntime:GCCreateSegment + DotNETRuntime:GCCreateSegment_V1 + DotNETRuntime:GCFreeSegment + DotNETRuntime:GCFreeSegment_V1 + DotNETRuntime:GCRestartEEBegin + DotNETRuntime:GCRestartEEBegin_V1 + DotNETRuntime:GCSuspendEEEnd + DotNETRuntime:GCSuspendEEEnd_V1 + DotNETRuntime:GCSuspendEEBegin + DotNETRuntime:GCSuspendEEBegin_V1 + DotNETRuntime:GCAllocationTick + DotNETRuntime:GCAllocationTick_V1 + DotNETRuntime:GCAllocationTick_V2 + DotNETRuntime:GCAllocationTick_V3 + DotNETRuntime:GCCreateConcurrentThread + DotNETRuntime:GCTerminateConcurrentThread + DotNETRuntime:GCFinalizersEnd + DotNETRuntime:GCFinalizersEnd_V1 + DotNETRuntime:GCFinalizersBegin + DotNETRuntime:GCFinalizersBegin_V1 + DotNETRuntime:GCMarkStackRoots + DotNETRuntime:GCMarkFinalizeQueueRoots + DotNETRuntime:GCMarkHandles + DotNETRuntime:GCMarkOlderGenerationRoots + DotNETRuntime:FinalizeObject + DotNETRuntime:PinObjectAtGCTime + DotNETRuntime:GCTriggered + DotNETRuntime:IncreaseMemoryPressure + DotNETRuntime:DecreaseMemoryPressure + DotNETRuntime:GCMarkWithType + DotNETRuntime:GCJoin_V2 + DotNETRuntime:GCPerHeapHistory_V3 + DotNETRuntime:GCGlobalHeapHistory_V2 + DotNETRuntime:GCCreateConcurrentThread_V1 + DotNETRuntime:GCTerminateConcurrentThread_V1 +) + +declare -a DotNETRuntime_TypeKeyword=( + DotNETRuntime:BulkType +) + +declare -a DotNETRuntime_GCHeapDumpKeyword=( + DotNETRuntime:GCBulkRootEdge + DotNETRuntime:GCBulkRootConditionalWeakTableElementEdge + DotNETRuntime:GCBulkNode + DotNETRuntime:GCBulkEdge + DotNETRuntime:GCBulkRootCCW + DotNETRuntime:GCBulkRCW + DotNETRuntime:GCBulkRootStaticVar +) + +declare -a DotNETRuntime_GCSampledObjectAllocationHighKeyword=( + DotNETRuntime:GCSampledObjectAllocationHigh +) + +declare -a DotNETRuntime_GCHeapSurvivalAndMovementKeyword=( + DotNETRuntime:GCBulkSurvivingObjectRanges + DotNETRuntime:GCBulkMovedObjectRanges + DotNETRuntime:GCGenerationRange +) + +declare -a DotNETRuntime_GCHandleKeyword=( + DotNETRuntime:SetGCHandle + DotNETRuntime:DestroyGCHandle +) + +declare -a DotNETRuntime_GCSampledObjectAllocationLowKeyword=( + DotNETRuntime:GCSampledObjectAllocationLow +) + +declare -a DotNETRuntime_ThreadingKeyword=( + DotNETRuntime:WorkerThreadCreate + DotNETRuntime:WorkerThreadTerminate + DotNETRuntime:WorkerThreadRetire + DotNETRuntime:WorkerThreadUnretire + DotNETRuntime:IOThreadCreate + DotNETRuntime:IOThreadCreate_V1 + DotNETRuntime:IOThreadTerminate + DotNETRuntime:IOThreadTerminate_V1 + DotNETRuntime:IOThreadRetire + DotNETRuntime:IOThreadRetire_V1 + DotNETRuntime:IOThreadUnretire + DotNETRuntime:IOThreadUnretire_V1 + DotNETRuntime:ThreadpoolSuspensionSuspendThread + DotNETRuntime:ThreadpoolSuspensionResumeThread + DotNETRuntime:ThreadPoolWorkerThreadStart + DotNETRuntime:ThreadPoolWorkerThreadStop + DotNETRuntime:ThreadPoolWorkerThreadRetirementStart + DotNETRuntime:ThreadPoolWorkerThreadRetirementStop + DotNETRuntime:ThreadPoolWorkerThreadAdjustmentSample + DotNETRuntime:ThreadPoolWorkerThreadAdjustmentAdjustment + DotNETRuntime:ThreadPoolWorkerThreadAdjustmentStats + DotNETRuntime:ThreadPoolWorkerThreadWait + DotNETRuntime:ThreadPoolWorkingThreadCount + DotNETRuntime:ThreadPoolIOPack + DotNETRuntime:GCCreateConcurrentThread_V1 + DotNETRuntime:GCTerminateConcurrentThread_V1 +) + +declare -a DotNETRuntime_ThreadingKeyword_ThreadTransferKeyword=( + DotNETRuntime:ThreadPoolEnqueue + DotNETRuntime:ThreadPoolDequeue + DotNETRuntime:ThreadPoolIOEnqueue + DotNETRuntime:ThreadPoolIODequeue + DotNETRuntime:ThreadCreating + DotNETRuntime:ThreadRunning +) + +declare -a DotNETRuntime_NoKeyword=( + DotNETRuntime:ExceptionThrown + DotNETRuntime:Contention + DotNETRuntime:RuntimeInformationStart + DotNETRuntime:EventSource +) + +declare -a DotNETRuntime_ExceptionKeyword=( + DotNETRuntime:ExceptionThrown_V1 + DotNETRuntime:ExceptionCatchStart + DotNETRuntime:ExceptionCatchStop + DotNETRuntime:ExceptionFinallyStart + DotNETRuntime:ExceptionFinallyStop + DotNETRuntime:ExceptionFilterStart + DotNETRuntime:ExceptionFilterStop + DotNETRuntime:ExceptionThrownStop +) + +declare -a DotNETRuntime_ContentionKeyword=( + DotNETRuntime:ContentionStart_V1 + DotNETRuntime:ContentionStop + DotNETRuntime:ContentionStop_V1 +) + +declare -a DotNETRuntime_StackKeyword=( + DotNETRuntime:CLRStackWalk +) + +declare -a DotNETRuntime_AppDomainResourceManagementKeyword=( + DotNETRuntime:AppDomainMemAllocated + DotNETRuntime:AppDomainMemSurvived +) + +declare -a DotNETRuntime_AppDomainResourceManagementKeyword_ThreadingKeyword=( + DotNETRuntime:ThreadCreated + DotNETRuntime:ThreadTerminated + DotNETRuntime:ThreadDomainEnter +) + +declare -a DotNETRuntime_InteropKeyword=( + DotNETRuntime:ILStubGenerated + DotNETRuntime:ILStubCacheHit +) + +declare -a DotNETRuntime_JitKeyword_NGenKeyword=( + DotNETRuntime:DCStartCompleteV2 + DotNETRuntime:DCEndCompleteV2 + DotNETRuntime:MethodDCStartV2 + DotNETRuntime:MethodDCEndV2 + DotNETRuntime:MethodDCStartVerboseV2 + DotNETRuntime:MethodDCEndVerboseV2 + DotNETRuntime:MethodLoad + DotNETRuntime:MethodLoad_V1 + DotNETRuntime:MethodLoad_V2 + DotNETRuntime:MethodUnload + DotNETRuntime:MethodUnload_V1 + DotNETRuntime:MethodUnload_V2 + DotNETRuntime:MethodLoadVerbose + DotNETRuntime:MethodLoadVerbose_V1 + DotNETRuntime:MethodLoadVerbose_V2 + DotNETRuntime:MethodUnloadVerbose + DotNETRuntime:MethodUnloadVerbose_V1 + DotNETRuntime:MethodUnloadVerbose_V2 +) + +declare -a DotNETRuntime_JitKeyword=( + DotNETRuntime:MethodJittingStarted + DotNETRuntime:MethodJittingStarted_V1 +) + +declare -a DotNETRuntime_JitTracingKeyword=( + DotNETRuntime:MethodJitInliningSucceeded + DotNETRuntime:MethodJitInliningFailed + DotNETRuntime:MethodJitTailCallSucceeded + DotNETRuntime:MethodJitTailCallFailed +) + +declare -a DotNETRuntime_JittedMethodILToNativeMapKeyword=( + DotNETRuntime:MethodILToNativeMap +) + +declare -a DotNETRuntime_LoaderKeyword=( + DotNETRuntime:ModuleDCStartV2 + DotNETRuntime:ModuleDCEndV2 + DotNETRuntime:DomainModuleLoad + DotNETRuntime:DomainModuleLoad_V1 + DotNETRuntime:ModuleLoad + DotNETRuntime:ModuleUnload + DotNETRuntime:AssemblyLoad + DotNETRuntime:AssemblyLoad_V1 + DotNETRuntime:AssemblyUnload + DotNETRuntime:AssemblyUnload_V1 + DotNETRuntime:AppDomainLoad + DotNETRuntime:AppDomainLoad_V1 + DotNETRuntime:AppDomainUnload + DotNETRuntime:AppDomainUnload_V1 +) + +declare -a DotNETRuntime_LoaderKeyword=( + DotNETRuntime:ModuleLoad_V1 + DotNETRuntime:ModuleLoad_V2 + DotNETRuntime:ModuleUnload_V1 + DotNETRuntime:ModuleUnload_V2 +) + +declare -a DotNETRuntime_SecurityKeyword=( + DotNETRuntime:StrongNameVerificationStart + DotNETRuntime:StrongNameVerificationStart_V1 + DotNETRuntime:StrongNameVerificationStop + DotNETRuntime:StrongNameVerificationStop_V1 + DotNETRuntime:AuthenticodeVerificationStart + DotNETRuntime:AuthenticodeVerificationStart_V1 + DotNETRuntime:AuthenticodeVerificationStop + DotNETRuntime:AuthenticodeVerificationStop_V1 +) + +declare -a DotNETRuntime_DebuggerKeyword=( + DotNETRuntime:DebugIPCEventStart + DotNETRuntime:DebugIPCEventEnd + DotNETRuntime:DebugExceptionProcessingStart + DotNETRuntime:DebugExceptionProcessingEnd +) + +declare -a DotNETRuntime_CodeSymbolsKeyword=( + DotNETRuntime:CodeSymbols +) + +declare -a DotNETRuntime_CompilationKeyword=( + DotNETRuntime:TieredCompilationSettings + DotNETRuntime:TieredCompilationPause + DotNETRuntime:TieredCompilationResume + DotNETRuntime:TieredCompilationBackgroundJitStart + DotNETRuntime:TieredCompilationBackgroundJitStop + DotNETRuntimeRundown:TieredCompilationSettingsDCStart +) + +# Separate GCCollectOnly list because our LTTng implementation doesn't set tracepoint verbosity. +# Once tracepoint verbosity is set, we can set verbosity and collapse this with DotNETRuntimePrivate_GCPrivateKeyword. +declare -a DotNETRuntimePrivate_GCPrivateKeyword_GCCollectOnly=( + DotNETRuntimePrivate:GCDecision + DotNETRuntimePrivate:GCDecision_V1 + DotNETRuntimePrivate:GCSettings + DotNETRuntimePrivate:GCSettings_V1 + DotNETRuntimePrivate:GCPerHeapHistory + DotNETRuntimePrivate:GCPerHeapHistory_V1 + DotNETRuntimePrivate:GCGlobalHeapHistory + DotNETRuntimePrivate:GCGlobalHeapHistory_V1 + DotNETRuntimePrivate:PrvGCMarkStackRoots + DotNETRuntimePrivate:PrvGCMarkStackRoots_V1 + DotNETRuntimePrivate:PrvGCMarkFinalizeQueueRoots + DotNETRuntimePrivate:PrvGCMarkFinalizeQueueRoots_V1 + DotNETRuntimePrivate:PrvGCMarkHandles + DotNETRuntimePrivate:PrvGCMarkHandles_V1 + DotNETRuntimePrivate:PrvGCMarkCards + DotNETRuntimePrivate:PrvGCMarkCards_V1 + DotNETRuntimePrivate:BGCBegin + DotNETRuntimePrivate:BGC1stNonConEnd + DotNETRuntimePrivate:BGC1stConEnd + DotNETRuntimePrivate:BGC2ndNonConBegin + DotNETRuntimePrivate:BGC2ndNonConEnd + DotNETRuntimePrivate:BGC2ndConBegin + DotNETRuntimePrivate:BGC2ndConEnd + DotNETRuntimePrivate:BGCPlanEnd + DotNETRuntimePrivate:BGCSweepEnd + DotNETRuntimePrivate:BGCDrainMark + DotNETRuntimePrivate:BGCRevisit + DotNETRuntimePrivate:BGCOverflow + DotNETRuntimePrivate:BGCAllocWaitBegin + DotNETRuntimePrivate:BGCAllocWaitEnd + DotNETRuntimePrivate:GCFullNotify + DotNETRuntimePrivate:GCFullNotify_V1 + DotNETRuntimePrivate:PrvFinalizeObject + DotNETRuntimePrivate:PinPlugAtGCTime +) + +declare -a DotNETRuntimePrivate_GCPrivateKeyword=( + DotNETRuntimePrivate:GCDecision + DotNETRuntimePrivate:GCDecision_V1 + DotNETRuntimePrivate:GCSettings + DotNETRuntimePrivate:GCSettings_V1 + DotNETRuntimePrivate:GCOptimized + DotNETRuntimePrivate:GCOptimized_V1 + DotNETRuntimePrivate:GCPerHeapHistory + DotNETRuntimePrivate:GCPerHeapHistory_V1 + DotNETRuntimePrivate:GCGlobalHeapHistory + DotNETRuntimePrivate:GCGlobalHeapHistory_V1 + DotNETRuntimePrivate:GCJoin + DotNETRuntimePrivate:GCJoin_V1 + DotNETRuntimePrivate:PrvGCMarkStackRoots + DotNETRuntimePrivate:PrvGCMarkStackRoots_V1 + DotNETRuntimePrivate:PrvGCMarkFinalizeQueueRoots + DotNETRuntimePrivate:PrvGCMarkFinalizeQueueRoots_V1 + DotNETRuntimePrivate:PrvGCMarkHandles + DotNETRuntimePrivate:PrvGCMarkHandles_V1 + DotNETRuntimePrivate:PrvGCMarkCards + DotNETRuntimePrivate:PrvGCMarkCards_V1 + DotNETRuntimePrivate:BGCBegin + DotNETRuntimePrivate:BGC1stNonConEnd + DotNETRuntimePrivate:BGC1stConEnd + DotNETRuntimePrivate:BGC2ndNonConBegin + DotNETRuntimePrivate:BGC2ndNonConEnd + DotNETRuntimePrivate:BGC2ndConBegin + DotNETRuntimePrivate:BGC2ndConEnd + DotNETRuntimePrivate:BGCPlanEnd + DotNETRuntimePrivate:BGCSweepEnd + DotNETRuntimePrivate:BGCDrainMark + DotNETRuntimePrivate:BGCRevisit + DotNETRuntimePrivate:BGCOverflow + DotNETRuntimePrivate:BGCAllocWaitBegin + DotNETRuntimePrivate:BGCAllocWaitEnd + DotNETRuntimePrivate:GCFullNotify + DotNETRuntimePrivate:GCFullNotify_V1 + DotNETRuntimePrivate:PrvFinalizeObject + DotNETRuntimePrivate:PinPlugAtGCTime +) + +declare -a DotNETRuntimePrivate_StartupKeyword=( + DotNETRuntimePrivate:EEStartupStart + DotNETRuntimePrivate:EEStartupStart_V1 + DotNETRuntimePrivate:EEStartupEnd + DotNETRuntimePrivate:EEStartupEnd_V1 + DotNETRuntimePrivate:EEConfigSetup + DotNETRuntimePrivate:EEConfigSetup_V1 + DotNETRuntimePrivate:EEConfigSetupEnd + DotNETRuntimePrivate:EEConfigSetupEnd_V1 + DotNETRuntimePrivate:LdSysBases + DotNETRuntimePrivate:LdSysBases_V1 + DotNETRuntimePrivate:LdSysBasesEnd + DotNETRuntimePrivate:LdSysBasesEnd_V1 + DotNETRuntimePrivate:ExecExe + DotNETRuntimePrivate:ExecExe_V1 + DotNETRuntimePrivate:ExecExeEnd + DotNETRuntimePrivate:ExecExeEnd_V1 + DotNETRuntimePrivate:Main + DotNETRuntimePrivate:Main_V1 + DotNETRuntimePrivate:MainEnd + DotNETRuntimePrivate:MainEnd_V1 + DotNETRuntimePrivate:ApplyPolicyStart + DotNETRuntimePrivate:ApplyPolicyStart_V1 + DotNETRuntimePrivate:ApplyPolicyEnd + DotNETRuntimePrivate:ApplyPolicyEnd_V1 + DotNETRuntimePrivate:LdLibShFolder + DotNETRuntimePrivate:LdLibShFolder_V1 + DotNETRuntimePrivate:LdLibShFolderEnd + DotNETRuntimePrivate:LdLibShFolderEnd_V1 + DotNETRuntimePrivate:PrestubWorker + DotNETRuntimePrivate:PrestubWorker_V1 + DotNETRuntimePrivate:PrestubWorkerEnd + DotNETRuntimePrivate:PrestubWorkerEnd_V1 + DotNETRuntimePrivate:GetInstallationStart + DotNETRuntimePrivate:GetInstallationStart_V1 + DotNETRuntimePrivate:GetInstallationEnd + DotNETRuntimePrivate:GetInstallationEnd_V1 + DotNETRuntimePrivate:OpenHModule + DotNETRuntimePrivate:OpenHModule_V1 + DotNETRuntimePrivate:OpenHModuleEnd + DotNETRuntimePrivate:OpenHModuleEnd_V1 + DotNETRuntimePrivate:ExplicitBindStart + DotNETRuntimePrivate:ExplicitBindStart_V1 + DotNETRuntimePrivate:ExplicitBindEnd + DotNETRuntimePrivate:ExplicitBindEnd_V1 + DotNETRuntimePrivate:ParseXml + DotNETRuntimePrivate:ParseXml_V1 + DotNETRuntimePrivate:ParseXmlEnd + DotNETRuntimePrivate:ParseXmlEnd_V1 + DotNETRuntimePrivate:InitDefaultDomain + DotNETRuntimePrivate:InitDefaultDomain_V1 + DotNETRuntimePrivate:InitDefaultDomainEnd + DotNETRuntimePrivate:InitDefaultDomainEnd_V1 + DotNETRuntimePrivate:InitSecurity + DotNETRuntimePrivate:InitSecurity_V1 + DotNETRuntimePrivate:InitSecurityEnd + DotNETRuntimePrivate:InitSecurityEnd_V1 + DotNETRuntimePrivate:AllowBindingRedirs + DotNETRuntimePrivate:AllowBindingRedirs_V1 + DotNETRuntimePrivate:AllowBindingRedirsEnd + DotNETRuntimePrivate:AllowBindingRedirsEnd_V1 + DotNETRuntimePrivate:EEConfigSync + DotNETRuntimePrivate:EEConfigSync_V1 + DotNETRuntimePrivate:EEConfigSyncEnd + DotNETRuntimePrivate:EEConfigSyncEnd_V1 + DotNETRuntimePrivate:FusionBinding + DotNETRuntimePrivate:FusionBinding_V1 + DotNETRuntimePrivate:FusionBindingEnd + DotNETRuntimePrivate:FusionBindingEnd_V1 + DotNETRuntimePrivate:LoaderCatchCall + DotNETRuntimePrivate:LoaderCatchCall_V1 + DotNETRuntimePrivate:LoaderCatchCallEnd + DotNETRuntimePrivate:LoaderCatchCallEnd_V1 + DotNETRuntimePrivate:FusionInit + DotNETRuntimePrivate:FusionInit_V1 + DotNETRuntimePrivate:FusionInitEnd + DotNETRuntimePrivate:FusionInitEnd_V1 + DotNETRuntimePrivate:FusionAppCtx + DotNETRuntimePrivate:FusionAppCtx_V1 + DotNETRuntimePrivate:FusionAppCtxEnd + DotNETRuntimePrivate:FusionAppCtxEnd_V1 + DotNETRuntimePrivate:Fusion2EE + DotNETRuntimePrivate:Fusion2EE_V1 + DotNETRuntimePrivate:Fusion2EEEnd + DotNETRuntimePrivate:Fusion2EEEnd_V1 + DotNETRuntimePrivate:SecurityCatchCall + DotNETRuntimePrivate:SecurityCatchCall_V1 + DotNETRuntimePrivate:SecurityCatchCallEnd + DotNETRuntimePrivate:SecurityCatchCallEnd_V1 +) + +declare -a DotNETRuntimePrivate_StackKeyword=( + DotNETRuntimePrivate:CLRStackWalkPrivate +) + +declare -a DotNETRuntimePrivate_PerfTrackPrivateKeyword=( + DotNETRuntimePrivate:ModuleRangeLoadPrivate +) + +declare -a DotNETRuntimePrivate_BindingKeyword=( + DotNETRuntimePrivate:BindingPolicyPhaseStart + DotNETRuntimePrivate:BindingPolicyPhaseEnd + DotNETRuntimePrivate:BindingNgenPhaseStart + DotNETRuntimePrivate:BindingNgenPhaseEnd + DotNETRuntimePrivate:BindingLookupAndProbingPhaseStart + DotNETRuntimePrivate:BindingLookupAndProbingPhaseEnd + DotNETRuntimePrivate:LoaderPhaseStart + DotNETRuntimePrivate:LoaderPhaseEnd + DotNETRuntimePrivate:BindingPhaseStart + DotNETRuntimePrivate:BindingPhaseEnd + DotNETRuntimePrivate:BindingDownloadPhaseStart + DotNETRuntimePrivate:BindingDownloadPhaseEnd + DotNETRuntimePrivate:LoaderAssemblyInitPhaseStart + DotNETRuntimePrivate:LoaderAssemblyInitPhaseEnd + DotNETRuntimePrivate:LoaderMappingPhaseStart + DotNETRuntimePrivate:LoaderMappingPhaseEnd + DotNETRuntimePrivate:LoaderDeliverEventsPhaseStart + DotNETRuntimePrivate:LoaderDeliverEventsPhaseEnd + DotNETRuntimePrivate:FusionMessageEvent + DotNETRuntimePrivate:FusionErrorCodeEvent +) + +declare -a DotNETRuntimePrivate_SecurityPrivateKeyword=( + DotNETRuntimePrivate:EvidenceGenerated + DotNETRuntimePrivate:ModuleTransparencyComputationStart + DotNETRuntimePrivate:ModuleTransparencyComputationEnd + DotNETRuntimePrivate:TypeTransparencyComputationStart + DotNETRuntimePrivate:TypeTransparencyComputationEnd + DotNETRuntimePrivate:MethodTransparencyComputationStart + DotNETRuntimePrivate:MethodTransparencyComputationEnd + DotNETRuntimePrivate:FieldTransparencyComputationStart + DotNETRuntimePrivate:FieldTransparencyComputationEnd + DotNETRuntimePrivate:TokenTransparencyComputationStart + DotNETRuntimePrivate:TokenTransparencyComputationEnd +) + +declare -a DotNETRuntimePrivate_PrivateFusionKeyword=( + DotNETRuntimePrivate:NgenBindEvent +) + +declare -a DotNETRuntimePrivate_NoKeyword=( + DotNETRuntimePrivate:FailFast +) + +declare -a DotNETRuntimePrivate_InteropPrivateKeyword=( + DotNETRuntimePrivate:CCWRefCountChange +) + +declare -a DotNETRuntimePrivate_GCHandlePrivateKeyword=( + DotNETRuntimePrivate:PrvSetGCHandle + DotNETRuntimePrivate:PrvDestroyGCHandle +) + +declare -a DotNETRuntimePrivate_LoaderHeapPrivateKeyword=( + DotNETRuntimePrivate:AllocRequest +) + +declare -a DotNETRuntimePrivate_MulticoreJitPrivateKeyword=( + DotNETRuntimePrivate:MulticoreJit + DotNETRuntimePrivate:MulticoreJitMethodCodeReturned +) + +declare -a DotNETRuntimePrivate_DynamicTypeUsageKeyword=( + DotNETRuntimePrivate:IInspectableRuntimeClassName + DotNETRuntimePrivate:WinRTUnbox + DotNETRuntimePrivate:CreateRCW + DotNETRuntimePrivate:RCWVariance + DotNETRuntimePrivate:RCWIEnumerableCasting + DotNETRuntimePrivate:CreateCCW + DotNETRuntimePrivate:CCWVariance + DotNETRuntimePrivate:ObjectVariantMarshallingToNative + DotNETRuntimePrivate:GetTypeFromGUID + DotNETRuntimePrivate:GetTypeFromProgID + DotNETRuntimePrivate:ConvertToCallbackEtw + DotNETRuntimePrivate:BeginCreateManagedReference + DotNETRuntimePrivate:EndCreateManagedReference + DotNETRuntimePrivate:ObjectVariantMarshallingToManaged +) + +declare -a EventSource=( + DotNETRuntime:EventSource +) + +declare -a LTTng_Kernel_ProcessLifetimeKeyword=( + sched_process_exec + sched_process_exit +) + + +###################################### +## Global Variables +###################################### + +# Install without waiting for standard input +forceInstall=0 + +# Declare an array of events to collect. +declare -a eventsToCollect + +# Use Perf_Event +usePerf=1 + +# Use LTTng +useLTTng=1 + +# LTTng Installed +lttngInstalled=0 + +# Collect hardware events +collect_HWevents=0 + +# Set to 1 when the CTRLC_Handler gets invoked. +handlerInvoked=0 + +# Log file +declare logFile +logFilePrefix='/tmp/perfcollect' +logEnabled=0 + +# Collect info to pass between processes +collectInfoFile=$(dirname `mktemp -u`)/'perfcollect.sessioninfo' + +###################################### +## Logging Functions +###################################### +LogAppend() +{ + if (( $logEnabled == 1 )) + then + echo $* >> $logFile + fi +} + +RunSilent() +{ + if (( $logEnabled == 1 )) + then + echo "Running \"$*\"" >> $logFile + $* >> $logFile 2>&1 + echo "" >> $logFile + else + $* > /dev/null 2>&1 + fi +} + +RunSilentBackground() +{ + if (( $logEnabled == 1 )) + then + echo "Running \"$*\"" >> $logFile + $* >> $logFile 2>&1 & sleep 1 + echo "" >> $logFile + else + $* > /dev/null 2>&1 & sleep 1 + fi + + # When handler is invoked, kill the process. + pid=$! + for (( ; ; )) + do + if [ "$handlerInvoked" == "1" ] + then + kill -INT $pid + break; + else + sleep 1 + fi + done + + # Wait for the process to exit. + wait $pid +} + +InitializeLog() +{ + # Pick the log file name. + logFile="$logFilePrefix.log" + while [ -f $logFile ]; + do + logFile="$logFilePrefix.$RANDOM.log" + done + + # Mark the log as enabled. + logEnabled=1 + + # Start the log + date=`date` + echo "Log started at ${date}" > $logFile + echo '' >> $logFile + + # The system information. + LogAppend 'Machine info: ' `uname -a` + if [ "$perfcmd" != "" ] + then + LogAppend 'perf version:' `$perfcmd --version 2>&1` + fi + if [ "$lttngcmd" != "" ] + then + LogAppend 'LTTng version: ' `$lttngcmd --version` + fi + LogAppend +} + +CloseLog() +{ + LogAppend "END LOG FILE" + LogAppend "NOTE: It is normal for the log file to end right before the trace is actually compressed. This occurs because the log file is part of the archive, and thus can't be written anymore." + + # The log itself doesn't need to be closed, + # but we need to tell the script not to log anymore. + logEnabled=0 +} + + +###################################### +## Helper Functions +###################################### + +## +# Console text color modification helpers. +## +RedText() +{ + tput=`GetCommandFullPath "tput"` + if [ "$tput" != "" ] + then + $tput setaf 1 + fi +} + +GreenText() +{ + tput=`GetCommandFullPath "tput"` + if [ "$tput" != "" ] + then + $tput setaf 2 + fi +} + +BlueText() +{ + tput=`GetCommandFullPath "tput"` + if [ "$tput" != "" ] + then + $tput setaf 6 + fi +} +YellowText() +{ + tput=`GetCommandFullPath "tput"` + if [ "$tput" != "" ] + then + $tput setaf 3 + fi +} + +ResetText() +{ + tput=`GetCommandFullPath "tput"` + if [ "$tput" != "" ] + then + $tput sgr0 + fi +} + +# $1 == Status message +WriteStatus() +{ + LogAppend $* + BlueText + echo $1 + ResetText +} + +# $1 == Message. +WriteWarning() +{ + LogAppend $* + YellowText + echo $1 + ResetText +} + +# $1 == Message. +FatalError() +{ + RedText + echo "ERROR: $1" + ResetText + PrintUsage + exit 1 +} + +EnsureRoot() +{ + # Warn non-root users. + if [ `whoami` != "root" ] + then + RedText + echo "This script must be run as root." + ResetText + exit 1; + fi +} + +###################################### +# Command Discovery +###################################### +DiscoverCommands() +{ + perfcmd=`GetCommandFullPath "perf"` + if [ "$(IsDebian)" == "1" ] + then + # Test perf to see if it successfully runs or fails because it doesn't match the kernel version. + $perfcmd --version > /dev/null 2>&1 + if [ "$?" == "1" ] + then + perfoutput=$($perfcmd 2>&1) + if [ $? -eq 1 ] + then + perfMarker="perf_" + if [[ "$perfoutput" == *"$perfMarker"* ]] + then + foundWorkingPerf=0 + WriteWarning "Perf is installed, but does not exactly match the version of the running kernel." + WriteWarning "This is often OK, and we'll try to workaround this." + WriteStatus "Attempting to find a working copy of perf." + # Attempt to find an existing version of perf to use. + # Order the search by newest directory first. + baseDir="/usr/bin" + searchPath="$baseDir/perf_*" + for fileName in $(ls -d --sort=time $searchPath) + do + $($fileName > /dev/null 2>&1) + if [ $? -eq 1 ] + then + # If $? == 1, then use this copy of perf. + perfcmd=$fileName + foundWorkingPerf=1 + break; + fi + done + if [ $foundWorkingPerf -eq 0 ] + then + FatalError "Unable to find a working copy of perf. Try re-installing via ./perfcollect install." + fi + WriteStatus "...FINISHED" + fi + fi + fi + fi + + # Check to see if perf is installed, but doesn't exactly match the current kernel version. + # This happens when the kernel gets upgraded, or when running inside of a container where the + # host and container OS versions don't match. + perfoutput=$($perfcmd 2>&1) + if [ $? -eq 2 ] + then + # Check the beginning of the output to see if it matches the kernel warning. + warningText="WARNING: perf not found for kernel" + if [[ "$perfoutput" == "$warningText"* ]] + then + foundWorkingPerf=0 + WriteWarning "Perf is installed, but does not exactly match the version of the running kernel." + WriteWarning "This is often OK, and we'll try to workaround this." + WriteStatus "Attempting to find a working copy of perf." + # Attempt to find an existing version of perf to use. + # Order the search by newest directory first. + baseDir="/usr/lib/linux-tools" + searchPath="$baseDir/*/" + for dirName in $(ls -d --sort=time $searchPath) + do + candidatePerfPath="$dirName""perf" + $($candidatePerfPath > /dev/null 2>&1) + if [ $? -eq 1 ] + then + # If $? == 1, then use this copy of perf. + perfcmd=$candidatePerfPath + foundWorkingPerf=1 + break; + fi + done + if [ $foundWorkingPerf -eq 0 ] + then + FatalError "Unable to find a working copy of perf. Try re-installing via ./perfcollect install." + fi + WriteStatus "...FINISHED" + fi + fi + + lttngcmd=`GetCommandFullPath "lttng"` + zipcmd=`GetCommandFullPath "zip"` + unzipcmd=`GetCommandFullPath "unzip"` +} + +GetCommandFullPath() +{ + echo `command -v $1` +} + +###################################### +# Prerequisite Installation +###################################### + +IsMariner() +{ + local mariner=0 + if [ -f /etc/lsb-release ] + then + local flavor=`cat /etc/lsb-release | grep DISTRIB_ID` + if [ "$flavor" == "DISTRIB_ID=\"Mariner\"" ] || [ "$flavor" == "DISTRIB_ID=\"azurelinux\"" ] + then + mariner=1 + fi + fi + + echo $mariner +} + +InstallPerf_Mariner() +{ + # Disallow non-root users. + EnsureRoot + + # Install perf + tdnf install -y kernel-tools + + # Install zip and unzip + tdnf install -y zip unzip +} + +IsAlpine() +{ + local alpine=0 + local apk=`GetCommandFullPath "apk"` + if [ "$apk" != "" ] + then + alpine=1 + fi + + echo $alpine +} + +InstallPerf_Alpine() +{ + # Disallow non-root users. + EnsureRoot + + # Install perf + apk add perf --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community + + # Install zip and unzip + apk add zip unzip +} + +IsRHEL() +{ + local rhel=0 + if [ -f /etc/redhat-release ] + then + rhel=1 + fi + + echo $rhel +} + +InstallPerf_RHEL() +{ + # Disallow non-root users. + EnsureRoot + + # Install perf + yum install perf zip unzip +} + +IsDebian() +{ + local debian=0 + local uname=`uname -a` + if [[ $uname =~ .*Debian.* ]] + then + debian=1 + elif [ -f /etc/debian_version ] + then + debian=1 + fi + + echo $debian +} + +InstallPerf_Debian() +{ + # Disallow non-root users. + EnsureRoot + + # Check for the existence of the linux-tools package. + pkgName='linux-tools' + pkgCount=`apt-cache search $pkgName | grep -c $pkgName` + if [ "$pkgCount" == "0" ] + then + pkgName='linux-perf' + pkgCount=`apt-cache search $pkgName | grep -c $pkgName` + if [ "$pkgCount" == "0" ] + then + FatalError "Unable to find a perf package to install." + fi + fi + + # Install zip and perf. + apt-get install -y zip binutils $pkgName +} + +IsSUSE() +{ + local suse=0 + if [ -f /usr/bin/zypper ] + then + suse=1 + fi + + echo $suse +} + +InstallPerf_SUSE() +{ + # Disallow non-root users. + EnsureRoot + + # Install perf. + zypper install perf zip unzip +} + +IsUbuntu() +{ + local ubuntu=0 + if [ -f /etc/lsb-release ] + then + local flavor=`cat /etc/lsb-release | grep DISTRIB_ID` + if [ "$flavor" == "DISTRIB_ID=Ubuntu" ] + then + ubuntu=1 + fi + fi + + echo $ubuntu +} + +InstallPerf_Ubuntu() +{ + # Disallow non-root users. + EnsureRoot + + # Install packages. + BlueText + echo "Installing perf_event packages." + ResetText + + # Handle Azure instances. + release=`uname -r` + if [[ "$release" == *"-azure" ]] + then + apt-get install -y linux-tools-azure zip software-properties-common + else + apt-get install -y linux-tools-common linux-tools-`uname -r` zip software-properties-common + fi +} + +InstallPerf() +{ + if [ "$(IsUbuntu)" == "1" ] + then + InstallPerf_Ubuntu + elif [ "$(IsSUSE)" == "1" ] + then + InstallPerf_SUSE + elif [ "$(IsDebian)" == "1" ] + then + InstallPerf_Debian + elif [ "$(IsRHEL)" == "1" ] + then + InstallPerf_RHEL + elif [ "$(IsAlpine)" == "1" ] + then + InstallPerf_Alpine + elif [ "$(IsMariner)" == "1" ] + then + InstallPerf_Mariner + else + FatalError "Auto install unsupported for this distribution. Install perf manually to continue." + fi +} + +InstallLTTng_RHEL() +{ + # Disallow non-root users. + EnsureRoot + + local isRHEL7=0 + local isRHEL8=0 + if [ -e /etc/redhat-release ]; then + local redhatRelease=$( /dev/null + then + lttngInstalled=1 + + BlueText + echo "LTTng already installed." + ResetText + return + fi + + if [ "$(IsUbuntu)" == "1" ] + then + InstallLTTng_Ubuntu + elif [ "$(IsSUSE)" == "1" ] + then + InstallLTTng_SUSE + elif [ "$(IsDebian)" == "1" ] + then + InstallLTTng_Debian + elif [ "$(IsRHEL)" == "1" ] + then + InstallLTTng_RHEL + elif [ "$(IsMariner)" == "1" ] + then + echo "Collection of events from lttng-ust is not supported on Mariner for .NET workloads, so no lttng-ust events will be collected." + elif [ "$(IsAlpine)" == "1" ] + then + echo "lttng-tools is not available on Alpine Linux, so no lttng-ust events will be collected." + else + FatalError "Auto install unsupported for this distribution. Install lttng and lttng-ust packages manually." + fi +} + +SupportsAutoInstall() +{ + local supportsAutoInstall=0 + if [ "$(IsUbuntu)" == "1" ] || [ "$(IsSUSE)" == "1" ] || [ "$(IsMariner)" == "1" ] + then + supportsAutoInstall=1 + fi + + echo $supportsAutoInstall +} + +EnsurePrereqsInstalled() +{ + # If perf is not installed, then bail, as it is currently required. + if [ "$perfcmd" == "" ] + then + RedText + echo "Perf not installed." + if [ "$(SupportsAutoInstall)" == "1" ] + then + echo "Run ./perfcollect install" + echo "or install perf manually." + else + echo "Install perf to proceed." + fi + ResetText + exit 1 + fi + + # Disable LTTng use if running on Alpine or Mariner. + if [ "$(IsAlpine)" == "1" ] || [ "$(IsMariner)" == "1" ] + then + useLTTng=0 + fi + + # If LTTng is installed, consider using it. + if [ "$lttngcmd" == "" ] && [ "$useLTTng" == "1" ] + then + RedText + echo "LTTng not installed." + if [ "$(SupportsAutoInstall)" == "1" ] + then + echo "Run ./perfcollect install" + echo "or install LTTng manually." + else + echo "Install LTTng to proceed." + fi + ResetText + exit 1 + + fi + + # If zip or unzip are not installing, then bail. + if [ "$zipcmd" == "" ] || [ "$unzipcmd" == "" ] + then + RedText + echo "Zip and unzip are not installed." + if [ "$(SupportsAutoInstall)" == "1" ] + then + echo "Run ./perfcollect install" + echo "or install zip and unzip manually." + else + echo "Install zip and unzip to proceed." + fi + ResetText + exit 1 + fi +} + +###################################### +# Argument Processing +###################################### +action='' +inputTraceName='' +collectionPid='' +processFilter='' +graphType='' +perfOpt='' +viewer='perf' +gcCollectOnly='' +gcOnly='' +gcWithHeap='' +events='' +rawevents='' +bufferSize='' + +ProcessArguments() +{ + # Set the action + action=$1 + + # Actions with no arguments. + if [ "$action" == "livetrace" ] || [ "$action" == "setenv" ] + then + return + fi + + # Not enough arguments. + if [ "$#" -le "1" ] + then + FatalError "Not enough arguments have been specified." + fi + + # Validate action name. + if [ "$action" != "collect" ] && [ "$action" != "view" ] \ + && [ "$action" != "start" ] && [ "$action" != "stop" ] + then + FatalError "Invalid action specified." + fi + + # Set the data file. + inputTraceName=$2 + if [ "$inputTraceName" == "" ] + then + FatalError "Invalid trace name specified." + fi + + # Process remaining arguments. + # First copy the args into an array so that we can walk the array. + args=( "$@" ) + for (( i=2; i<${#args[@]}; i++ )) + do + # Get the arg. + local arg=${args[$i]} + + # Convert the arg to lower case. + arg=`echo $arg | tr '[:upper:]' '[:lower:]'` + + # Get the arg value. + if [ ${i+1} -lt $# ] + then + local value=${args[$i+1]} + + # Keep the cases of '-events' value to match keyword variables + # Keep the cases of '-rawevents' + if [ "-events" != "$arg" ] && [ "-rawevents" != "$arg" ] + then + # Convert the value to lower case. + value=`echo $value | tr '[:upper:]' '[:lower:]'` + fi + + # Use upper case for '-buffersize' as perf requires upper case. + if [ "-buffersize" == "$arg" ] + then + # Convert the value to upper case. + value=`echo $value | tr '[:lower:]' '[:upper:]'` + fi + fi + + # Match the arg to a known value. + if [ "-pid" == "$arg" ] + then + collectionPid=$value + i=$i+1 + elif [ "-processfilter" == "$arg" ] + then + processFilter=$value + i=$i+1 + elif [ "-graphtype" == "$arg" ] + then + graphType=$value + i=$i+1 + elif [ "-threadtime" == "$arg" ] + then + collect_threadTime=1 + elif [ "-offcpu" == "$arg" ] + then + # Perf doesn't support capturing cpu-clock events and sched events concurrently. + collect_cpu=0 + collect_offcpu=1 + elif [ "-system" == "$arg" ] + then + collect_system=1 + elif [ "-hwevents" == "$arg" ] + then + collect_HWevents=1 + elif [ "-perfopt" == "$arg" ] + then + perfOpt=$value + i=$i+1 + elif [ "-viewer" == "$arg" ] + then + viewer=$value + i=$i+1 + + # Validate the viewer. + if [ "$viewer" != "perf" ] && [ "$viewer" != "lttng" ] + then + FatalError "Invalid viewer specified. Valid values are 'perf' and 'lttng'." + fi + elif [ "-nolttng" == "$arg" ] + then + useLTTng=0 + elif [ "-noperf" == "$arg" ] + then + usePerf=0 + elif [ "-gccollectonly" == "$arg" ] + then + gcCollectOnly=1 + elif [ "-gconly" == "$arg" ] + then + gcOnly=1 + elif [ "-gcwithheap" == "$arg" ] + then + gcWithHeap=1 + elif [ "-events" == "$arg" ] + then + events=$value + i=$i+1 + elif [ "-rawevents" == "$arg" ] + then + rawevents=$value + i=$i+1 + elif [ "-collectsec" == "$arg" ] + then + duration=$value + i=$i+1 + elif [ "-buffersize" == "$arg" ] + then + bufferSize="--mmap-pages="$value + i=$i+1 + else + echo "Unknown arg ${arg}, ignored..." + fi + done + +} + + + +## +# LTTng collection +## +lttngSessionName='' +lttngTraceDir='' +CreateLTTngSession() +{ + if [ "$action" == "livetrace" ] + then + output=`$lttngcmd create --live` + else + output=`$lttngcmd create` + fi + + lttngSessionName=`echo $output | grep -o "Session.*created." | sed 's/\(Session \| created.\)//g'` + lttngTraceDir=`echo $output | grep -o "Traces.*" | sed 's/\(Traces will be written in \|\)//g' | sed 's/\(Traces will be output to \|\)//g'` +} + +SetupLTTngSession() +{ + + # Setup per-event context information. + RunSilent "$lttngcmd add-context --userspace --type vpid" + RunSilent "$lttngcmd add-context --userspace --type vtid" + RunSilent "$lttngcmd add-context --userspace --type procname" + RunSilent "$lttngcmd add-context --kernel -t pid -t procname" + + if [ "$action" == "livetrace" ] + then + RunSilent "$lttngcmd enable-event --userspace --tracepoint DotNETRuntime:EventSource" + elif [ "$gcCollectOnly" == "1" ] + then + usePerf=0 + EnableLTTngEvents ${DotNETRuntime_GCKeyword_GCCollectOnly[@]} + EnableLTTngEvents ${DotNETRuntimePrivate_GCPrivateKeyword_GCCollectOnly[@]} + EnableLTTngEvents ${DotNETRuntime_ExceptionKeyword[@]} + elif [ "$gcOnly" == "1" ] + then + usePerf=0 + EnableLTTngEvents ${DotNETRuntime_GCKeyword[@]} + EnableLTTngEvents ${DotNETRuntimePrivate_GCPrivateKeyword[@]} + EnableLTTngEvents ${DotNETRuntime_JitKeyword[@]} + EnableLTTngEvents ${DotNETRuntime_LoaderKeyword[@]} + EnableLTTngEvents ${DotNETRuntime_ExceptionKeyword[@]} + elif [ "$gcWithHeap" == "1" ] + then + usePerf=0 + EnableLTTngEvents ${DotNETRuntime_GCKeyword[@]} + EnableLTTngEvents ${DotNETRuntime_GCHeapSurvivalAndMovementKeyword[@]} + else + if [ "$events" == "" ] + then + # Enable the default set of events. + EnableLTTngEvents ${DotNETRuntime_ThreadingKeyword[@]} + EnableLTTngEvents ${DotNETRuntime_ThreadingKeyword_ThreadTransferKeyword[@]} + EnableLTTngEvents ${DotNETRuntime_NoKeyword[@]} + EnableLTTngEvents ${DotNETRuntime_ExceptionKeyword[@]} + EnableLTTngEvents ${DotNETRuntime_ContentionKeyword[@]} + EnableLTTngEvents ${DotNETRuntime_JitKeyword_NGenKeyword[@]} + EnableLTTngEvents ${DotNETRuntime_JitKeyword[@]} + EnableLTTngEvents ${DotNETRuntime_LoaderKeyword[@]} + EnableLTTngEvents ${DotNETRuntime_GCKeyword_GCCollectOnly[@]} + EnableLTTngEvents ${DotNETRuntimePrivate_GCPrivateKeyword_GCCollectOnly[@]} + EnableLTTngEvents ${DotNETRuntimePrivate_BindingKeyword[@]} + EnableLTTngEvents ${DotNETRuntimePrivate_MulticoreJitPrivateKeyword[@]} + EnableLTTngEvents ${DotNETRuntime_CompilationKeyword[@]} + elif [ "$events" == "threading" ] + then + EnableLTTngEvents ${DotNETRuntime_ThreadingKeyword[@]} + else + # Enable other keywords + events=(${events//","/" "}) + for event in ${events[@]} + do + if [ "${!event}" == "" ] || [ "$( echo `declare -p $event | grep -- -a` )" == "" ] + then + echo Invalid keyword $event, skipped... + continue + fi + local -a 'keywords=("${'"$event"'[@]}")' + if [ "${event#"LTTng_Kernel_"}" != "$event" ] + then + EnableLTTngKernelEvents ${keywords[@]} + else + EnableLTTngEvents ${keywords[@]} + fi + done + fi + if [ "$rawevents" != "" ] + then + rawevents=(${rawevents//","/" "}) + for rawevent in ${rawevents[@]} + do + EnableLTTngEvents $rawevent + done + fi + fi +} + +DestroyLTTngSession() +{ + RunSilent "$lttngcmd destroy $lttngSessionName" +} + +StartLTTngCollection() +{ + CreateLTTngSession + SetupLTTngSession + + RunSilent "$lttngcmd start $lttngSessionName" +} + +StopLTTngCollection() +{ + RunSilent "$lttngcmd stop $lttngSessionName" + DestroyLTTngSession +} + +# $@ == event names to be enabled +EnableLTTngEvents() +{ + args=( "$@" ) + for (( i=0; i<${#args[@]}; i++ )) + do + RunSilent "$lttngcmd enable-event -s $lttngSessionName -u --tracepoint ${args[$i]}" + done +} + +EnableLTTngKernelEvents() +{ + args=( "$@" ) + for (( i=0; i<${#args[@]}; i++ )) + do + RunSilent "$lttngcmd enable-event -s $lttngSessionName -k ${args[$i]}" + done +} + +## +# Helper that processes collected data. +# This helper is called when the CTRL+C signal is handled. +## +ProcessCollectedData() +{ + # Make a new target directory. + local traceSuffix=".trace" + local traceName=$inputTraceName + local directoryName=$traceName$traceSuffix + mkdir $directoryName + + # Save LTTng trace files. + if [ "$useLTTng" == "1" ] + then + LogAppend "Saving LTTng trace files." + + if [ -d $lttngTraceDir ] + then + RunSilent "mkdir lttngTrace" + RunSilent "cp -r $lttngTraceDir lttngTrace" + fi + fi + + if [ "$usePerf" == 1 ] + then + # Get any perf-$pid.map files that were used by the + # trace and store them alongside the trace. + LogAppend "Saving perf.map files." + RunSilent "$perfcmd buildid-list --with-hits" + local mapFiles=`$perfcmd buildid-list --with-hits | grep /tmp/perf- | cut -d ' ' -f 2` + for mapFile in $mapFiles + do + if [ -f $mapFile ] + then + LogAppend "Saving $mapFile" + + # Change permissions on the file before saving, as perf will need to access the file later + # in this script when running perf script. + RunSilent "chown root $mapFile" + RunSilent "cp $mapFile ." + else + LogAppend "Skipping $mapFile. Some managed symbols may not be resolvable, but trace is still valid." + fi + + # Also check for jit-.dump files. + # Convert to jit dump file name. + local pid=`echo $mapFile | awk -F"-" '{print $NF}' | awk -F"." '{print $1}'` + local path=`echo $mapFile | awk -F"/" '{OFS="/";NF--;print $0;}'` + local jitDumpFile="$path/jit-$pid.dump" + + if [ -f $jitDumpFile ] + then + LogAppend "Saving $jitDumpFile" + RunSilent "cp $jitDumpFile ." + fi + done + + WriteStatus "Resolving JIT and R2R symbols" + + originalFile="perf.data" + inputFile="perf-jit.data" + RunSilent $perfcmd inject --input $originalFile --jit --output $inputFile + + WriteStatus "...FINISHED" + + WriteStatus "Exporting perf.data file" + + outputDumpFile="perf.data.txt" + + LogAppend "Running $perfcmd script -i $inputFile --fields comm,pid,tid,cpu,time,period,event,ip,sym,dso,trace > $outputDumpFile" + $perfcmd script -i $inputFile --fields comm,pid,tid,cpu,time,period,event,ip,sym,dso,trace > $outputDumpFile 2>>$logFile + LogAppend + + # Try capturing without the cpu field which is unavailable in some containerized environments. + if [ $? -ne 0 ] + then + LogAppend "Running $perfcmd script -i $inputFile --fields comm,pid,tid,time,period,event,ip,sym,dso,trace > $outputDumpFile" + $perfcmd script -i $inputFile --fields comm,pid,tid,time,period,event,ip,sym,dso,trace > $outputDumpFile 2>>$logFile + LogAppend + fi + + # If the dump file is zero length, try to collect without the period field, which was added recently. + if [ ! -s $outputDumpFile ] + then + LogAppend "Running $perfcmd script -i $inputFile --fields comm,pid,tid,time,event,ip,sym,dso,trace > $outputDumpFile" + $perfcmd script -i $inputFile --fields comm,pid,tid,time,event,ip,sym,dso,trace > $outputDumpFile 2>>$logFile + LogAppend + fi + + WriteStatus "...FINISHED" + fi + + WriteStatus "Compressing trace files" + + # Move all collected files to the new directory. + RunSilent "mv -f * $directoryName" + + # Close the log - this stops all writing to the log, so that we can move it into the archive. + CloseLog + + # Move the log file to the new directory and rename it to the standard log name. + RunSilent "mv $logFile $directoryName/perfcollect.log" + + # Compress the data. + local archiveSuffix=".zip" + local archiveName=$directoryName$archiveSuffix + RunSilent "$zipcmd -r $archiveName $directoryName" + + # Move back to the original directory. + popd > /dev/null + + # Move the archive. + RunSilent "mv $tempDir/$archiveName ." + + WriteStatus "...FINISHED" + + WriteStatus "Cleaning up artifacts" + + # Delete the temp directory. + RunSilent "rm -rf $tempDir $collectInfoFile" + + WriteStatus "...FINISHED" + + # Tell the user where the trace is. + WriteStatus + WriteStatus "Trace saved to $archiveName" +} + +## +# Handle the CTRL+C signal. +## +CTRLC_Handler() +{ + # Mark the handler invoked. + handlerInvoked=1 +} + +EndCollect() +{ + # The user must either use "collect stop" or CTRL+C to stop collection. + if [ "$action" == "stop" ] + then + # Recover trace info in the previous program. + source $collectInfoFile # TODO: exit and dispose upon missing file + # New program started, so go back to the temp directory. + pushd $tempDir > /dev/null + fi + + if [ "$useLTTng" == "1" ] + then + StopLTTngCollection + fi + + # Update the user. + WriteStatus + WriteStatus "...STOPPED." + WriteStatus + WriteStatus "Starting post-processing. This may take some time." + WriteStatus + + # The user used CTRL+C to stop collection. + # When this happens, we catch the signal and finish our work. + ProcessCollectedData +} + +## +# Print usage information. +## +PrintUsage() +{ + echo "This script uses perf_event and LTTng to collect and view performance traces for .NET applications." + echo "For detailed collection and viewing steps, view this script in a text editor or viewer." + echo "" + echo "./perfcollect " + echo "Valid Actions: collect start/stop view livetrace install" + echo "" + echo "collect options:" + echo "By default, collection includes CPU samples collected every ms." + echo " -pid : Only collect data from the specified process id." + echo " -threadtime : Collect events for thread time analysis (on and off cpu)." + echo " -offcpu : Collect events for off-cpu analysis." + echo " -hwevents : Collect (some) hardware counters." + echo " -buffersize : Set the size of the buffer used by perf_events. Default size is specified in pages." + echo " Specify B/K/M/G suffix for bytes/kilobytes/megabytes/gigabytes." + echo " Example: -buffersize 100M for 100 megabytes" + echo "" + echo "start:" + echo " Start collection, but with Lttng trace ONLY. It needs to be used with 'stop' action." + echo "" + echo "stop:" + echo " Stop collection if 'start' action is used." + echo "" + echo "view options:" + echo " -processfilter : Filter data by the specified process name." + echo " -graphtype : Specify the type of graph. Valid values are 'caller' and 'callee'. Default is 'callee'." + echo " -viewer : Specify the data viewer. Valid values are 'perf' and 'lttng'. Default is 'perf'." + echo "" + echo "livetrace:" + echo " Print EventSource events directly to the console. Root privileges not required." + echo "" + echo "install options:" + echo " Useful for first-time setup. Installs/upgrades perf_event and LTTng." + echo " -force : Force installation of required packages without prompt" + echo "" +} + +## +# Validate and set arguments. +## + +BuildPerfRecordArgs() +{ + # Start with default collection arguments that record at realtime priority, all CPUs (-a), and collect call stacks (-g) + collectionArgs="record $bufferSize -k 1 -g" + + # Filter to a single process if desired + if [ "$collectionPid" != "" ] + then + if ps -p "$collectionPid" > /dev/null; + then + collectionArgs="$collectionArgs --pid=$collectionPid" + else + WriteWarning "Process with PID '$collectionPid' does not exist. Please specify a valid PID." + exit 1 + fi + else + collectionArgs="$collectionArgs -a" + fi + + # Enable CPU Collection + if [ $collect_cpu -eq 1 ] + then + collectionArgs="$collectionArgs" + eventsToCollect=( "${eventsToCollect[@]}" "cpu-clock" ) + + # If only collecting CPU events, set the sampling rate to 1000. + # Otherwise, use the default sampling rate to avoid sampling sched events. + if [ $collect_threadTime -eq 0 ] && [ $collect_offcpu -eq 0 ] + then + collectionArgs="$collectionArgs -F 1000" + fi + fi + + if [ $collect_system -eq 1 ] + then + collectionArgs="$collectionArgs -e major-faults -e minor-faults" + fi + + # Enable HW counters event collection + if [ $collect_HWevents -eq 1 ] + then + collectionArgs="$collectionArgs -e cycles,instructions,branches,cache-misses" + fi + + # Enable context switches. + if [ $collect_threadTime -eq 1 ] + then + eventsToCollect=( "${eventsToCollect[@]}" "sched:sched_stat_sleep" "sched:sched_switch" "sched:sched_process_exit" ) + fi + + # Enable offcpu collection + if [ $collect_offcpu -eq 1 ] + then + eventsToCollect=( "${eventsToCollect[@]}" "sched:sched_stat_sleep" "sched:sched_switch" "sched:sched_process_exit" ) + fi + + # Build up the set of events. + local eventString="" + local comma="," + for (( i=0; i<${#eventsToCollect[@]}; i++ )) + do + # Get the arg. + eventName=${eventsToCollect[$i]} + + # Build up the comma separated list. + if [ "$eventString" == "" ] + then + eventString=$eventName + else + eventString="$eventString$comma$eventName" + fi + + done + + if [ ! -z ${duration} ] + then + durationString="sleep ${duration}" + fi + + # Add the events onto the collection command line args. + collectionArgs="$collectionArgs -e $eventString $durationString" +} + +DoCollect() +{ + # Ensure the script is run as root. + EnsureRoot + + # Build collection args. + # Places the resulting args in $collectionArgs + BuildPerfRecordArgs + + # Trap CTRL+C + trap CTRLC_Handler SIGINT + + # Create a temp directory to use for collection. + local tempDir=`mktemp -d` + LogAppend "Created temp directory $tempDir" + + # Switch to the directory. + pushd $tempDir > /dev/null + + # Start LTTng collection. + if [ "$useLTTng" == "1" ] + then + StartLTTngCollection + fi + + # Tell the user that collection has started and how to exit. + if [ "$duration" != "" ] + then + WriteStatus "Collection started. Collection will automatically stop in $duration second(s). Press CTRL+C to stop early." + elif [ "$action" == "start" ] + then + WriteStatus "Collection started." + else + WriteStatus "Collection started. Press CTRL+C to stop." + fi + + # Start perf record. + if [ "$action" == "start" ] + then + # Skip perf, which can only be stopped by CTRL+C. + # Pass trace directory and session name to the stop process. + popd > /dev/null + usePerf=0 + declare -p | grep -e lttngTraceDir -e lttngSessionName -e tempDir -e usePerf -e useLttng -e logFile > $collectInfoFile + else + if [ "$usePerf" == "1" ] + then + if [ ! -z ${duration} ] + then + RunSilent $perfcmd $collectionArgs + else + RunSilentBackground $perfcmd $collectionArgs + fi + else + # Wait here until CTRL+C handler gets called when user types CTRL+C. + LogAppend "Waiting for CTRL+C handler to get called." + + waitTime=0 + for (( ; ; )) + do + if [ "$handlerInvoked" == "1" ] + then + break; + fi + + # Wait and then check to see if the handler has been invoked or we've crossed the duration threshold. + sleep 1 + waitTime=$waitTime+1 + if (( duration > 0 && duration <= waitTime )) + then + break; + fi + done + fi + # End collection if action is 'collect'. + EndCollect + fi +} + +DoLiveTrace() +{ + # Start the session + StartLTTngCollection + + # View the event stream (until the user hits CTRL+C) + WriteStatus "Listening for events from LTTng. Hit CTRL+C to stop." + $lttngcmd view + + # Stop the LTTng sessoin + StopLTTngCollection +} + +# $1 == Path to directory containing trace files +PropSymbolsAndMapFilesForView() +{ + # Get the current directory + local currentDir=`pwd` + + # Copy map files to /tmp since they aren't supported by perf buildid-cache. + local mapFiles=`find -name *.map` + for mapFile in $mapFiles + do + echo "Copying $mapFile to /tmp." + cp $mapFile /tmp + done + + # Cache all debuginfo files saved with the trace in the buildid cache. + local debugInfoFiles=`find $currentDir -name *.debuginfo` + for debugInfoFile in $debugInfoFiles + do + echo "Caching $debugInfoFile in buildid cache using perf buildid-cache." + $perfcmd buildid-cache --add=$debugInfoFile + done +} + +SetEnvironment() +{ + WriteStatus "Starting a new shell configured for profiling." + WriteStatus "When done, type 'exit' to exit the profiling shell." + bash -c 'export COMPlus_PerfMapEnabled=1;export COMPlus_EnableEventLog=1; exec bash' + WriteStatus "Profiling shell exited." +} + +DoView() +{ + # Generate a temp directory to extract the trace files into. + local tempDir=`mktemp -d` + + # Extract the trace files. + $unzipcmd $inputTraceName -d $tempDir + + # Move the to temp directory. + pushd $tempDir + cd `ls` + + # Select the viewer. + if [ "$viewer" == "perf" ] + then + # Prop symbols and map files. + PropSymbolsAndMapFilesForView `pwd` + + # Choose the view + if [ "$graphType" == "" ] + then + graphType="callee" + elif [ "$graphType" != "callee" ] && [ "$graphType" != "caller"] + then + FatalError "Invalid graph type specified. Valid values are 'callee' and 'caller'." + fi + + # Filter to specific process names if desired. + if [ "$processFilter" != "" ] + then + processFilter="--comms=$processFilter" + fi + + # Execute the viewer. + $perfcmd report -n -g graph,0.5,$graphType $processFilter $perfOpt + elif [ "$viewer" == "lttng" ] + then + babeltrace lttngTrace/ | more + fi + + # Switch back to the original directory. + popd + + # Delete the temp directory. + rm -rf $tempDir +} + +##################################### +## Main Script Start +##################################### + +# No arguments +if [ "$#" == "0" ] +then + PrintUsage + exit 0 +fi + +# Install perf if requested. Do this before all other validation. +if [ "$1" == "install" ] +then + if [ "$2" == "-force" ] + then + forceInstall=1 + fi + InstallPerf + InstallLTTng + exit 0 +fi + +# Discover external commands that will be called by this script. +DiscoverCommands + +# Initialize the log. +if [ "$1" != "stop" ] +then + InitializeLog +fi + +# Process arguments. +ProcessArguments $@ + +# Ensure prerequisites are installed. +EnsurePrereqsInstalled + +# Take the appropriate action. +if [ "$action" == "collect" ] || [ "$action" == "start" ] +then + DoCollect +elif [ "$action" == "stop" ] +then + EndCollect +elif [ "$action" == "setenv" ] +then + SetEnvironment +elif [ "$action" == "view" ] +then + DoView +elif [ "$action" == "livetrace" ] +then + DoLiveTrace +fi diff --git a/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.LongDifferentStrings-20250319-164137.trace.zip b/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.LongDifferentStrings-20250319-164137.trace.zip new file mode 100644 index 0000000..0394dbc Binary files /dev/null and b/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.LongDifferentStrings-20250319-164137.trace.zip differ diff --git a/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.LongIdenticalStrings-20250319-164137.trace.zip b/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.LongIdenticalStrings-20250319-164137.trace.zip new file mode 100644 index 0000000..27d9401 Binary files /dev/null and b/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.LongIdenticalStrings-20250319-164137.trace.zip differ diff --git a/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.LongPartiallySimilarStrings-20250319-164137.trace.zip b/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.LongPartiallySimilarStrings-20250319-164137.trace.zip new file mode 100644 index 0000000..c8686d3 Binary files /dev/null and b/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.LongPartiallySimilarStrings-20250319-164137.trace.zip differ diff --git a/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.ShortDifferentStrings-20250319-164137.trace.zip b/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.ShortDifferentStrings-20250319-164137.trace.zip new file mode 100644 index 0000000..bb3f148 Binary files /dev/null and b/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.ShortDifferentStrings-20250319-164137.trace.zip differ diff --git a/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.ShortIdenticalStrings-20250319-164137.trace.zip b/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.ShortIdenticalStrings-20250319-164137.trace.zip new file mode 100644 index 0000000..d8ce957 Binary files /dev/null and b/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.ShortIdenticalStrings-20250319-164137.trace.zip differ diff --git a/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.ShortSimilarStrings-20250319-164137.trace.zip b/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.ShortSimilarStrings-20250319-164137.trace.zip new file mode 100644 index 0000000..f759087 Binary files /dev/null and b/C#/LevenshteinRatio.Bench/res/LevenshteinBenchmark.ShortSimilarStrings-20250319-164137.trace.zip differ diff --git a/C#/LevenshteinRatio.Bench/res/perfcollect b/C#/LevenshteinRatio.Bench/res/perfcollect new file mode 100644 index 0000000..c266c9c --- /dev/null +++ b/C#/LevenshteinRatio.Bench/res/perfcollect @@ -0,0 +1,2202 @@ +#!/bin/bash + +############################################################################################################# +# .NET Performance Data Collection Script +############################################################################################################# + +############################################################################################################# +# +# ***** HOW TO USE THIS SCRIPT ***** +# +# This script can be used to collect and view performance data collected with perf_event on Linux. + +# It's job is to make it simple to collect performance traces. +# +# How to collect a performance trace: +# 1. Prior to starting the .NET process, set the environment variable COMPlus_PerfMapEnabled=1. +# This tells the runtime to emit information that enables perf_event to resolve JIT-compiled code symbols. +# +# 2. Setup your system to reproduce the performance issue you'd like to capture. Data collection can be +# started on already running processes. +# +# 3. [Usage #1] use "collect" command +# - Run this script: sudo ./perfcollect collect samplePerfTrace. This will start data collection. +# - Let the repro run as long as you need to capture the performance problem. +# - Hit CTRL+C to stop collection. +# +# [Usage #2] use "start" and "stop" command +# - Run this script: sudo ./perfcollect start samplePerfTrace. This will start data colletion. +# - Let the repro run as long as you need to capture the performance problem. +# - Run: sudo ./perfcollect stop samplePerfTrace. This will stop collection. +# +# 4. When collection is stopped, the script will create a trace.zip file matching the name specified on the +# command line. This file will contain the trace, JIT-compiled symbol information, and all debugging +# symbols for binaries referenced by this trace that were available on the machine at collection time. +# +# How to view a performance trace: +# 1. Run this script: ./perfcollect view samplePerfTrace.trace.zip +# This will extract the trace, place and register all symbol files and JIT-compiled symbol information +# and start the perf_event viewer. By default, you will be looking at a callee view - stacks are ordered +# top down. For a caller or bottom up view, specify '-graphtype caller'. +############################################################################################################# + +###################################### +## FOR DEBUGGING ONLY +###################################### +# set -x + +###################################### +## Collection Options +## NOTE: These values represent the collection defaults. +###################################### + +# Set when we parse command line arguments to determine if we should enable specific collection options. +collect_cpu=1 +collect_threadTime=0 +collect_offcpu=0 + +###################################### +## .NET Event Categories +###################################### + +# Separate GCCollectOnly list because our LTTng implementation doesn't set tracepoint verbosity. +# Once tracepoint verbosity is set, we can set verbosity and collapse this with DotNETRuntime_GCKeyword. +declare -a DotNETRuntime_GCKeyword_GCCollectOnly=( + DotNETRuntime:GCStart + DotNETRuntime:GCStart_V1 + DotNETRuntime:GCStart_V2 + DotNETRuntime:GCEnd + DotNETRuntime:GCEnd_V1 + DotNETRuntime:GCRestartEEEnd + DotNETRuntime:GCRestartEEEnd_V1 + DotNETRuntime:GCHeapStats + DotNETRuntime:GCHeapStats_V1 + DotNETRuntime:GCCreateSegment + DotNETRuntime:GCCreateSegment_V1 + DotNETRuntime:GCFreeSegment + DotNETRuntime:GCFreeSegment_V1 + DotNETRuntime:GCRestartEEBegin + DotNETRuntime:GCRestartEEBegin_V1 + DotNETRuntime:GCSuspendEEEnd + DotNETRuntime:GCSuspendEEEnd_V1 + DotNETRuntime:GCSuspendEEBegin + DotNETRuntime:GCSuspendEEBegin_V1 + DotNETRuntime:GCCreateConcurrentThread + DotNETRuntime:GCTerminateConcurrentThread + DotNETRuntime:GCFinalizersEnd + DotNETRuntime:GCFinalizersEnd_V1 + DotNETRuntime:GCFinalizersBegin + DotNETRuntime:GCFinalizersBegin_V1 + DotNETRuntime:GCMarkStackRoots + DotNETRuntime:GCMarkFinalizeQueueRoots + DotNETRuntime:GCMarkHandles + DotNETRuntime:GCMarkOlderGenerationRoots + DotNETRuntime:FinalizeObject + DotNETRuntime:GCTriggered + DotNETRuntime:IncreaseMemoryPressure + DotNETRuntime:DecreaseMemoryPressure + DotNETRuntime:GCMarkWithType + DotNETRuntime:GCPerHeapHistory_V3 + DotNETRuntime:GCGlobalHeapHistory_V2 + DotNETRuntime:GCCreateConcurrentThread_V1 + DotNETRuntime:GCTerminateConcurrentThread_V1 +) + + +declare -a DotNETRuntime_GCKeyword=( + DotNETRuntime:GCStart + DotNETRuntime:GCStart_V1 + DotNETRuntime:GCStart_V2 + DotNETRuntime:GCEnd + DotNETRuntime:GCEnd_V1 + DotNETRuntime:GCRestartEEEnd + DotNETRuntime:GCRestartEEEnd_V1 + DotNETRuntime:GCHeapStats + DotNETRuntime:GCHeapStats_V1 + DotNETRuntime:GCCreateSegment + DotNETRuntime:GCCreateSegment_V1 + DotNETRuntime:GCFreeSegment + DotNETRuntime:GCFreeSegment_V1 + DotNETRuntime:GCRestartEEBegin + DotNETRuntime:GCRestartEEBegin_V1 + DotNETRuntime:GCSuspendEEEnd + DotNETRuntime:GCSuspendEEEnd_V1 + DotNETRuntime:GCSuspendEEBegin + DotNETRuntime:GCSuspendEEBegin_V1 + DotNETRuntime:GCAllocationTick + DotNETRuntime:GCAllocationTick_V1 + DotNETRuntime:GCAllocationTick_V2 + DotNETRuntime:GCAllocationTick_V3 + DotNETRuntime:GCCreateConcurrentThread + DotNETRuntime:GCTerminateConcurrentThread + DotNETRuntime:GCFinalizersEnd + DotNETRuntime:GCFinalizersEnd_V1 + DotNETRuntime:GCFinalizersBegin + DotNETRuntime:GCFinalizersBegin_V1 + DotNETRuntime:GCMarkStackRoots + DotNETRuntime:GCMarkFinalizeQueueRoots + DotNETRuntime:GCMarkHandles + DotNETRuntime:GCMarkOlderGenerationRoots + DotNETRuntime:FinalizeObject + DotNETRuntime:PinObjectAtGCTime + DotNETRuntime:GCTriggered + DotNETRuntime:IncreaseMemoryPressure + DotNETRuntime:DecreaseMemoryPressure + DotNETRuntime:GCMarkWithType + DotNETRuntime:GCJoin_V2 + DotNETRuntime:GCPerHeapHistory_V3 + DotNETRuntime:GCGlobalHeapHistory_V2 + DotNETRuntime:GCCreateConcurrentThread_V1 + DotNETRuntime:GCTerminateConcurrentThread_V1 +) + +declare -a DotNETRuntime_TypeKeyword=( + DotNETRuntime:BulkType +) + +declare -a DotNETRuntime_GCHeapDumpKeyword=( + DotNETRuntime:GCBulkRootEdge + DotNETRuntime:GCBulkRootConditionalWeakTableElementEdge + DotNETRuntime:GCBulkNode + DotNETRuntime:GCBulkEdge + DotNETRuntime:GCBulkRootCCW + DotNETRuntime:GCBulkRCW + DotNETRuntime:GCBulkRootStaticVar +) + +declare -a DotNETRuntime_GCSampledObjectAllocationHighKeyword=( + DotNETRuntime:GCSampledObjectAllocationHigh +) + +declare -a DotNETRuntime_GCHeapSurvivalAndMovementKeyword=( + DotNETRuntime:GCBulkSurvivingObjectRanges + DotNETRuntime:GCBulkMovedObjectRanges + DotNETRuntime:GCGenerationRange +) + +declare -a DotNETRuntime_GCHandleKeyword=( + DotNETRuntime:SetGCHandle + DotNETRuntime:DestroyGCHandle +) + +declare -a DotNETRuntime_GCSampledObjectAllocationLowKeyword=( + DotNETRuntime:GCSampledObjectAllocationLow +) + +declare -a DotNETRuntime_ThreadingKeyword=( + DotNETRuntime:WorkerThreadCreate + DotNETRuntime:WorkerThreadTerminate + DotNETRuntime:WorkerThreadRetire + DotNETRuntime:WorkerThreadUnretire + DotNETRuntime:IOThreadCreate + DotNETRuntime:IOThreadCreate_V1 + DotNETRuntime:IOThreadTerminate + DotNETRuntime:IOThreadTerminate_V1 + DotNETRuntime:IOThreadRetire + DotNETRuntime:IOThreadRetire_V1 + DotNETRuntime:IOThreadUnretire + DotNETRuntime:IOThreadUnretire_V1 + DotNETRuntime:ThreadpoolSuspensionSuspendThread + DotNETRuntime:ThreadpoolSuspensionResumeThread + DotNETRuntime:ThreadPoolWorkerThreadStart + DotNETRuntime:ThreadPoolWorkerThreadStop + DotNETRuntime:ThreadPoolWorkerThreadRetirementStart + DotNETRuntime:ThreadPoolWorkerThreadRetirementStop + DotNETRuntime:ThreadPoolWorkerThreadAdjustmentSample + DotNETRuntime:ThreadPoolWorkerThreadAdjustmentAdjustment + DotNETRuntime:ThreadPoolWorkerThreadAdjustmentStats + DotNETRuntime:ThreadPoolWorkerThreadWait + DotNETRuntime:ThreadPoolWorkingThreadCount + DotNETRuntime:ThreadPoolIOPack + DotNETRuntime:GCCreateConcurrentThread_V1 + DotNETRuntime:GCTerminateConcurrentThread_V1 +) + +declare -a DotNETRuntime_ThreadingKeyword_ThreadTransferKeyword=( + DotNETRuntime:ThreadPoolEnqueue + DotNETRuntime:ThreadPoolDequeue + DotNETRuntime:ThreadPoolIOEnqueue + DotNETRuntime:ThreadPoolIODequeue + DotNETRuntime:ThreadCreating + DotNETRuntime:ThreadRunning +) + +declare -a DotNETRuntime_NoKeyword=( + DotNETRuntime:ExceptionThrown + DotNETRuntime:Contention + DotNETRuntime:RuntimeInformationStart + DotNETRuntime:EventSource +) + +declare -a DotNETRuntime_ExceptionKeyword=( + DotNETRuntime:ExceptionThrown_V1 + DotNETRuntime:ExceptionCatchStart + DotNETRuntime:ExceptionCatchStop + DotNETRuntime:ExceptionFinallyStart + DotNETRuntime:ExceptionFinallyStop + DotNETRuntime:ExceptionFilterStart + DotNETRuntime:ExceptionFilterStop + DotNETRuntime:ExceptionThrownStop +) + +declare -a DotNETRuntime_ContentionKeyword=( + DotNETRuntime:ContentionStart_V1 + DotNETRuntime:ContentionStop + DotNETRuntime:ContentionStop_V1 +) + +declare -a DotNETRuntime_StackKeyword=( + DotNETRuntime:CLRStackWalk +) + +declare -a DotNETRuntime_AppDomainResourceManagementKeyword=( + DotNETRuntime:AppDomainMemAllocated + DotNETRuntime:AppDomainMemSurvived +) + +declare -a DotNETRuntime_AppDomainResourceManagementKeyword_ThreadingKeyword=( + DotNETRuntime:ThreadCreated + DotNETRuntime:ThreadTerminated + DotNETRuntime:ThreadDomainEnter +) + +declare -a DotNETRuntime_InteropKeyword=( + DotNETRuntime:ILStubGenerated + DotNETRuntime:ILStubCacheHit +) + +declare -a DotNETRuntime_JitKeyword_NGenKeyword=( + DotNETRuntime:DCStartCompleteV2 + DotNETRuntime:DCEndCompleteV2 + DotNETRuntime:MethodDCStartV2 + DotNETRuntime:MethodDCEndV2 + DotNETRuntime:MethodDCStartVerboseV2 + DotNETRuntime:MethodDCEndVerboseV2 + DotNETRuntime:MethodLoad + DotNETRuntime:MethodLoad_V1 + DotNETRuntime:MethodLoad_V2 + DotNETRuntime:MethodUnload + DotNETRuntime:MethodUnload_V1 + DotNETRuntime:MethodUnload_V2 + DotNETRuntime:MethodLoadVerbose + DotNETRuntime:MethodLoadVerbose_V1 + DotNETRuntime:MethodLoadVerbose_V2 + DotNETRuntime:MethodUnloadVerbose + DotNETRuntime:MethodUnloadVerbose_V1 + DotNETRuntime:MethodUnloadVerbose_V2 +) + +declare -a DotNETRuntime_JitKeyword=( + DotNETRuntime:MethodJittingStarted + DotNETRuntime:MethodJittingStarted_V1 +) + +declare -a DotNETRuntime_JitTracingKeyword=( + DotNETRuntime:MethodJitInliningSucceeded + DotNETRuntime:MethodJitInliningFailed + DotNETRuntime:MethodJitTailCallSucceeded + DotNETRuntime:MethodJitTailCallFailed +) + +declare -a DotNETRuntime_JittedMethodILToNativeMapKeyword=( + DotNETRuntime:MethodILToNativeMap +) + +declare -a DotNETRuntime_LoaderKeyword=( + DotNETRuntime:ModuleDCStartV2 + DotNETRuntime:ModuleDCEndV2 + DotNETRuntime:DomainModuleLoad + DotNETRuntime:DomainModuleLoad_V1 + DotNETRuntime:ModuleLoad + DotNETRuntime:ModuleUnload + DotNETRuntime:AssemblyLoad + DotNETRuntime:AssemblyLoad_V1 + DotNETRuntime:AssemblyUnload + DotNETRuntime:AssemblyUnload_V1 + DotNETRuntime:AppDomainLoad + DotNETRuntime:AppDomainLoad_V1 + DotNETRuntime:AppDomainUnload + DotNETRuntime:AppDomainUnload_V1 +) + +declare -a DotNETRuntime_LoaderKeyword=( + DotNETRuntime:ModuleLoad_V1 + DotNETRuntime:ModuleLoad_V2 + DotNETRuntime:ModuleUnload_V1 + DotNETRuntime:ModuleUnload_V2 +) + +declare -a DotNETRuntime_SecurityKeyword=( + DotNETRuntime:StrongNameVerificationStart + DotNETRuntime:StrongNameVerificationStart_V1 + DotNETRuntime:StrongNameVerificationStop + DotNETRuntime:StrongNameVerificationStop_V1 + DotNETRuntime:AuthenticodeVerificationStart + DotNETRuntime:AuthenticodeVerificationStart_V1 + DotNETRuntime:AuthenticodeVerificationStop + DotNETRuntime:AuthenticodeVerificationStop_V1 +) + +declare -a DotNETRuntime_DebuggerKeyword=( + DotNETRuntime:DebugIPCEventStart + DotNETRuntime:DebugIPCEventEnd + DotNETRuntime:DebugExceptionProcessingStart + DotNETRuntime:DebugExceptionProcessingEnd +) + +declare -a DotNETRuntime_CodeSymbolsKeyword=( + DotNETRuntime:CodeSymbols +) + +declare -a DotNETRuntime_CompilationKeyword=( + DotNETRuntime:TieredCompilationSettings + DotNETRuntime:TieredCompilationPause + DotNETRuntime:TieredCompilationResume + DotNETRuntime:TieredCompilationBackgroundJitStart + DotNETRuntime:TieredCompilationBackgroundJitStop + DotNETRuntimeRundown:TieredCompilationSettingsDCStart +) + +# Separate GCCollectOnly list because our LTTng implementation doesn't set tracepoint verbosity. +# Once tracepoint verbosity is set, we can set verbosity and collapse this with DotNETRuntimePrivate_GCPrivateKeyword. +declare -a DotNETRuntimePrivate_GCPrivateKeyword_GCCollectOnly=( + DotNETRuntimePrivate:GCDecision + DotNETRuntimePrivate:GCDecision_V1 + DotNETRuntimePrivate:GCSettings + DotNETRuntimePrivate:GCSettings_V1 + DotNETRuntimePrivate:GCPerHeapHistory + DotNETRuntimePrivate:GCPerHeapHistory_V1 + DotNETRuntimePrivate:GCGlobalHeapHistory + DotNETRuntimePrivate:GCGlobalHeapHistory_V1 + DotNETRuntimePrivate:PrvGCMarkStackRoots + DotNETRuntimePrivate:PrvGCMarkStackRoots_V1 + DotNETRuntimePrivate:PrvGCMarkFinalizeQueueRoots + DotNETRuntimePrivate:PrvGCMarkFinalizeQueueRoots_V1 + DotNETRuntimePrivate:PrvGCMarkHandles + DotNETRuntimePrivate:PrvGCMarkHandles_V1 + DotNETRuntimePrivate:PrvGCMarkCards + DotNETRuntimePrivate:PrvGCMarkCards_V1 + DotNETRuntimePrivate:BGCBegin + DotNETRuntimePrivate:BGC1stNonConEnd + DotNETRuntimePrivate:BGC1stConEnd + DotNETRuntimePrivate:BGC2ndNonConBegin + DotNETRuntimePrivate:BGC2ndNonConEnd + DotNETRuntimePrivate:BGC2ndConBegin + DotNETRuntimePrivate:BGC2ndConEnd + DotNETRuntimePrivate:BGCPlanEnd + DotNETRuntimePrivate:BGCSweepEnd + DotNETRuntimePrivate:BGCDrainMark + DotNETRuntimePrivate:BGCRevisit + DotNETRuntimePrivate:BGCOverflow + DotNETRuntimePrivate:BGCAllocWaitBegin + DotNETRuntimePrivate:BGCAllocWaitEnd + DotNETRuntimePrivate:GCFullNotify + DotNETRuntimePrivate:GCFullNotify_V1 + DotNETRuntimePrivate:PrvFinalizeObject + DotNETRuntimePrivate:PinPlugAtGCTime +) + +declare -a DotNETRuntimePrivate_GCPrivateKeyword=( + DotNETRuntimePrivate:GCDecision + DotNETRuntimePrivate:GCDecision_V1 + DotNETRuntimePrivate:GCSettings + DotNETRuntimePrivate:GCSettings_V1 + DotNETRuntimePrivate:GCOptimized + DotNETRuntimePrivate:GCOptimized_V1 + DotNETRuntimePrivate:GCPerHeapHistory + DotNETRuntimePrivate:GCPerHeapHistory_V1 + DotNETRuntimePrivate:GCGlobalHeapHistory + DotNETRuntimePrivate:GCGlobalHeapHistory_V1 + DotNETRuntimePrivate:GCJoin + DotNETRuntimePrivate:GCJoin_V1 + DotNETRuntimePrivate:PrvGCMarkStackRoots + DotNETRuntimePrivate:PrvGCMarkStackRoots_V1 + DotNETRuntimePrivate:PrvGCMarkFinalizeQueueRoots + DotNETRuntimePrivate:PrvGCMarkFinalizeQueueRoots_V1 + DotNETRuntimePrivate:PrvGCMarkHandles + DotNETRuntimePrivate:PrvGCMarkHandles_V1 + DotNETRuntimePrivate:PrvGCMarkCards + DotNETRuntimePrivate:PrvGCMarkCards_V1 + DotNETRuntimePrivate:BGCBegin + DotNETRuntimePrivate:BGC1stNonConEnd + DotNETRuntimePrivate:BGC1stConEnd + DotNETRuntimePrivate:BGC2ndNonConBegin + DotNETRuntimePrivate:BGC2ndNonConEnd + DotNETRuntimePrivate:BGC2ndConBegin + DotNETRuntimePrivate:BGC2ndConEnd + DotNETRuntimePrivate:BGCPlanEnd + DotNETRuntimePrivate:BGCSweepEnd + DotNETRuntimePrivate:BGCDrainMark + DotNETRuntimePrivate:BGCRevisit + DotNETRuntimePrivate:BGCOverflow + DotNETRuntimePrivate:BGCAllocWaitBegin + DotNETRuntimePrivate:BGCAllocWaitEnd + DotNETRuntimePrivate:GCFullNotify + DotNETRuntimePrivate:GCFullNotify_V1 + DotNETRuntimePrivate:PrvFinalizeObject + DotNETRuntimePrivate:PinPlugAtGCTime +) + +declare -a DotNETRuntimePrivate_StartupKeyword=( + DotNETRuntimePrivate:EEStartupStart + DotNETRuntimePrivate:EEStartupStart_V1 + DotNETRuntimePrivate:EEStartupEnd + DotNETRuntimePrivate:EEStartupEnd_V1 + DotNETRuntimePrivate:EEConfigSetup + DotNETRuntimePrivate:EEConfigSetup_V1 + DotNETRuntimePrivate:EEConfigSetupEnd + DotNETRuntimePrivate:EEConfigSetupEnd_V1 + DotNETRuntimePrivate:LdSysBases + DotNETRuntimePrivate:LdSysBases_V1 + DotNETRuntimePrivate:LdSysBasesEnd + DotNETRuntimePrivate:LdSysBasesEnd_V1 + DotNETRuntimePrivate:ExecExe + DotNETRuntimePrivate:ExecExe_V1 + DotNETRuntimePrivate:ExecExeEnd + DotNETRuntimePrivate:ExecExeEnd_V1 + DotNETRuntimePrivate:Main + DotNETRuntimePrivate:Main_V1 + DotNETRuntimePrivate:MainEnd + DotNETRuntimePrivate:MainEnd_V1 + DotNETRuntimePrivate:ApplyPolicyStart + DotNETRuntimePrivate:ApplyPolicyStart_V1 + DotNETRuntimePrivate:ApplyPolicyEnd + DotNETRuntimePrivate:ApplyPolicyEnd_V1 + DotNETRuntimePrivate:LdLibShFolder + DotNETRuntimePrivate:LdLibShFolder_V1 + DotNETRuntimePrivate:LdLibShFolderEnd + DotNETRuntimePrivate:LdLibShFolderEnd_V1 + DotNETRuntimePrivate:PrestubWorker + DotNETRuntimePrivate:PrestubWorker_V1 + DotNETRuntimePrivate:PrestubWorkerEnd + DotNETRuntimePrivate:PrestubWorkerEnd_V1 + DotNETRuntimePrivate:GetInstallationStart + DotNETRuntimePrivate:GetInstallationStart_V1 + DotNETRuntimePrivate:GetInstallationEnd + DotNETRuntimePrivate:GetInstallationEnd_V1 + DotNETRuntimePrivate:OpenHModule + DotNETRuntimePrivate:OpenHModule_V1 + DotNETRuntimePrivate:OpenHModuleEnd + DotNETRuntimePrivate:OpenHModuleEnd_V1 + DotNETRuntimePrivate:ExplicitBindStart + DotNETRuntimePrivate:ExplicitBindStart_V1 + DotNETRuntimePrivate:ExplicitBindEnd + DotNETRuntimePrivate:ExplicitBindEnd_V1 + DotNETRuntimePrivate:ParseXml + DotNETRuntimePrivate:ParseXml_V1 + DotNETRuntimePrivate:ParseXmlEnd + DotNETRuntimePrivate:ParseXmlEnd_V1 + DotNETRuntimePrivate:InitDefaultDomain + DotNETRuntimePrivate:InitDefaultDomain_V1 + DotNETRuntimePrivate:InitDefaultDomainEnd + DotNETRuntimePrivate:InitDefaultDomainEnd_V1 + DotNETRuntimePrivate:InitSecurity + DotNETRuntimePrivate:InitSecurity_V1 + DotNETRuntimePrivate:InitSecurityEnd + DotNETRuntimePrivate:InitSecurityEnd_V1 + DotNETRuntimePrivate:AllowBindingRedirs + DotNETRuntimePrivate:AllowBindingRedirs_V1 + DotNETRuntimePrivate:AllowBindingRedirsEnd + DotNETRuntimePrivate:AllowBindingRedirsEnd_V1 + DotNETRuntimePrivate:EEConfigSync + DotNETRuntimePrivate:EEConfigSync_V1 + DotNETRuntimePrivate:EEConfigSyncEnd + DotNETRuntimePrivate:EEConfigSyncEnd_V1 + DotNETRuntimePrivate:FusionBinding + DotNETRuntimePrivate:FusionBinding_V1 + DotNETRuntimePrivate:FusionBindingEnd + DotNETRuntimePrivate:FusionBindingEnd_V1 + DotNETRuntimePrivate:LoaderCatchCall + DotNETRuntimePrivate:LoaderCatchCall_V1 + DotNETRuntimePrivate:LoaderCatchCallEnd + DotNETRuntimePrivate:LoaderCatchCallEnd_V1 + DotNETRuntimePrivate:FusionInit + DotNETRuntimePrivate:FusionInit_V1 + DotNETRuntimePrivate:FusionInitEnd + DotNETRuntimePrivate:FusionInitEnd_V1 + DotNETRuntimePrivate:FusionAppCtx + DotNETRuntimePrivate:FusionAppCtx_V1 + DotNETRuntimePrivate:FusionAppCtxEnd + DotNETRuntimePrivate:FusionAppCtxEnd_V1 + DotNETRuntimePrivate:Fusion2EE + DotNETRuntimePrivate:Fusion2EE_V1 + DotNETRuntimePrivate:Fusion2EEEnd + DotNETRuntimePrivate:Fusion2EEEnd_V1 + DotNETRuntimePrivate:SecurityCatchCall + DotNETRuntimePrivate:SecurityCatchCall_V1 + DotNETRuntimePrivate:SecurityCatchCallEnd + DotNETRuntimePrivate:SecurityCatchCallEnd_V1 +) + +declare -a DotNETRuntimePrivate_StackKeyword=( + DotNETRuntimePrivate:CLRStackWalkPrivate +) + +declare -a DotNETRuntimePrivate_PerfTrackPrivateKeyword=( + DotNETRuntimePrivate:ModuleRangeLoadPrivate +) + +declare -a DotNETRuntimePrivate_BindingKeyword=( + DotNETRuntimePrivate:BindingPolicyPhaseStart + DotNETRuntimePrivate:BindingPolicyPhaseEnd + DotNETRuntimePrivate:BindingNgenPhaseStart + DotNETRuntimePrivate:BindingNgenPhaseEnd + DotNETRuntimePrivate:BindingLookupAndProbingPhaseStart + DotNETRuntimePrivate:BindingLookupAndProbingPhaseEnd + DotNETRuntimePrivate:LoaderPhaseStart + DotNETRuntimePrivate:LoaderPhaseEnd + DotNETRuntimePrivate:BindingPhaseStart + DotNETRuntimePrivate:BindingPhaseEnd + DotNETRuntimePrivate:BindingDownloadPhaseStart + DotNETRuntimePrivate:BindingDownloadPhaseEnd + DotNETRuntimePrivate:LoaderAssemblyInitPhaseStart + DotNETRuntimePrivate:LoaderAssemblyInitPhaseEnd + DotNETRuntimePrivate:LoaderMappingPhaseStart + DotNETRuntimePrivate:LoaderMappingPhaseEnd + DotNETRuntimePrivate:LoaderDeliverEventsPhaseStart + DotNETRuntimePrivate:LoaderDeliverEventsPhaseEnd + DotNETRuntimePrivate:FusionMessageEvent + DotNETRuntimePrivate:FusionErrorCodeEvent +) + +declare -a DotNETRuntimePrivate_SecurityPrivateKeyword=( + DotNETRuntimePrivate:EvidenceGenerated + DotNETRuntimePrivate:ModuleTransparencyComputationStart + DotNETRuntimePrivate:ModuleTransparencyComputationEnd + DotNETRuntimePrivate:TypeTransparencyComputationStart + DotNETRuntimePrivate:TypeTransparencyComputationEnd + DotNETRuntimePrivate:MethodTransparencyComputationStart + DotNETRuntimePrivate:MethodTransparencyComputationEnd + DotNETRuntimePrivate:FieldTransparencyComputationStart + DotNETRuntimePrivate:FieldTransparencyComputationEnd + DotNETRuntimePrivate:TokenTransparencyComputationStart + DotNETRuntimePrivate:TokenTransparencyComputationEnd +) + +declare -a DotNETRuntimePrivate_PrivateFusionKeyword=( + DotNETRuntimePrivate:NgenBindEvent +) + +declare -a DotNETRuntimePrivate_NoKeyword=( + DotNETRuntimePrivate:FailFast +) + +declare -a DotNETRuntimePrivate_InteropPrivateKeyword=( + DotNETRuntimePrivate:CCWRefCountChange +) + +declare -a DotNETRuntimePrivate_GCHandlePrivateKeyword=( + DotNETRuntimePrivate:PrvSetGCHandle + DotNETRuntimePrivate:PrvDestroyGCHandle +) + +declare -a DotNETRuntimePrivate_LoaderHeapPrivateKeyword=( + DotNETRuntimePrivate:AllocRequest +) + +declare -a DotNETRuntimePrivate_MulticoreJitPrivateKeyword=( + DotNETRuntimePrivate:MulticoreJit + DotNETRuntimePrivate:MulticoreJitMethodCodeReturned +) + +declare -a DotNETRuntimePrivate_DynamicTypeUsageKeyword=( + DotNETRuntimePrivate:IInspectableRuntimeClassName + DotNETRuntimePrivate:WinRTUnbox + DotNETRuntimePrivate:CreateRCW + DotNETRuntimePrivate:RCWVariance + DotNETRuntimePrivate:RCWIEnumerableCasting + DotNETRuntimePrivate:CreateCCW + DotNETRuntimePrivate:CCWVariance + DotNETRuntimePrivate:ObjectVariantMarshallingToNative + DotNETRuntimePrivate:GetTypeFromGUID + DotNETRuntimePrivate:GetTypeFromProgID + DotNETRuntimePrivate:ConvertToCallbackEtw + DotNETRuntimePrivate:BeginCreateManagedReference + DotNETRuntimePrivate:EndCreateManagedReference + DotNETRuntimePrivate:ObjectVariantMarshallingToManaged +) + +declare -a EventSource=( + DotNETRuntime:EventSource +) + +declare -a LTTng_Kernel_ProcessLifetimeKeyword=( + sched_process_exec + sched_process_exit +) + + +###################################### +## Global Variables +###################################### + +# Install without waiting for standard input +forceInstall=0 + +# Declare an array of events to collect. +declare -a eventsToCollect + +# Use Perf_Event +usePerf=1 + +# Use LTTng +useLTTng=1 + +# LTTng Installed +lttngInstalled=0 + +# Collect hardware events +collect_HWevents=0 + +# Set to 1 when the CTRLC_Handler gets invoked. +handlerInvoked=0 + +# Log file +declare logFile +logFilePrefix='/tmp/perfcollect' +logEnabled=0 + +# Collect info to pass between processes +collectInfoFile=$(dirname `mktemp -u`)/'perfcollect.sessioninfo' + +###################################### +## Logging Functions +###################################### +LogAppend() +{ + if (( $logEnabled == 1 )) + then + echo $* >> $logFile + fi +} + +RunSilent() +{ + if (( $logEnabled == 1 )) + then + echo "Running \"$*\"" >> $logFile + $* >> $logFile 2>&1 + echo "" >> $logFile + else + $* > /dev/null 2>&1 + fi +} + +RunSilentBackground() +{ + if (( $logEnabled == 1 )) + then + echo "Running \"$*\"" >> $logFile + $* >> $logFile 2>&1 & sleep 1 + echo "" >> $logFile + else + $* > /dev/null 2>&1 & sleep 1 + fi + + # When handler is invoked, kill the process. + pid=$! + for (( ; ; )) + do + if [ "$handlerInvoked" == "1" ] + then + kill -INT $pid + break; + else + sleep 1 + fi + done + + # Wait for the process to exit. + wait $pid +} + +InitializeLog() +{ + # Pick the log file name. + logFile="$logFilePrefix.log" + while [ -f $logFile ]; + do + logFile="$logFilePrefix.$RANDOM.log" + done + + # Mark the log as enabled. + logEnabled=1 + + # Start the log + date=`date` + echo "Log started at ${date}" > $logFile + echo '' >> $logFile + + # The system information. + LogAppend 'Machine info: ' `uname -a` + if [ "$perfcmd" != "" ] + then + LogAppend 'perf version:' `$perfcmd --version 2>&1` + fi + if [ "$lttngcmd" != "" ] + then + LogAppend 'LTTng version: ' `$lttngcmd --version` + fi + LogAppend +} + +CloseLog() +{ + LogAppend "END LOG FILE" + LogAppend "NOTE: It is normal for the log file to end right before the trace is actually compressed. This occurs because the log file is part of the archive, and thus can't be written anymore." + + # The log itself doesn't need to be closed, + # but we need to tell the script not to log anymore. + logEnabled=0 +} + + +###################################### +## Helper Functions +###################################### + +## +# Console text color modification helpers. +## +RedText() +{ + tput=`GetCommandFullPath "tput"` + if [ "$tput" != "" ] + then + $tput setaf 1 + fi +} + +GreenText() +{ + tput=`GetCommandFullPath "tput"` + if [ "$tput" != "" ] + then + $tput setaf 2 + fi +} + +BlueText() +{ + tput=`GetCommandFullPath "tput"` + if [ "$tput" != "" ] + then + $tput setaf 6 + fi +} +YellowText() +{ + tput=`GetCommandFullPath "tput"` + if [ "$tput" != "" ] + then + $tput setaf 3 + fi +} + +ResetText() +{ + tput=`GetCommandFullPath "tput"` + if [ "$tput" != "" ] + then + $tput sgr0 + fi +} + +# $1 == Status message +WriteStatus() +{ + LogAppend $* + BlueText + echo $1 + ResetText +} + +# $1 == Message. +WriteWarning() +{ + LogAppend $* + YellowText + echo $1 + ResetText +} + +# $1 == Message. +FatalError() +{ + RedText + echo "ERROR: $1" + ResetText + PrintUsage + exit 1 +} + +EnsureRoot() +{ + # Warn non-root users. + if [ `whoami` != "root" ] + then + RedText + echo "This script must be run as root." + ResetText + exit 1; + fi +} + +###################################### +# Command Discovery +###################################### +DiscoverCommands() +{ + perfcmd=`GetCommandFullPath "perf"` + if [ "$(IsDebian)" == "1" ] + then + # Test perf to see if it successfully runs or fails because it doesn't match the kernel version. + $perfcmd --version > /dev/null 2>&1 + if [ "$?" == "1" ] + then + perf49Cmd=`GetCommandFullPath "perf_4.9"` + $perf49Cmd --version > /dev/null 2>&1 + if [ "$?" == "0" ] + then + perfcmd=$perf49Cmd + else + perf419Cmd=`GetCommandFullPath "perf_4.19"` + $perf419Cmd --version > /dev/null 2>&1 + if [ "$?" == "0" ] + then + perfcmd=$perf419Cmd + else + perf316Cmd=`GetCommandFullPath "perf_3.16"` + $perf316Cmd --version > /dev/null 2>&1 + if [ "$?" == "0" ] + then + perfcmd=$perf316Cmd + fi + fi + fi + fi + fi + + # Check to see if perf is installed, but doesn't exactly match the current kernel version. + # This happens when the kernel gets upgraded, or when running inside of a container where the + # host and container OS versions don't match. + perfoutput=$($perfcmd 2>&1) + if [ $? -eq 2 ] + then + # Check the beginning of the output to see if it matches the kernel warning. + warningText="WARNING: perf not found for kernel" + if [[ "$perfoutput" == "$warningText"* ]] + then + foundWorkingPerf=0 + WriteWarning "Perf is installed, but does not exactly match the version of the running kernel." + WriteWarning "This is often OK, and we'll try to workaround this." + WriteStatus "Attempting to find a working copy of perf." + # Attempt to find an existing version of perf to use. + # Order the search by newest directory first. + baseDir="/usr/lib/linux-tools" + searchPath="$baseDir/*/" + for dirName in $(ls -d --sort=time $searchPath) + do + candidatePerfPath="$dirName""perf" + $($candidatePerfPath > /dev/null 2>&1) + if [ $? -eq 1 ] + then + # If $? == 1, then use this copy of perf. + perfcmd=$candidatePerfPath + foundWorkingPerf=1 + break; + fi + done + if [ $foundWorkingPerf -eq 0 ] + then + FatalError "Unable to find a working copy of perf. Try re-installing via ./perfcollect install." + fi + WriteStatus "...FINISHED" + fi + fi + + lttngcmd=`GetCommandFullPath "lttng"` + zipcmd=`GetCommandFullPath "zip"` + unzipcmd=`GetCommandFullPath "unzip"` + objdumpcmd=`GetCommandFullPath "objdump"` +} + +GetCommandFullPath() +{ + echo `command -v $1` +} + +###################################### +# Prerequisite Installation +###################################### +IsAlpine() +{ + local alpine=0 + local apk=`GetCommandFullPath "apk"` + if [ "$apk" != "" ] + then + alpine=1 + fi + + echo $alpine +} + +InstallPerf_Alpine() +{ + # Disallow non-root users. + EnsureRoot + + # Install perf + apk add perf --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community + + # Install zip and unzip + apk add zip unzip +} + +IsRHEL() +{ + local rhel=0 + if [ -f /etc/redhat-release ] + then + rhel=1 + fi + + echo $rhel +} + +InstallPerf_RHEL() +{ + # Disallow non-root users. + EnsureRoot + + # Install perf + yum install perf zip unzip +} + +IsDebian() +{ + local debian=0 + local uname=`uname -a` + if [[ $uname =~ .*Debian.* ]] + then + debian=1 + elif [ -f /etc/debian_version ] + then + debian=1 + fi + + echo $debian +} + +InstallPerf_Debian() +{ + # Disallow non-root users. + EnsureRoot + + # Check for the existence of the linux-tools package. + pkgName='linux-tools' + pkgCount=`apt-cache search $pkgName | grep -c $pkgName` + if [ "$pkgCount" == "0" ] + then + pkgName='linux-perf' + pkgCount=`apt-cache search $pkgName | grep -c $pkgName` + if [ "$pkgCount" == "0" ] + then + FatalError "Unable to find a perf package to install." + fi + fi + + # Install zip and perf. + apt-get install -y zip binutils $pkgName +} + +IsSUSE() +{ + local suse=0 + if [ -f /usr/bin/zypper ] + then + suse=1 + fi + + echo $suse +} + +InstallPerf_SUSE() +{ + # Disallow non-root users. + EnsureRoot + + # Install perf. + zypper install perf zip unzip +} + +IsUbuntu() +{ + local ubuntu=0 + if [ -f /etc/lsb-release ] + then + local flavor=`cat /etc/lsb-release | grep DISTRIB_ID` + if [ "$flavor" == "DISTRIB_ID=Ubuntu" ] + then + ubuntu=1 + fi + fi + + echo $ubuntu +} + +InstallPerf_Ubuntu() +{ + # Disallow non-root users. + EnsureRoot + + # Install packages. + BlueText + echo "Installing perf_event packages." + ResetText + + # Handle Azure instances. + release=`uname -r` + if [[ "$release" == *"-azure" ]] + then + apt-get install -y linux-tools-azure zip software-properties-common + else + apt-get install -y linux-tools-common linux-tools-`uname -r` linux-cloud-tools-`uname -r` zip software-properties-common + fi +} + +InstallPerf() +{ + if [ "$(IsUbuntu)" == "1" ] + then + InstallPerf_Ubuntu + elif [ "$(IsSUSE)" == "1" ] + then + InstallPerf_SUSE + elif [ "$(IsDebian)" == "1" ] + then + InstallPerf_Debian + elif [ "$(IsRHEL)" == "1" ] + then + InstallPerf_RHEL + elif [ "$(IsAlpine)" == "1" ] + then + InstallPerf_Alpine + else + FatalError "Auto install unsupported for this distribution. Install perf manually to continue." + fi +} + +InstallLTTng_RHEL() +{ + # Disallow non-root users. + EnsureRoot + + local isRHEL7=0 + local isRHEL8=0 + if [ -e /etc/redhat-release ]; then + local redhatRelease=$(.dump files. + # Convert to jit dump file name. + local pid=`echo $mapFile | awk -F"-" '{print $NF}' | awk -F"." '{print $1}'` + local path=`echo $mapFile | awk -F"/" '{OFS="/";NF--;print $0;}'` + local jitDumpFile="$path/jit-$pid.dump" + + if [ -f $jitDumpFile ] + then + LogAppend "Saving $jitDumpFile" + RunSilent "cp $jitDumpFile ." + writeCrossgenWarning=0 + fi + done + + WriteStatus "Generating native image symbol files" + + # Get the list of loaded images and use the path to libcoreclr.so to find crossgen. + # crossgen is expected to sit next to libcoreclr.so. + local buildidList=`$perfcmd buildid-list | grep libcoreclr.so | cut -d ' ' -f 2` + local crossgenCmd='' + local crossgenDir='' + for file in $buildidList + do + crossgenDir=`dirname "${file}"` + if [ -f ${crossgenDir}/crossgen ] + then + crossgenCmd=${crossgenDir}/crossgen + LogAppend "Found crossgen at ${crossgenCmd}" + break + fi + done + + OLDIFS=$IFS + + imagePaths="" + + if [ "$crossgenCmd" != "" ] + then + local perfinfos=`ls . | grep perfinfo | cut -d ' ' -f 2` + for perfinfo in $perfinfos + do + if [ -f $perfinfo ] + then + IFS=";" + while read command dll guid; do + if [ $command ]; then + if [ $command = "ImageLoad" ]; then + if [ -f $dll ]; then + imagePaths="${dll}:${imagePaths}" + fi + fi + fi + done < $perfinfo + IFS=$OLDIFS + fi + done + + IFS=":" + LogAppend "Generating PerfMaps for native images" + for path in $imagePaths + do + if [ `echo ${path} | grep ^.*\.dll$` ] + then + IFS="" + LogAppend "Generating PerfMap for ${path}" + LogAppend "Running ${crossgenCmd} /r $imagePaths /CreatePerfMap . ${path}" + ${crossgenCmd} /r $imagePaths /CreatePerfMap . ${path} >> $logFile 2>&1 + IFS=":" + else + LogAppend "Skipping ${path}" + fi + done + else + if [ "$buildidList" != "" ] && [ $writeCrossgenWarning -eq 1 ] + then + LogAppend "crossgen not found, skipping native image map generation." + WriteStatus "...SKIPPED" + WriteWarning "Crossgen not found. Framework symbols will be unavailable." + WriteWarning "See https://github.com/dotnet/coreclr/blob/master/Documentation/project-docs/linux-performance-tracing.md#resolving-framework-symbols for details." + fi + fi + + IFS=$OLDIFS + + WriteStatus "...FINISHED" + + if [ "$objdumpcmd" != "" ] + then + # Create debuginfo files (separate symbols) for all modules in the trace. + WriteStatus "Saving native symbols" + + # Get the list of DSOs with hits in the trace file (those that are actually used). + # Filter out /tmp/perf-$pid.map files and files that end in .dll. + local dsosWithHits=`$perfcmd buildid-list --with-hits | grep -v /tmp/perf- | grep -v .dll$` + for dso in $dsosWithHits + do + # Build up tuples of buildid and binary path. + local processEntry=0 + if [ -f $dso ] + then + local pathToBinary=$dso + processEntry=1 + else + local buildid=$dso + pathToBinary='' + fi + + # Once we have a tuple for a binary path that exists, process it. + if [ "$processEntry" == "1" ] + then + # Get the binary name without path. + local binaryName=`basename $pathToBinary` + + # Build the debuginfo file name. + local destFileName=$binaryName.debuginfo + + # Build the destination directory for the debuginfo file. + local currentDir=`pwd` + local destDir=$currentDir/debuginfo/$buildid + + # Build the full path to the debuginfo file. + local destPath=$destDir/$destFileName + + # Check to see if the DSO contains symbols, and if so, build the debuginfo file. + local noSymbols=`$objdumpcmd -t $pathToBinary | grep "no symbols" -c` + if [ "$noSymbols" == "0" ] + then + LogAppend "Generating debuginfo for $binaryName with buildid=$buildid" + RunSilent "mkdir -p $destDir" + RunSilent "objcopy --only-keep-debug $pathToBinary $destPath" + else + LogAppend "Skipping $binaryName with buildid=$buildid. No symbol information." + fi + fi + done + + WriteStatus "...FINISHED" + fi + + WriteStatus "Resolving JIT and R2R symbols" + + originalFile="perf.data" + inputFile="perf-jit.data" + RunSilent $perfcmd inject --input $originalFile --jit --output $inputFile + + WriteStatus "...FINISHED" + + WriteStatus "Exporting perf.data file" + + outputDumpFile="perf.data.txt" + + # I've not found a good way to get the behavior that we want here - running the command and redirecting the output + # when passing the command line to a function. Thus, this case is hardcoded. + + # There is a breaking change where the capitalization of the -f parameter changed. + LogAppend "Running $perfcmd script -i $inputFile -F comm,pid,tid,cpu,time,period,event,ip,sym,dso,trace > $outputDumpFile" + $perfcmd script -i $inputFile -F comm,pid,tid,cpu,time,period,event,ip,sym,dso,trace > $outputDumpFile 2>>$logFile + LogAppend + + if [ $? -ne 0 ] + then + LogAppend "Running $perfcmd script -i $inputFile -f comm,pid,tid,cpu,time,period,event,ip,sym,dso,trace > $outputDumpFile" + $perfcmd script -i $inputFile -f comm,pid,tid,cpu,time,period,event,ip,sym,dso,trace > $outputDumpFile 2>>$logFile + LogAppend + fi + + # If the dump file is zero length, try to collect without the period field, which was added recently. + if [ ! -s $outputDumpFile ] + then + LogAppend "Running $perfcmd script -i $inputFile -f comm,pid,tid,cpu,time,event,ip,sym,dso,trace > $outputDumpFile" + $perfcmd script -i $inputFile -f comm,pid,tid,cpu,time,event,ip,sym,dso,trace > $outputDumpFile 2>>$logFile + LogAppend + fi + + WriteStatus "...FINISHED" + fi + + WriteStatus "Compressing trace files" + + # Move all collected files to the new directory. + RunSilent "mv -f * $directoryName" + + # Close the log - this stops all writing to the log, so that we can move it into the archive. + CloseLog + + # Move the log file to the new directory and rename it to the standard log name. + RunSilent "mv $logFile $directoryName/perfcollect.log" + + # Compress the data. + local archiveSuffix=".zip" + local archiveName=$directoryName$archiveSuffix + RunSilent "$zipcmd -r $archiveName $directoryName" + + # Move back to the original directory. + popd > /dev/null + + # Move the archive. + RunSilent "mv $tempDir/$archiveName ." + + WriteStatus "...FINISHED" + + WriteStatus "Cleaning up artifacts" + + # Delete the temp directory. + RunSilent "rm -rf $tempDir $collectInfoFile" + + WriteStatus "...FINISHED" + + # Tell the user where the trace is. + WriteStatus + WriteStatus "Trace saved to $archiveName" +} + +## +# Handle the CTRL+C signal. +## +CTRLC_Handler() +{ + # Mark the handler invoked. + handlerInvoked=1 +} + +EndCollect() +{ + # The user must either use "collect stop" or CTRL+C to stop collection. + if [ "$action" == "stop" ] + then + # Recover trace info in the previous program. + source $collectInfoFile # TODO: exit and dispose upon missing file + # New program started, so go back to the temp directory. + pushd $tempDir > /dev/null + fi + + if [ "$useLTTng" == "1" ] + then + StopLTTngCollection + fi + + # Update the user. + WriteStatus + WriteStatus "...STOPPED." + WriteStatus + WriteStatus "Starting post-processing. This may take some time." + WriteStatus + + # The user used CTRL+C to stop collection. + # When this happens, we catch the signal and finish our work. + ProcessCollectedData +} + +## +# Print usage information. +## +PrintUsage() +{ + echo "This script uses perf_event and LTTng to collect and view performance traces for .NET applications." + echo "For detailed collection and viewing steps, view this script in a text editor or viewer." + echo "" + echo "./perfcollect " + echo "Valid Actions: collect start/stop view livetrace install" + echo "" + echo "collect options:" + echo "By default, collection includes CPU samples collected every ms." + echo " -pid : Only collect data from the specified process id." + echo " -threadtime : Collect events for thread time analysis (on and off cpu)." + echo " -offcpu : Collect events for off-cpu analysis." + echo " -hwevents : Collect (some) hardware counters." + echo "" + echo "start:" + echo " Start collection, but with Lttng trace ONLY. It needs to be used with 'stop' action." + echo "" + echo "stop:" + echo " Stop collection if 'start' action is used." + echo "" + echo "view options:" + echo " -processfilter : Filter data by the specified process name." + echo " -graphtype : Specify the type of graph. Valid values are 'caller' and 'callee'. Default is 'callee'." + echo " -viewer : Specify the data viewer. Valid values are 'perf' and 'lttng'. Default is 'perf'." + echo "" + echo "livetrace:" + echo " Print EventSource events directly to the console. Root privileges not required." + echo "" + echo "install options:" + echo " Useful for first-time setup. Installs/upgrades perf_event and LTTng." + echo " -force : Force installation of required packages without prompt" + echo "" +} + +## +# Validate and set arguments. +## + +BuildPerfRecordArgs() +{ + # Start with default collection arguments that record at realtime priority, all CPUs (-a), and collect call stacks (-g) + collectionArgs="record -k 1 -g" + + # Filter to a single process if desired + if [ "$collectionPid" != "" ] + then + collectionArgs="$collectionArgs --pid=$collectionPid" + else + collectionArgs="$collectionArgs -a" + fi + + # Enable CPU Collection + if [ $collect_cpu -eq 1 ] + then + collectionArgs="$collectionArgs" + eventsToCollect=( "${eventsToCollect[@]}" "cpu-clock" ) + + # If only collecting CPU events, set the sampling rate to 1000. + # Otherwise, use the default sampling rate to avoid sampling sched events. + if [ $collect_threadTime -eq 0 ] && [ $collect_offcpu -eq 0 ] + then + collectionArgs="$collectionArgs -F 1000" + fi + fi + + # Enable HW counters event collection + if [ $collect_HWevents -eq 1 ] + then + collectionArgs="$collectionArgs -e cycles,instructions,branches,cache-misses" + fi + + # Enable context switches. + if [ $collect_threadTime -eq 1 ] + then + eventsToCollect=( "${eventsToCollect[@]}" "sched:sched_stat_sleep" "sched:sched_switch" "sched:sched_process_exit" ) + fi + + # Enable offcpu collection + if [ $collect_offcpu -eq 1 ] + then + eventsToCollect=( "${eventsToCollect[@]}" "sched:sched_stat_sleep" "sched:sched_switch" "sched:sched_process_exit" ) + fi + + # Build up the set of events. + local eventString="" + local comma="," + for (( i=0; i<${#eventsToCollect[@]}; i++ )) + do + # Get the arg. + eventName=${eventsToCollect[$i]} + + # Build up the comma separated list. + if [ "$eventString" == "" ] + then + eventString=$eventName + else + eventString="$eventString$comma$eventName" + fi + + done + + if [ ! -z ${duration} ] + then + durationString="sleep ${duration}" + fi + + # Add the events onto the collection command line args. + collectionArgs="$collectionArgs -e $eventString $durationString" +} + +DoCollect() +{ + # Ensure the script is run as root. + EnsureRoot + + # Build collection args. + # Places the resulting args in $collectionArgs + BuildPerfRecordArgs + + # Trap CTRL+C + trap CTRLC_Handler SIGINT + + # Create a temp directory to use for collection. + local tempDir=`mktemp -d` + LogAppend "Created temp directory $tempDir" + + # Switch to the directory. + pushd $tempDir > /dev/null + + # Start LTTng collection. + if [ "$useLTTng" == "1" ] + then + StartLTTngCollection + fi + + # Tell the user that collection has started and how to exit. + if [ "$duration" != "" ] + then + WriteStatus "Collection started. Collection will automatically stop in $duration second(s). Press CTRL+C to stop early." + elif [ "$action" == "start" ] + then + WriteStatus "Collection started." + else + WriteStatus "Collection started. Press CTRL+C to stop." + fi + + # Start perf record. + if [ "$action" == "start" ] + then + # Skip perf, which can only be stopped by CTRL+C. + # Pass trace directory and session name to the stop process. + popd > /dev/null + usePerf=0 + declare -p | grep -e lttngTraceDir -e lttngSessionName -e tempDir -e usePerf -e useLttng -e logFile > $collectInfoFile + else + if [ "$usePerf" == "1" ] + then + if [ ! -z ${duration} ] + then + RunSilent $perfcmd $collectionArgs + else + RunSilentBackground $perfcmd $collectionArgs + fi + else + # Wait here until CTRL+C handler gets called when user types CTRL+C. + LogAppend "Waiting for CTRL+C handler to get called." + + waitTime=0 + for (( ; ; )) + do + if [ "$handlerInvoked" == "1" ] + then + break; + fi + + # Wait and then check to see if the handler has been invoked or we've crossed the duration threshold. + sleep 1 + waitTime=$waitTime+1 + if (( duration > 0 && duration <= waitTime )) + then + break; + fi + done + fi + # End collection if action is 'collect'. + EndCollect + fi +} + +DoLiveTrace() +{ + # Start the session + StartLTTngCollection + + # View the event stream (until the user hits CTRL+C) + WriteStatus "Listening for events from LTTng. Hit CTRL+C to stop." + $lttngcmd view + + # Stop the LTTng sessoin + StopLTTngCollection +} + +# $1 == Path to directory containing trace files +PropSymbolsAndMapFilesForView() +{ + # Get the current directory + local currentDir=`pwd` + + # Copy map files to /tmp since they aren't supported by perf buildid-cache. + local mapFiles=`find -name *.map` + for mapFile in $mapFiles + do + echo "Copying $mapFile to /tmp." + cp $mapFile /tmp + done + + # Cache all debuginfo files saved with the trace in the buildid cache. + local debugInfoFiles=`find $currentDir -name *.debuginfo` + for debugInfoFile in $debugInfoFiles + do + echo "Caching $debugInfoFile in buildid cache using perf buildid-cache." + $perfcmd buildid-cache --add=$debugInfoFile + done +} + +DoView() +{ + # Generate a temp directory to extract the trace files into. + local tempDir=`mktemp -d` + + # Extract the trace files. + $unzipcmd $inputTraceName -d $tempDir + + # Move the to temp directory. + pushd $tempDir + cd `ls` + + # Select the viewer. + if [ "$viewer" == "perf" ] + then + # Prop symbols and map files. + PropSymbolsAndMapFilesForView `pwd` + + # Choose the view + if [ "$graphType" == "" ] + then + graphType="callee" + elif [ "$graphType" != "callee" ] && [ "$graphType" != "caller"] + then + FatalError "Invalid graph type specified. Valid values are 'callee' and 'caller'." + fi + + # Filter to specific process names if desired. + if [ "$processFilter" != "" ] + then + processFilter="--comms=$processFilter" + fi + + # Execute the viewer. + $perfcmd report -n -g graph,0.5,$graphType $processFilter $perfOpt + elif [ "$viewer" == "lttng" ] + then + babeltrace lttngTrace/ | more + fi + + # Switch back to the original directory. + popd + + # Delete the temp directory. + rm -rf $tempDir +} + +##################################### +## Main Script Start +##################################### + +# No arguments +if [ "$#" == "0" ] +then + PrintUsage + exit 0 +fi + +# Install perf if requested. Do this before all other validation. +if [ "$1" == "install" ] +then + if [ "$2" == "-force" ] + then + forceInstall=1 + fi + InstallPerf + InstallLTTng + exit 0 +fi + +# Discover external commands that will be called by this script. +DiscoverCommands + +# Initialize the log. +if [ "$1" != "stop" ] +then + InitializeLog +fi + +# Process arguments. +ProcessArguments $@ + +# Ensure prerequisites are installed. +EnsurePrereqsInstalled + +# Take the appropriate action. +if [ "$action" == "collect" ] || [ "$action" == "start" ] +then + DoCollect +elif [ "$action" == "stop" ] +then + EndCollect +elif [ "$action" == "view" ] +then + DoView +elif [ "$action" == "livetrace" ] +then + DoLiveTrace +fi \ No newline at end of file diff --git a/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report-brief.json b/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report-brief.json new file mode 100644 index 0000000..bdc15ee --- /dev/null +++ b/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report-brief.json @@ -0,0 +1,373 @@ +{ + "Title":"LevenshteinBenchmark-20250319-164145", + "HostEnvironmentInfo":{ + "BenchmarkDotNetCaption":"BenchmarkDotNet", + "BenchmarkDotNetVersion":"0.14.0", + "OsVersion":"Ubuntu 24.04.2 LTS (Noble Numbat)", + "ProcessorName":"11th Gen Intel Core i5-1135G7 2.40GHz", + "PhysicalProcessorCount":1, + "PhysicalCoreCount":4, + "LogicalCoreCount":8, + "RuntimeVersion":".NET 9.0.3 (9.0.325.11113)", + "Architecture":"X64", + "HasAttachedDebugger":false, + "HasRyuJit":true, + "Configuration":"RELEASE", + "DotNetCliVersion":"9.0.202", + "ChronometerFrequency":{ + "Hertz":1000000000 + }, + "HardwareTimerKind":"Unknown" + }, + "Benchmarks":[ + { + "DisplayInfo":"LevenshteinBenchmark.ShortIdenticalStrings: DefaultJob", + "Namespace":null, + "Type":"LevenshteinBenchmark", + "Method":"ShortIdenticalStrings", + "MethodTitle":"ShortIdenticalStrings", + "Parameters":"", + "FullName":"LevenshteinBenchmark.ShortIdenticalStrings", + "HardwareIntrinsics":"AVX-512F+CD+BW+DQ+VL+VBMI,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256", + "Statistics":{ + "OriginalValues":[ + 1.3122192546725273,1.3119930550456047,1.3118473999202251,1.3121077232062817,1.311529390513897,1.3117906488478184,1.3121429197490215,1.3120162226259708,1.3126698806881905,1.3126554787158966,1.3122191280126572,1.312406037002802,1.3119770847260952 + ], + "N":13, + "Min":1.311529390513897, + "LowerFence":1.311613829806447, + "Q1":1.3119770847260952, + "Median":1.3121077232062817, + "Mean":1.3121210941328452, + "Q3":1.3122192546725273, + "UpperFence":1.3125825095921755, + "Max":1.3126698806881905, + "InterquartileRange":0.00024216994643211365, + "LowerOutliers":[ + 1.311529390513897 + ], + "UpperOutliers":[ + 1.3126554787158966,1.3126698806881905 + ], + "AllOutliers":[ + 1.311529390513897,1.3126554787158966,1.3126698806881905 + ], + "StandardError":9.023380629462272e-05, + "Variance":1.058478173794014e-07, + "StandardDeviation":0.00032534261537554745, + "Skewness":0.1628914997379797, + "Kurtosis":2.1967979721438327, + "ConfidenceInterval":{ + "N":13, + "Mean":1.3121210941328452, + "StandardError":9.023380629462272e-05, + "Level":12, + "Margin":0.0003896107422005775, + "Lower":1.3117314833906446, + "Upper":1.3125107048750457 + }, + "Percentiles":{ + "P0":1.311529390513897, + "P25":1.3119770847260952, + "P50":1.3121077232062817, + "P67":1.312219133079052, + "P80":1.312331324070692, + "P85":1.3124559253454209, + "P90":1.3126055903732778, + "P95":1.312661239504814, + "P100":1.3126698806881905 + } + } + },{ + "DisplayInfo":"LevenshteinBenchmark.ShortDifferentStrings: DefaultJob", + "Namespace":null, + "Type":"LevenshteinBenchmark", + "Method":"ShortDifferentStrings", + "MethodTitle":"ShortDifferentStrings", + "Parameters":"", + "FullName":"LevenshteinBenchmark.ShortDifferentStrings", + "HardwareIntrinsics":"AVX-512F+CD+BW+DQ+VL+VBMI,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256", + "Statistics":{ + "OriginalValues":[ + 103.12229603528976,103.03741377592087,103.10553914308548,103.13338202238083,102.98720997571945,103.09312230348587,103.02143269777298,103.05606418848038,102.9788470864296,102.98888665437698,103.00126200914383,103.10569542646408,103.00963455438614 + ], + "N":13, + "Min":102.9788470864296, + "LowerFence":102.84484630823135, + "Q1":103.00126200914383, + "Median":103.03741377592087, + "Mean":103.0492912209951, + "Q3":103.10553914308548, + "UpperFence":103.26195484399796, + "Max":103.13338202238083, + "InterquartileRange":0.10427713394165039, + "LowerOutliers":[ + + ], + "UpperOutliers":[ + + ], + "AllOutliers":[ + + ], + "StandardError":0.015602239729917667, + "Variance":0.003164588499667677, + "StandardDeviation":0.05625467535829957, + "Skewness":0.18146008118606596, + "Kurtosis":1.255409377124384, + "ConfidenceInterval":{ + "N":13, + "Mean":103.0492912209951, + "StandardError":0.015602239729917667, + "Level":12, + "Margin":0.06736721469242524, + "Lower":102.98192400630268, + "Upper":103.11665843568753 + }, + "Percentiles":{ + "P0":102.9788470864296, + "P25":103.00126200914383, + "P50":103.03741377592087, + "P67":103.09361897706985, + "P80":103.10563291311264, + "P85":103.10901554822922, + "P90":103.11897591352462, + "P95":103.1267304301262, + "P100":103.13338202238083 + } + } + },{ + "DisplayInfo":"LevenshteinBenchmark.ShortSimilarStrings: DefaultJob", + "Namespace":null, + "Type":"LevenshteinBenchmark", + "Method":"ShortSimilarStrings", + "MethodTitle":"ShortSimilarStrings", + "Parameters":"", + "FullName":"LevenshteinBenchmark.ShortSimilarStrings", + "HardwareIntrinsics":"AVX-512F+CD+BW+DQ+VL+VBMI,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256", + "Statistics":{ + "OriginalValues":[ + 194.64095902442932,194.6236617565155,194.58102941513062,194.61565017700195,194.72907066345215,194.61952018737793,194.65580105781555,194.58437180519104,194.53602480888367,194.58503246307373,194.75757479667664,194.68950080871582,194.71601390838623 + ], + "N":13, + "Min":194.53602480888367, + "LowerFence":194.4283299446106, + "Q1":194.58503246307373, + "Median":194.6236617565155, + "Mean":194.64109314405002, + "Q3":194.68950080871582, + "UpperFence":194.84620332717896, + "Max":194.75757479667664, + "InterquartileRange":0.10446834564208984, + "LowerOutliers":[ + + ], + "UpperOutliers":[ + + ], + "AllOutliers":[ + + ], + "StandardError":0.018240643910889157, + "Variance":0.00432537417369015, + "StandardDeviation":0.06576757691819085, + "Skewness":0.2789173120100915, + "Kurtosis":1.7962774382882687, + "ConfidenceInterval":{ + "N":13, + "Mean":194.64109314405002, + "StandardError":0.018240643910889157, + "Level":12, + "Margin":0.07875929326458525, + "Lower":194.56233385078542, + "Upper":194.71985243731461 + }, + "Percentiles":{ + "P0":194.53602480888367, + "P25":194.58503246307373, + "P50":194.6236617565155, + "P67":194.65714904785156, + "P80":194.70540866851806, + "P85":194.7186252593994, + "P90":194.72645931243898, + "P95":194.74047231674194, + "P100":194.75757479667664 + } + } + },{ + "DisplayInfo":"LevenshteinBenchmark.LongIdenticalStrings: DefaultJob", + "Namespace":null, + "Type":"LevenshteinBenchmark", + "Method":"LongIdenticalStrings", + "MethodTitle":"LongIdenticalStrings", + "Parameters":"", + "FullName":"LevenshteinBenchmark.LongIdenticalStrings", + "HardwareIntrinsics":"AVX-512F+CD+BW+DQ+VL+VBMI,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256", + "Statistics":{ + "OriginalValues":[ + 1.3276808485388756,1.3253048248589039,1.3282077759504318,1.3255497366189957,1.3258876204490662,1.325188308954239,1.3264326639473438,1.3242758549749851,1.3243814371526241,1.3257913440465927,1.3265650123357773,1.323415718972683,1.3252713829278946,1.3249648287892342 + ], + "N":14, + "Min":1.323415718972683, + "LowerFence":1.3231071424670517, + "Q1":1.3250206988304853, + "Median":1.3254272807389498, + "Mean":1.3256369541798319, + "Q3":1.3262964030727744, + "UpperFence":1.328209959436208, + "Max":1.3282077759504318, + "InterquartileRange":0.0012757042422890663, + "LowerOutliers":[ + + ], + "UpperOutliers":[ + + ], + "AllOutliers":[ + + ], + "StandardError":0.00034478165264552346, + "Variance":1.6642414320136974e-06, + "StandardDeviation":0.00129005481744525, + "Skewness":0.3630293989221866, + "Kurtosis":2.3936090732433777, + "ConfidenceInterval":{ + "N":14, + "Mean":1.3256369541798319, + "StandardError":0.00034478165264552346, + "Level":12, + "Margin":0.0014552653381542764, + "Lower":1.3241816888416775, + "Upper":1.3270922195179862 + }, + "Percentiles":{ + "P0":1.323415718972683, + "P25":1.3250206988304853, + "P50":1.3254272807389498, + "P67":1.325859700292349, + "P80":1.326485603302717, + "P85":1.3266208041459322, + "P90":1.327346097677946, + "P95":1.3278652731329201, + "P100":1.3282077759504318 + } + } + },{ + "DisplayInfo":"LevenshteinBenchmark.LongDifferentStrings: DefaultJob", + "Namespace":null, + "Type":"LevenshteinBenchmark", + "Method":"LongDifferentStrings", + "MethodTitle":"LongDifferentStrings", + "Parameters":"", + "FullName":"LevenshteinBenchmark.LongDifferentStrings", + "HardwareIntrinsics":"AVX-512F+CD+BW+DQ+VL+VBMI,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256", + "Statistics":{ + "OriginalValues":[ + 4222361.9765625,4226985.3359375,4215263.46875,4228238.4375,4218046.9140625,4227512.296875,4231538.75,4225826.0859375,4223870.234375,4228274.109375,4222810.9140625,4224481.5078125,4219367.5859375,4218697.1953125 + ], + "N":14, + "Min":4215263.46875, + "LowerFence":4209219.6240234375, + "Q1":4220116.18359375, + "Median":4224175.87109375, + "Mean":4223805.34375, + "Q3":4227380.556640625, + "UpperFence":4238277.1162109375, + "Max":4231538.75, + "InterquartileRange":7264.373046875, + "LowerOutliers":[ + + ], + "UpperOutliers":[ + + ], + "AllOutliers":[ + + ], + "StandardError":1246.5526818369437, + "Variance":21754510.240328275, + "StandardDeviation":4664.173049998068, + "Skewness":-0.21706448246449261, + "Kurtosis":1.8363476608564502, + "ConfidenceInterval":{ + "N":14, + "Mean":4223805.34375, + "StandardError":1246.5526818369437, + "Level":12, + "Margin":5261.4891080809175, + "Lower":4218543.854641919, + "Upper":4229066.832858081 + }, + "Percentiles":{ + "P0":4215263.46875, + "P25":4220116.18359375, + "P50":4224175.87109375, + "P67":4226649.1534375, + "P80":4227802.753125, + "P85":4228240.221093751, + "P90":4228263.4078125, + "P95":4229416.733593751, + "P100":4231538.75 + } + } + },{ + "DisplayInfo":"LevenshteinBenchmark.LongPartiallySimilarStrings: DefaultJob", + "Namespace":null, + "Type":"LevenshteinBenchmark", + "Method":"LongPartiallySimilarStrings", + "MethodTitle":"LongPartiallySimilarStrings", + "Parameters":"", + "FullName":"LevenshteinBenchmark.LongPartiallySimilarStrings", + "HardwareIntrinsics":"AVX-512F+CD+BW+DQ+VL+VBMI,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256", + "Statistics":{ + "OriginalValues":[ + 4255596.015625,4240398.6328125,4234403.7109375,4240588.109375,4236701.0234375,4244767.828125,4250534.75,4245292.4453125,4237879.59375,4239885.4296875,4264399.703125,4245124.8046875,4257501.3203125,4263518.7421875,4251461.046875 + ], + "N":15, + "Min":4234403.7109375, + "LowerFence":4220062.28125, + "Q1":4240142.03125, + "Median":4245124.8046875, + "Mean":4247203.54375, + "Q3":4253528.53125, + "UpperFence":4273608.28125, + "Max":4264399.703125, + "InterquartileRange":13386.5, + "LowerOutliers":[ + + ], + "UpperOutliers":[ + + ], + "AllOutliers":[ + + ], + "StandardError":2474.826680123027, + "Variance":91871506.44973145, + "StandardDeviation":9584.962516866273, + "Skewness":0.4642446551361218, + "Kurtosis":1.8049567528998605, + "ConfidenceInterval":{ + "N":15, + "Mean":4247203.54375, + "StandardError":2474.826680123027, + "Level":12, + "Margin":10246.906301938036, + "Lower":4236956.637448062, + "Upper":4257450.450051938 + }, + "Percentiles":{ + "P0":4234403.7109375, + "P25":4240142.03125, + "P50":4245124.8046875, + "P67":4250886.7428125, + "P80":4255977.0765625, + "P85":4257310.78984375, + "P90":4261111.7734375, + "P95":4263783.030468751, + "P100":4264399.703125 + } + } + } + ] +} diff --git a/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report-full.json b/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report-full.json new file mode 100644 index 0000000..0695918 --- /dev/null +++ b/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report-full.json @@ -0,0 +1,3793 @@ +{ + "Title":"LevenshteinBenchmark-20250319-164145", + "HostEnvironmentInfo":{ + "BenchmarkDotNetCaption":"BenchmarkDotNet", + "BenchmarkDotNetVersion":"0.14.0", + "OsVersion":"Ubuntu 24.04.2 LTS (Noble Numbat)", + "ProcessorName":"11th Gen Intel Core i5-1135G7 2.40GHz", + "PhysicalProcessorCount":1, + "PhysicalCoreCount":4, + "LogicalCoreCount":8, + "RuntimeVersion":".NET 9.0.3 (9.0.325.11113)", + "Architecture":"X64", + "HasAttachedDebugger":false, + "HasRyuJit":true, + "Configuration":"RELEASE", + "DotNetCliVersion":"9.0.202", + "ChronometerFrequency":{ + "Hertz":1000000000 + }, + "HardwareTimerKind":"Unknown" + }, + "Benchmarks":[ + { + "DisplayInfo":"LevenshteinBenchmark.ShortIdenticalStrings: DefaultJob", + "Namespace":null, + "Type":"LevenshteinBenchmark", + "Method":"ShortIdenticalStrings", + "MethodTitle":"ShortIdenticalStrings", + "Parameters":"", + "FullName":"LevenshteinBenchmark.ShortIdenticalStrings", + "HardwareIntrinsics":"AVX-512F+CD+BW+DQ+VL+VBMI,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256", + "Statistics":{ + "OriginalValues":[ + 1.3122192546725273,1.3119930550456047,1.3118473999202251,1.3121077232062817,1.311529390513897,1.3117906488478184,1.3121429197490215,1.3120162226259708,1.3126698806881905,1.3126554787158966,1.3122191280126572,1.312406037002802,1.3119770847260952 + ], + "N":13, + "Min":1.311529390513897, + "LowerFence":1.311613829806447, + "Q1":1.3119770847260952, + "Median":1.3121077232062817, + "Mean":1.3121210941328452, + "Q3":1.3122192546725273, + "UpperFence":1.3125825095921755, + "Max":1.3126698806881905, + "InterquartileRange":0.00024216994643211365, + "LowerOutliers":[ + 1.311529390513897 + ], + "UpperOutliers":[ + 1.3126554787158966,1.3126698806881905 + ], + "AllOutliers":[ + 1.311529390513897,1.3126554787158966,1.3126698806881905 + ], + "StandardError":9.023380629462272e-05, + "Variance":1.058478173794014e-07, + "StandardDeviation":0.00032534261537554745, + "Skewness":0.1628914997379797, + "Kurtosis":2.1967979721438327, + "ConfidenceInterval":{ + "N":13, + "Mean":1.3121210941328452, + "StandardError":9.023380629462272e-05, + "Level":12, + "Margin":0.0003896107422005775, + "Lower":1.3117314833906446, + "Upper":1.3125107048750457 + }, + "Percentiles":{ + "P0":1.311529390513897, + "P25":1.3119770847260952, + "P50":1.3121077232062817, + "P67":1.312219133079052, + "P80":1.312331324070692, + "P85":1.3124559253454209, + "P90":1.3126055903732778, + "P95":1.312661239504814, + "P100":1.3126698806881905 + } + }, + "Measurements":[ + { + "IterationMode":"Overhead", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":1, + "Nanoseconds":231366 + },{ + "IterationMode":"Workload", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":1, + "Nanoseconds":605246 + },{ + "IterationMode":"Overhead", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":16, + "Nanoseconds":212130 + },{ + "IterationMode":"Workload", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":16, + "Nanoseconds":233594 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":16, + "Nanoseconds":2219 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":32, + "Nanoseconds":1214 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":64, + "Nanoseconds":1511 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":1669 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":256, + "Nanoseconds":2918 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":512, + "Nanoseconds":5536 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":1024, + "Nanoseconds":10631 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":2048, + "Nanoseconds":20851 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":4096, + "Nanoseconds":41555 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":8192, + "Nanoseconds":123213 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":16384, + "Nanoseconds":192149 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":32768, + "Nanoseconds":315457 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":65536, + "Nanoseconds":554153 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":131072, + "Nanoseconds":1128017 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":262144, + "Nanoseconds":2289105 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":16, + "Operations":524288, + "Nanoseconds":5115009 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":17, + "Operations":1048576, + "Nanoseconds":8581997 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":18, + "Operations":2097152, + "Nanoseconds":16700990 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":19, + "Operations":4194304, + "Nanoseconds":32641427 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":20, + "Operations":8388608, + "Nanoseconds":65176098 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":21, + "Operations":16777216, + "Nanoseconds":58014592 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":22, + "Operations":33554432, + "Nanoseconds":110103324 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":23, + "Operations":67108864, + "Nanoseconds":216563928 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":24, + "Operations":134217728, + "Nanoseconds":425359384 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":25, + "Operations":268435456, + "Nanoseconds":877479548 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":268435456, + "Nanoseconds":582542802 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":268435456, + "Nanoseconds":525273399 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":268435456, + "Nanoseconds":525151942 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":268435456, + "Nanoseconds":525750216 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":268435456, + "Nanoseconds":525357628 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":268435456, + "Nanoseconds":525079546 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":268435456, + "Nanoseconds":525232354 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":268435456, + "Nanoseconds":525249632 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":268435456, + "Nanoseconds":525467943 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":268435456, + "Nanoseconds":524974412 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":268435456, + "Nanoseconds":524698576 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":268435456, + "Nanoseconds":524683700 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":268435456, + "Nanoseconds":524664479 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":268435456, + "Nanoseconds":524680676 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":268435456, + "Nanoseconds":524654729 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":268435456, + "Nanoseconds":524643681 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":268435456, + "Nanoseconds":525060500 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":268435456, + "Nanoseconds":526348007 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":268435456, + "Nanoseconds":524683215 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":268435456, + "Nanoseconds":524720879 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":268435456, + "Nanoseconds":526639628 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":268435456, + "Nanoseconds":524701946 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":268435456, + "Nanoseconds":525211485 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":268435456, + "Nanoseconds":524805224 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":268435456, + "Nanoseconds":524962864 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":268435456, + "Nanoseconds":877069311 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":268435456, + "Nanoseconds":877029566 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":268435456, + "Nanoseconds":876981362 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":268435456, + "Nanoseconds":877216888 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":268435456, + "Nanoseconds":876749045 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":268435456, + "Nanoseconds":876964550 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":268435456, + "Nanoseconds":876937887 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":268435456, + "Nanoseconds":876948120 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":268435456, + "Nanoseconds":877972021 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":268435456, + "Nanoseconds":877546468 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":268435456, + "Nanoseconds":876887400 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":268435456, + "Nanoseconds":876848301 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":268435456, + "Nanoseconds":876918181 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":268435456, + "Nanoseconds":876762936 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":268435456, + "Nanoseconds":876833067 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":268435456, + "Nanoseconds":876927629 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":268435456, + "Nanoseconds":876893619 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":268435456, + "Nanoseconds":877069084 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":268435456, + "Nanoseconds":877065218 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":268435456, + "Nanoseconds":876948086 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":268435456, + "Nanoseconds":876998259 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":268435456, + "Nanoseconds":876883113 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":268435456, + "Nanoseconds":352246174 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":268435456, + "Nanoseconds":352185454 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":268435456, + "Nanoseconds":352146355 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":268435456, + "Nanoseconds":352216235 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":268435456, + "Nanoseconds":352060990 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":268435456, + "Nanoseconds":352131121 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":268435456, + "Nanoseconds":352225683 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":268435456, + "Nanoseconds":352191673 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":268435456, + "Nanoseconds":352367138 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":268435456, + "Nanoseconds":352363272 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":268435456, + "Nanoseconds":352246140 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":268435456, + "Nanoseconds":352296313 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":268435456, + "Nanoseconds":352181167 + } + ] + },{ + "DisplayInfo":"LevenshteinBenchmark.ShortDifferentStrings: DefaultJob", + "Namespace":null, + "Type":"LevenshteinBenchmark", + "Method":"ShortDifferentStrings", + "MethodTitle":"ShortDifferentStrings", + "Parameters":"", + "FullName":"LevenshteinBenchmark.ShortDifferentStrings", + "HardwareIntrinsics":"AVX-512F+CD+BW+DQ+VL+VBMI,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256", + "Statistics":{ + "OriginalValues":[ + 103.12229603528976,103.03741377592087,103.10553914308548,103.13338202238083,102.98720997571945,103.09312230348587,103.02143269777298,103.05606418848038,102.9788470864296,102.98888665437698,103.00126200914383,103.10569542646408,103.00963455438614 + ], + "N":13, + "Min":102.9788470864296, + "LowerFence":102.84484630823135, + "Q1":103.00126200914383, + "Median":103.03741377592087, + "Mean":103.0492912209951, + "Q3":103.10553914308548, + "UpperFence":103.26195484399796, + "Max":103.13338202238083, + "InterquartileRange":0.10427713394165039, + "LowerOutliers":[ + + ], + "UpperOutliers":[ + + ], + "AllOutliers":[ + + ], + "StandardError":0.015602239729917667, + "Variance":0.003164588499667677, + "StandardDeviation":0.05625467535829957, + "Skewness":0.18146008118606596, + "Kurtosis":1.255409377124384, + "ConfidenceInterval":{ + "N":13, + "Mean":103.0492912209951, + "StandardError":0.015602239729917667, + "Level":12, + "Margin":0.06736721469242524, + "Lower":102.98192400630268, + "Upper":103.11665843568753 + }, + "Percentiles":{ + "P0":102.9788470864296, + "P25":103.00126200914383, + "P50":103.03741377592087, + "P67":103.09361897706985, + "P80":103.10563291311264, + "P85":103.10901554822922, + "P90":103.11897591352462, + "P95":103.1267304301262, + "P100":103.13338202238083 + } + }, + "Measurements":[ + { + "IterationMode":"Overhead", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":1, + "Nanoseconds":286546 + },{ + "IterationMode":"Workload", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":1, + "Nanoseconds":1120424 + },{ + "IterationMode":"Overhead", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":16, + "Nanoseconds":289516 + },{ + "IterationMode":"Workload", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":16, + "Nanoseconds":297797 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":16, + "Nanoseconds":10714 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":32, + "Nanoseconds":20280 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":64, + "Nanoseconds":29981 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":57667 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":256, + "Nanoseconds":115397 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":512, + "Nanoseconds":291202 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":1024, + "Nanoseconds":599550 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":2048, + "Nanoseconds":1198382 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":4096, + "Nanoseconds":2709817 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":8192, + "Nanoseconds":4767577 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":16384, + "Nanoseconds":7832208 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":32768, + "Nanoseconds":17522629 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":65536, + "Nanoseconds":29913905 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":131072, + "Nanoseconds":51847795 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":262144, + "Nanoseconds":105100302 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":16, + "Operations":524288, + "Nanoseconds":58789422 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":17, + "Operations":1048576, + "Nanoseconds":111597609 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":18, + "Operations":2097152, + "Nanoseconds":205563628 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":19, + "Operations":4194304, + "Nanoseconds":441783753 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":20, + "Operations":8388608, + "Nanoseconds":884480549 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":8388608, + "Nanoseconds":23140968 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":8388608, + "Nanoseconds":23147409 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":8388608, + "Nanoseconds":23298544 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":8388608, + "Nanoseconds":23112521 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":8388608, + "Nanoseconds":23136075 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":8388608, + "Nanoseconds":23113704 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":8388608, + "Nanoseconds":23217332 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":8388608, + "Nanoseconds":23169019 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":8388608, + "Nanoseconds":23228584 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":8388608, + "Nanoseconds":23198171 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":8388608, + "Nanoseconds":23131770 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":8388608, + "Nanoseconds":23279002 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":8388608, + "Nanoseconds":23158288 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":8388608, + "Nanoseconds":23180703 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":8388608, + "Nanoseconds":23182520 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":8388608, + "Nanoseconds":23136060 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":8388608, + "Nanoseconds":18139771 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":8388608, + "Nanoseconds":16478490 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":8388608, + "Nanoseconds":16485672 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":8388608, + "Nanoseconds":16570286 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":8388608, + "Nanoseconds":16478383 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":16, + "Operations":8388608, + "Nanoseconds":16605033 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":17, + "Operations":8388608, + "Nanoseconds":16670831 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":18, + "Operations":8388608, + "Nanoseconds":16539405 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":19, + "Operations":8388608, + "Nanoseconds":16483156 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":20, + "Operations":8388608, + "Nanoseconds":16456125 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":8388608, + "Nanoseconds":887670600 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":8388608, + "Nanoseconds":886177542 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":8388608, + "Nanoseconds":885724775 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":8388608, + "Nanoseconds":886029919 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":8388608, + "Nanoseconds":884684983 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":8388608, + "Nanoseconds":885076518 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":8388608, + "Nanoseconds":884643188 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":8388608, + "Nanoseconds":890554077 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":8388608, + "Nanoseconds":885688288 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":8388608, + "Nanoseconds":884976244 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":8388608, + "Nanoseconds":885547721 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":8388608, + "Nanoseconds":885781284 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":8388608, + "Nanoseconds":884555104 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":8388608, + "Nanoseconds":885443561 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":8388608, + "Nanoseconds":888767700 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":8388608, + "Nanoseconds":884842185 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":8388608, + "Nanoseconds":885132695 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":8388608, + "Nanoseconds":884484951 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":8388608, + "Nanoseconds":884569169 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":8388608, + "Nanoseconds":884672981 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":8388608, + "Nanoseconds":885549032 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":8388608, + "Nanoseconds":884743215 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":8388608, + "Nanoseconds":865052517.5 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":8388608, + "Nanoseconds":864340473.5 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":8388608, + "Nanoseconds":864911950.5 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":8388608, + "Nanoseconds":865145513.5 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":8388608, + "Nanoseconds":863919333.5 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":8388608, + "Nanoseconds":864807790.5 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":8388608, + "Nanoseconds":864206414.5 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":8388608, + "Nanoseconds":864496924.5 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":8388608, + "Nanoseconds":863849180.5 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":8388608, + "Nanoseconds":863933398.5 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":8388608, + "Nanoseconds":864037210.5 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":8388608, + "Nanoseconds":864913261.5 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":8388608, + "Nanoseconds":864107444.5 + } + ] + },{ + "DisplayInfo":"LevenshteinBenchmark.ShortSimilarStrings: DefaultJob", + "Namespace":null, + "Type":"LevenshteinBenchmark", + "Method":"ShortSimilarStrings", + "MethodTitle":"ShortSimilarStrings", + "Parameters":"", + "FullName":"LevenshteinBenchmark.ShortSimilarStrings", + "HardwareIntrinsics":"AVX-512F+CD+BW+DQ+VL+VBMI,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256", + "Statistics":{ + "OriginalValues":[ + 194.64095902442932,194.6236617565155,194.58102941513062,194.61565017700195,194.72907066345215,194.61952018737793,194.65580105781555,194.58437180519104,194.53602480888367,194.58503246307373,194.75757479667664,194.68950080871582,194.71601390838623 + ], + "N":13, + "Min":194.53602480888367, + "LowerFence":194.4283299446106, + "Q1":194.58503246307373, + "Median":194.6236617565155, + "Mean":194.64109314405002, + "Q3":194.68950080871582, + "UpperFence":194.84620332717896, + "Max":194.75757479667664, + "InterquartileRange":0.10446834564208984, + "LowerOutliers":[ + + ], + "UpperOutliers":[ + + ], + "AllOutliers":[ + + ], + "StandardError":0.018240643910889157, + "Variance":0.00432537417369015, + "StandardDeviation":0.06576757691819085, + "Skewness":0.2789173120100915, + "Kurtosis":1.7962774382882687, + "ConfidenceInterval":{ + "N":13, + "Mean":194.64109314405002, + "StandardError":0.018240643910889157, + "Level":12, + "Margin":0.07875929326458525, + "Lower":194.56233385078542, + "Upper":194.71985243731461 + }, + "Percentiles":{ + "P0":194.53602480888367, + "P25":194.58503246307373, + "P50":194.6236617565155, + "P67":194.65714904785156, + "P80":194.70540866851806, + "P85":194.7186252593994, + "P90":194.72645931243898, + "P95":194.74047231674194, + "P100":194.75757479667664 + } + }, + "Measurements":[ + { + "IterationMode":"Overhead", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":1, + "Nanoseconds":293580 + },{ + "IterationMode":"Workload", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":1, + "Nanoseconds":996902 + },{ + "IterationMode":"Overhead", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":16, + "Nanoseconds":261299 + },{ + "IterationMode":"Workload", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":16, + "Nanoseconds":264140 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":16, + "Nanoseconds":17128 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":32, + "Nanoseconds":40787 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":64, + "Nanoseconds":61954 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":135979 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":256, + "Nanoseconds":305798 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":512, + "Nanoseconds":585936 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":1024, + "Nanoseconds":1440125 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":2048, + "Nanoseconds":2329666 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":4096, + "Nanoseconds":4252190 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":8192, + "Nanoseconds":9518480 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":16384, + "Nanoseconds":17710273 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":32768, + "Nanoseconds":31094286 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":65536, + "Nanoseconds":56170847 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":131072, + "Nanoseconds":31600443 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":262144, + "Nanoseconds":57953068 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":16, + "Operations":524288, + "Nanoseconds":107944574 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":17, + "Operations":1048576, + "Nanoseconds":202762794 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":18, + "Operations":2097152, + "Nanoseconds":412897941 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":19, + "Operations":4194304, + "Nanoseconds":830884425 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":4194304, + "Nanoseconds":11576090 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":4194304, + "Nanoseconds":11668592 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":4194304, + "Nanoseconds":11670982 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":4194304, + "Nanoseconds":11638529 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":4194304, + "Nanoseconds":11616208 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":4194304, + "Nanoseconds":11924169 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":4194304, + "Nanoseconds":11771006 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":4194304, + "Nanoseconds":11668448 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":4194304, + "Nanoseconds":11660319 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":4194304, + "Nanoseconds":11674048 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":4194304, + "Nanoseconds":11708770 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":4194304, + "Nanoseconds":11639713 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":4194304, + "Nanoseconds":11581211 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":4194304, + "Nanoseconds":11645479 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":4194304, + "Nanoseconds":11693940 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":4194304, + "Nanoseconds":11659328 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":4194304, + "Nanoseconds":11612893 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":4194304, + "Nanoseconds":11618932 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":4194304, + "Nanoseconds":11715091 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":4194304, + "Nanoseconds":11613702 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":4194304, + "Nanoseconds":11634804 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":4194304, + "Nanoseconds":11627229 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":4194304, + "Nanoseconds":840231127 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":4194304, + "Nanoseconds":830956611 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":4194304, + "Nanoseconds":829753521 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":4194304, + "Nanoseconds":828975804 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":4194304, + "Nanoseconds":829993065 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":4194304, + "Nanoseconds":829482241 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":4194304, + "Nanoseconds":830185133 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":4194304, + "Nanoseconds":829295833 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":4194304, + "Nanoseconds":831169819 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":4194304, + "Nanoseconds":828028832 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":4194304, + "Nanoseconds":827956282 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":4194304, + "Nanoseconds":827777469 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":4194304, + "Nanoseconds":827922679 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":4194304, + "Nanoseconds":828398399 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":4194304, + "Nanoseconds":827938911 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":4194304, + "Nanoseconds":828091084 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":4194304, + "Nanoseconds":856837541 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":4194304, + "Nanoseconds":827791488 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":4194304, + "Nanoseconds":827588706 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":4194304, + "Nanoseconds":827794259 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":4194304, + "Nanoseconds":828517954 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":4194304, + "Nanoseconds":828232431 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":4194304, + "Nanoseconds":828343635 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":4194304, + "Nanoseconds":816383353 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":4194304, + "Nanoseconds":816310803 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":4194304, + "Nanoseconds":816131990 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":4194304, + "Nanoseconds":816277200 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":4194304, + "Nanoseconds":816752920 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":4194304, + "Nanoseconds":816293432 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":4194304, + "Nanoseconds":816445605 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":4194304, + "Nanoseconds":816146009 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":4194304, + "Nanoseconds":815943227 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":4194304, + "Nanoseconds":816148780 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":4194304, + "Nanoseconds":816872475 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":4194304, + "Nanoseconds":816586952 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":4194304, + "Nanoseconds":816698156 + } + ] + },{ + "DisplayInfo":"LevenshteinBenchmark.LongIdenticalStrings: DefaultJob", + "Namespace":null, + "Type":"LevenshteinBenchmark", + "Method":"LongIdenticalStrings", + "MethodTitle":"LongIdenticalStrings", + "Parameters":"", + "FullName":"LevenshteinBenchmark.LongIdenticalStrings", + "HardwareIntrinsics":"AVX-512F+CD+BW+DQ+VL+VBMI,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256", + "Statistics":{ + "OriginalValues":[ + 1.3276808485388756,1.3253048248589039,1.3282077759504318,1.3255497366189957,1.3258876204490662,1.325188308954239,1.3264326639473438,1.3242758549749851,1.3243814371526241,1.3257913440465927,1.3265650123357773,1.323415718972683,1.3252713829278946,1.3249648287892342 + ], + "N":14, + "Min":1.323415718972683, + "LowerFence":1.3231071424670517, + "Q1":1.3250206988304853, + "Median":1.3254272807389498, + "Mean":1.3256369541798319, + "Q3":1.3262964030727744, + "UpperFence":1.328209959436208, + "Max":1.3282077759504318, + "InterquartileRange":0.0012757042422890663, + "LowerOutliers":[ + + ], + "UpperOutliers":[ + + ], + "AllOutliers":[ + + ], + "StandardError":0.00034478165264552346, + "Variance":1.6642414320136974e-06, + "StandardDeviation":0.00129005481744525, + "Skewness":0.3630293989221866, + "Kurtosis":2.3936090732433777, + "ConfidenceInterval":{ + "N":14, + "Mean":1.3256369541798319, + "StandardError":0.00034478165264552346, + "Level":12, + "Margin":0.0014552653381542764, + "Lower":1.3241816888416775, + "Upper":1.3270922195179862 + }, + "Percentiles":{ + "P0":1.323415718972683, + "P25":1.3250206988304853, + "P50":1.3254272807389498, + "P67":1.325859700292349, + "P80":1.326485603302717, + "P85":1.3266208041459322, + "P90":1.327346097677946, + "P95":1.3278652731329201, + "P100":1.3282077759504318 + } + }, + "Measurements":[ + { + "IterationMode":"Overhead", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":1, + "Nanoseconds":293921 + },{ + "IterationMode":"Workload", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":1, + "Nanoseconds":847386 + },{ + "IterationMode":"Overhead", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":16, + "Nanoseconds":310374 + },{ + "IterationMode":"Workload", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":16, + "Nanoseconds":238348 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":16, + "Nanoseconds":2340 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":32, + "Nanoseconds":1332 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":64, + "Nanoseconds":1256 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":1773 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":256, + "Nanoseconds":3023 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":512, + "Nanoseconds":5666 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":1024, + "Nanoseconds":27805 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":2048, + "Nanoseconds":27133 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":4096, + "Nanoseconds":43755 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":8192, + "Nanoseconds":137757 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":16384, + "Nanoseconds":224912 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":32768, + "Nanoseconds":376061 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":65536, + "Nanoseconds":795804 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":131072, + "Nanoseconds":1415016 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":262144, + "Nanoseconds":2973944 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":16, + "Operations":524288, + "Nanoseconds":5273179 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":17, + "Operations":1048576, + "Nanoseconds":10995421 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":18, + "Operations":2097152, + "Nanoseconds":21427057 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":19, + "Operations":4194304, + "Nanoseconds":42798821 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":20, + "Operations":8388608, + "Nanoseconds":55544016 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":21, + "Operations":16777216, + "Nanoseconds":55256940 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":22, + "Operations":33554432, + "Nanoseconds":107097787 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":23, + "Operations":67108864, + "Nanoseconds":209768558 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":24, + "Operations":134217728, + "Nanoseconds":436432964 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":25, + "Operations":268435456, + "Nanoseconds":882015311 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":268435456, + "Nanoseconds":583907508 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":268435456, + "Nanoseconds":525571694 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":268435456, + "Nanoseconds":525136905 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":268435456, + "Nanoseconds":526211570 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":268435456, + "Nanoseconds":525453350 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":268435456, + "Nanoseconds":525710257 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":268435456, + "Nanoseconds":525831548 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":268435456, + "Nanoseconds":525857312 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":268435456, + "Nanoseconds":525792263 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":268435456, + "Nanoseconds":524877215 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":268435456, + "Nanoseconds":531193807 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":268435456, + "Nanoseconds":528624178 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":268435456, + "Nanoseconds":526033062 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":268435456, + "Nanoseconds":525262417 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":268435456, + "Nanoseconds":526483371 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":268435456, + "Nanoseconds":525275755 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":268435456, + "Nanoseconds":525330879 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":268435456, + "Nanoseconds":524013477 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":268435456, + "Nanoseconds":526420526 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":268435456, + "Nanoseconds":525981998 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":268435456, + "Nanoseconds":527226503 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":268435456, + "Nanoseconds":525742770 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":268435456, + "Nanoseconds":526081821 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":268435456, + "Nanoseconds":526223622 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":268435456, + "Nanoseconds":882090936 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":268435456, + "Nanoseconds":881631930 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":268435456, + "Nanoseconds":881680285 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":268435456, + "Nanoseconds":882251073 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":268435456, + "Nanoseconds":882034857 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":268435456, + "Nanoseconds":882120112 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":268435456, + "Nanoseconds":881639631 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":268435456, + "Nanoseconds":882429676 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":268435456, + "Nanoseconds":881791867 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":268435456, + "Nanoseconds":882571122 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":268435456, + "Nanoseconds":881857610 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":268435456, + "Nanoseconds":881948310 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":268435456, + "Nanoseconds":881760590 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":268435456, + "Nanoseconds":882094619 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":268435456, + "Nanoseconds":881515655 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":268435456, + "Nanoseconds":881543997 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":268435456, + "Nanoseconds":881922466 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":268435456, + "Nanoseconds":882130146 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":268435456, + "Nanoseconds":881284764 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":268435456, + "Nanoseconds":883154097 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":268435456, + "Nanoseconds":881782890 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":268435456, + "Nanoseconds":881700600 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":268435456, + "Nanoseconds":356396614 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":268435456, + "Nanoseconds":355758805 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":268435456, + "Nanoseconds":356538060 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":268435456, + "Nanoseconds":355824548 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":268435456, + "Nanoseconds":355915248 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":268435456, + "Nanoseconds":355727528 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":268435456, + "Nanoseconds":356061557 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":268435456, + "Nanoseconds":355482593 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":268435456, + "Nanoseconds":355510935 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":268435456, + "Nanoseconds":355889404 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":268435456, + "Nanoseconds":356097084 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":268435456, + "Nanoseconds":355251702 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":268435456, + "Nanoseconds":355749828 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":268435456, + "Nanoseconds":355667538 + } + ] + },{ + "DisplayInfo":"LevenshteinBenchmark.LongDifferentStrings: DefaultJob", + "Namespace":null, + "Type":"LevenshteinBenchmark", + "Method":"LongDifferentStrings", + "MethodTitle":"LongDifferentStrings", + "Parameters":"", + "FullName":"LevenshteinBenchmark.LongDifferentStrings", + "HardwareIntrinsics":"AVX-512F+CD+BW+DQ+VL+VBMI,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256", + "Statistics":{ + "OriginalValues":[ + 4222361.9765625,4226985.3359375,4215263.46875,4228238.4375,4218046.9140625,4227512.296875,4231538.75,4225826.0859375,4223870.234375,4228274.109375,4222810.9140625,4224481.5078125,4219367.5859375,4218697.1953125 + ], + "N":14, + "Min":4215263.46875, + "LowerFence":4209219.6240234375, + "Q1":4220116.18359375, + "Median":4224175.87109375, + "Mean":4223805.34375, + "Q3":4227380.556640625, + "UpperFence":4238277.1162109375, + "Max":4231538.75, + "InterquartileRange":7264.373046875, + "LowerOutliers":[ + + ], + "UpperOutliers":[ + + ], + "AllOutliers":[ + + ], + "StandardError":1246.5526818369437, + "Variance":21754510.240328275, + "StandardDeviation":4664.173049998068, + "Skewness":-0.21706448246449261, + "Kurtosis":1.8363476608564502, + "ConfidenceInterval":{ + "N":14, + "Mean":4223805.34375, + "StandardError":1246.5526818369437, + "Level":12, + "Margin":5261.4891080809175, + "Lower":4218543.854641919, + "Upper":4229066.832858081 + }, + "Percentiles":{ + "P0":4215263.46875, + "P25":4220116.18359375, + "P50":4224175.87109375, + "P67":4226649.1534375, + "P80":4227802.753125, + "P85":4228240.221093751, + "P90":4228263.4078125, + "P95":4229416.733593751, + "P100":4231538.75 + } + }, + "Measurements":[ + { + "IterationMode":"Overhead", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":1, + "Nanoseconds":282653 + },{ + "IterationMode":"Workload", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":1, + "Nanoseconds":6747361 + },{ + "IterationMode":"Overhead", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":16, + "Nanoseconds":283588 + },{ + "IterationMode":"Workload", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":16, + "Nanoseconds":78566422 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":16, + "Nanoseconds":76678271 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":32, + "Nanoseconds":142792759 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":64, + "Nanoseconds":276481084 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":538278741 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":128, + "Nanoseconds":1888 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":128, + "Nanoseconds":789 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":128, + "Nanoseconds":684 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":626 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":128, + "Nanoseconds":766 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":128, + "Nanoseconds":738 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":128, + "Nanoseconds":702 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":128, + "Nanoseconds":634 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":128, + "Nanoseconds":653 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":128, + "Nanoseconds":677 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":128, + "Nanoseconds":767 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":128, + "Nanoseconds":765 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":128, + "Nanoseconds":755 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":722 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":128, + "Nanoseconds":816 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":128, + "Nanoseconds":786 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":128, + "Nanoseconds":816 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":128, + "Nanoseconds":769 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":128, + "Nanoseconds":793 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":128, + "Nanoseconds":761 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":128, + "Nanoseconds":739 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":128, + "Nanoseconds":746 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":128, + "Nanoseconds":832 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":128, + "Nanoseconds":795 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":128, + "Nanoseconds":763 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":128, + "Nanoseconds":553453071 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":128, + "Nanoseconds":541427105 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":128, + "Nanoseconds":541311362 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":545089219 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":128, + "Nanoseconds":759968700 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":128, + "Nanoseconds":807498698 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":128, + "Nanoseconds":539450217 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":128, + "Nanoseconds":540648078 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":128, + "Nanoseconds":539803713 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":128, + "Nanoseconds":540463100 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":128, + "Nanoseconds":541054890 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":128, + "Nanoseconds":539554491 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":541215287 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":128, + "Nanoseconds":539910772 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":128, + "Nanoseconds":541122341 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":128, + "Nanoseconds":545325501 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":128, + "Nanoseconds":541637727 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":128, + "Nanoseconds":540906506 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":128, + "Nanoseconds":540656157 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":128, + "Nanoseconds":541219853 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":128, + "Nanoseconds":540520564 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":128, + "Nanoseconds":540734400 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":128, + "Nanoseconds":540079818 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":128, + "Nanoseconds":539994008 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":128, + "Nanoseconds":540462333 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":128, + "Nanoseconds":541054123 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":128, + "Nanoseconds":539553724 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":541214520 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":128, + "Nanoseconds":539910005 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":128, + "Nanoseconds":541121574 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":128, + "Nanoseconds":541636960 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":128, + "Nanoseconds":540905739 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":128, + "Nanoseconds":540655390 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":128, + "Nanoseconds":541219086 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":128, + "Nanoseconds":540519797 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":128, + "Nanoseconds":540733633 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":128, + "Nanoseconds":540079051 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":128, + "Nanoseconds":539993241 + } + ] + },{ + "DisplayInfo":"LevenshteinBenchmark.LongPartiallySimilarStrings: DefaultJob", + "Namespace":null, + "Type":"LevenshteinBenchmark", + "Method":"LongPartiallySimilarStrings", + "MethodTitle":"LongPartiallySimilarStrings", + "Parameters":"", + "FullName":"LevenshteinBenchmark.LongPartiallySimilarStrings", + "HardwareIntrinsics":"AVX-512F+CD+BW+DQ+VL+VBMI,AES,BMI1,BMI2,FMA,LZCNT,PCLMUL,POPCNT VectorSize=256", + "Statistics":{ + "OriginalValues":[ + 4255596.015625,4240398.6328125,4234403.7109375,4240588.109375,4236701.0234375,4244767.828125,4250534.75,4245292.4453125,4237879.59375,4239885.4296875,4264399.703125,4245124.8046875,4257501.3203125,4263518.7421875,4251461.046875 + ], + "N":15, + "Min":4234403.7109375, + "LowerFence":4220062.28125, + "Q1":4240142.03125, + "Median":4245124.8046875, + "Mean":4247203.54375, + "Q3":4253528.53125, + "UpperFence":4273608.28125, + "Max":4264399.703125, + "InterquartileRange":13386.5, + "LowerOutliers":[ + + ], + "UpperOutliers":[ + + ], + "AllOutliers":[ + + ], + "StandardError":2474.826680123027, + "Variance":91871506.44973145, + "StandardDeviation":9584.962516866273, + "Skewness":0.4642446551361218, + "Kurtosis":1.8049567528998605, + "ConfidenceInterval":{ + "N":15, + "Mean":4247203.54375, + "StandardError":2474.826680123027, + "Level":12, + "Margin":10246.906301938036, + "Lower":4236956.637448062, + "Upper":4257450.450051938 + }, + "Percentiles":{ + "P0":4234403.7109375, + "P25":4240142.03125, + "P50":4245124.8046875, + "P67":4250886.7428125, + "P80":4255977.0765625, + "P85":4257310.78984375, + "P90":4261111.7734375, + "P95":4263783.030468751, + "P100":4264399.703125 + } + }, + "Measurements":[ + { + "IterationMode":"Overhead", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":1, + "Nanoseconds":298960 + },{ + "IterationMode":"Workload", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":1, + "Nanoseconds":6913302 + },{ + "IterationMode":"Overhead", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":16, + "Nanoseconds":1299713 + },{ + "IterationMode":"Workload", + "IterationStage":"Jitting", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":16, + "Nanoseconds":87113942 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":16, + "Nanoseconds":77487634 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":32, + "Nanoseconds":146469841 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":64, + "Nanoseconds":279080818 + },{ + "IterationMode":"Workload", + "IterationStage":"Pilot", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":539775902 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":128, + "Nanoseconds":1734 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":128, + "Nanoseconds":885 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":128, + "Nanoseconds":701 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":656 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":128, + "Nanoseconds":717 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":128, + "Nanoseconds":687 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":128, + "Nanoseconds":718 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":128, + "Nanoseconds":804 + },{ + "IterationMode":"Overhead", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":128, + "Nanoseconds":736 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":128, + "Nanoseconds":1301 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":128, + "Nanoseconds":1152 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":128, + "Nanoseconds":1021 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":732 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":128, + "Nanoseconds":771 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":128, + "Nanoseconds":716 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":128, + "Nanoseconds":713 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":128, + "Nanoseconds":683 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":128, + "Nanoseconds":704 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":128, + "Nanoseconds":717 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":128, + "Nanoseconds":730 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":128, + "Nanoseconds":738 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":128, + "Nanoseconds":734 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":128, + "Nanoseconds":729 + },{ + "IterationMode":"Overhead", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":128, + "Nanoseconds":731 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":128, + "Nanoseconds":558754396 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":128, + "Nanoseconds":543510555 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":128, + "Nanoseconds":543341586 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":542562199 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":128, + "Nanoseconds":543751100 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":128, + "Nanoseconds":542642678 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":128, + "Nanoseconds":563632682 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":128, + "Nanoseconds":565767528 + },{ + "IterationMode":"Workload", + "IterationStage":"Warmup", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":128, + "Nanoseconds":543020357 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":128, + "Nanoseconds":544717021 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":128, + "Nanoseconds":542771756 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":128, + "Nanoseconds":542004406 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":542796009 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":128, + "Nanoseconds":542298462 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":128, + "Nanoseconds":543331013 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":128, + "Nanoseconds":544069179 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":128, + "Nanoseconds":543398164 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":128, + "Nanoseconds":542449319 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":128, + "Nanoseconds":542706066 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":128, + "Nanoseconds":545843893 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":128, + "Nanoseconds":543376706 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":128, + "Nanoseconds":544960900 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":128, + "Nanoseconds":545731130 + },{ + "IterationMode":"Workload", + "IterationStage":"Actual", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":128, + "Nanoseconds":544187745 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":1, + "Operations":128, + "Nanoseconds":544716290 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":2, + "Operations":128, + "Nanoseconds":542771025 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":3, + "Operations":128, + "Nanoseconds":542003675 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":4, + "Operations":128, + "Nanoseconds":542795278 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":5, + "Operations":128, + "Nanoseconds":542297731 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":6, + "Operations":128, + "Nanoseconds":543330282 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":7, + "Operations":128, + "Nanoseconds":544068448 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":8, + "Operations":128, + "Nanoseconds":543397433 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":9, + "Operations":128, + "Nanoseconds":542448588 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":10, + "Operations":128, + "Nanoseconds":542705335 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":11, + "Operations":128, + "Nanoseconds":545843162 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":12, + "Operations":128, + "Nanoseconds":543375975 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":13, + "Operations":128, + "Nanoseconds":544960169 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":14, + "Operations":128, + "Nanoseconds":545730399 + },{ + "IterationMode":"Workload", + "IterationStage":"Result", + "LaunchIndex":1, + "IterationIndex":15, + "Operations":128, + "Nanoseconds":544187014 + } + ] + } + ] +} diff --git a/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report-github.md b/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report-github.md new file mode 100644 index 0000000..be60997 --- /dev/null +++ b/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report-github.md @@ -0,0 +1,18 @@ +``` + +BenchmarkDotNet v0.14.0, Ubuntu 24.04.2 LTS (Noble Numbat) +11th Gen Intel Core i5-1135G7 2.40GHz, 1 CPU, 8 logical and 4 physical cores +.NET SDK 9.0.202 + [Host] : .NET 9.0.3 (9.0.325.11113), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI + DefaultJob : .NET 9.0.3 (9.0.325.11113), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI + + +``` +| Method | Mean | Error | StdDev | +|---------------------------- |-----------------:|---------------:|--------------:| +| ShortIdenticalStrings | 1.312 ns | 0.0004 ns | 0.0003 ns | +| ShortDifferentStrings | 103.049 ns | 0.0674 ns | 0.0563 ns | +| ShortSimilarStrings | 194.641 ns | 0.0788 ns | 0.0658 ns | +| LongIdenticalStrings | 1.326 ns | 0.0015 ns | 0.0013 ns | +| LongDifferentStrings | 4,223,805.344 ns | 5,261.4891 ns | 4,664.1730 ns | +| LongPartiallySimilarStrings | 4,247,203.544 ns | 10,246.9063 ns | 9,584.9625 ns | diff --git a/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report.csv b/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report.csv new file mode 100644 index 0000000..2dcd5f5 --- /dev/null +++ b/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report.csv @@ -0,0 +1,7 @@ +Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,LargeAddressAware,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Mean,Error,StdDev +ShortIdenticalStrings,DefaultJob,False,Default,Default,Default,Default,Default,Default,11111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,1.312 ns,0.0004 ns,0.0003 ns +ShortDifferentStrings,DefaultJob,False,Default,Default,Default,Default,Default,Default,11111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,103.049 ns,0.0674 ns,0.0563 ns +ShortSimilarStrings,DefaultJob,False,Default,Default,Default,Default,Default,Default,11111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,194.641 ns,0.0788 ns,0.0658 ns +LongIdenticalStrings,DefaultJob,False,Default,Default,Default,Default,Default,Default,11111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,1.326 ns,0.0015 ns,0.0013 ns +LongDifferentStrings,DefaultJob,False,Default,Default,Default,Default,Default,Default,11111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"4,223,805.344 ns","5,261.4891 ns","4,664.1730 ns" +LongPartiallySimilarStrings,DefaultJob,False,Default,Default,Default,Default,Default,Default,11111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"4,247,203.544 ns","10,246.9063 ns","9,584.9625 ns" diff --git a/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report.html b/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report.html new file mode 100644 index 0000000..cd69108 --- /dev/null +++ b/C#/LevenshteinRatio.Bench/res/results/LevenshteinBenchmark-report.html @@ -0,0 +1,35 @@ + + + + +LevenshteinBenchmark-20250319-164145 + + + + +

+BenchmarkDotNet v0.14.0, Ubuntu 24.04.2 LTS (Noble Numbat)
+11th Gen Intel Core i5-1135G7 2.40GHz, 1 CPU, 8 logical and 4 physical cores
+.NET SDK 9.0.202
+  [Host]     : .NET 9.0.3 (9.0.325.11113), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
+  DefaultJob : .NET 9.0.3 (9.0.325.11113), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
+
+
+ + + + + + + + + + +
Method Mean Error StdDev
ShortIdenticalStrings1.312 ns0.0004 ns0.0003 ns
ShortDifferentStrings103.049 ns0.0674 ns0.0563 ns
ShortSimilarStrings194.641 ns0.0788 ns0.0658 ns
LongIdenticalStrings1.326 ns0.0015 ns0.0013 ns
LongDifferentStrings4,223,805.344 ns5,261.4891 ns4,664.1730 ns
LongPartiallySimilarStrings4,247,203.544 ns10,246.9063 ns9,584.9625 ns
+ + diff --git a/C#/LevenshteinRatio.Tests/LevenshteinRatio.Tests.csproj b/C#/LevenshteinRatio.Tests/LevenshteinRatio.Tests.csproj new file mode 100644 index 0000000..b441aa7 --- /dev/null +++ b/C#/LevenshteinRatio.Tests/LevenshteinRatio.Tests.csproj @@ -0,0 +1,25 @@ + + + + net9.0 + enable + enable + false + + + + + + + + + + + + + + + + + + diff --git a/C#/LevenshteinRatio.Tests/UnitTest1.cs b/C#/LevenshteinRatio.Tests/UnitTest1.cs new file mode 100644 index 0000000..c00f093 --- /dev/null +++ b/C#/LevenshteinRatio.Tests/UnitTest1.cs @@ -0,0 +1,82 @@ +namespace LevenshteinRatio.Tests; + +using Xunit; +using LevenshteinRatio; + +public class UnitTest1Test +{ + [Fact] + public void Test_LevenshteinRatio_EqualStrings() + { + // Arrange + string str1 = "test"; + string str2 = "test"; + double expectedRatio = 1.0; + + // Act + double actualRatio = Levenshtein.Ratio(str1, str2); + + // Assert + Assert.Equal(expectedRatio, actualRatio); + } + + [Fact] + public void Test_LevenshteinRatio_CompletelyDifferentStrings() + { + // Arrange + string str1 = "test"; + string str2 = "abcd"; + double expectedRatio = 0.0; + + // Act + double actualRatio = Levenshtein.Ratio(str1, str2); + + // Assert + Assert.Equal(expectedRatio, actualRatio); + } + + [Fact] + public void Test_LevenshteinRatio_SimilarStrings() + { + // Arrange + string str1 = "kitten"; + string str2 = "sitting"; + double expectedRatio = 0.5714285714285714; // Example ratio + + // Act + double actualRatio = Levenshtein.Ratio(str1, str2); + + // Assert + Assert.Equal(expectedRatio, actualRatio, 5); + } + + [Fact] + public void Test_LevenshteinRatio_EmptyStrings() + { + // Arrange + string str1 = ""; + string str2 = ""; + double expectedRatio = 1.0; + + // Act + double actualRatio = Levenshtein.Ratio(str1, str2); + + // Assert + Assert.Equal(expectedRatio, actualRatio); + } + + [Fact] + public void Test_LevenshteinRatio_OneEmptyString() + { + // Arrange + string str1 = "test"; + string str2 = ""; + double expectedRatio = 0.0; + + // Act + double actualRatio = Levenshtein.Ratio(str1, str2); + + // Assert + Assert.Equal(expectedRatio, actualRatio); + } +} \ No newline at end of file diff --git a/C#/LevenshteinRatio.sln b/C#/LevenshteinRatio.sln new file mode 100644 index 0000000..83f1116 --- /dev/null +++ b/C#/LevenshteinRatio.sln @@ -0,0 +1,62 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LevenshteinRatio", "LevenshteinRatio\LevenshteinRatio.csproj", "{9F685456-3336-422F-8F4F-1800C80DB10C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Console", "Console\Console.csproj", "{B49DD477-1671-4FA1-87EC-5E0BFA76C3B4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LevenshteinRatio.Tests", "LevenshteinRatio.Tests\LevenshteinRatio.Tests.csproj", "{406046CF-F612-4E57-8DCD-31C4A2B1D455}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9F685456-3336-422F-8F4F-1800C80DB10C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9F685456-3336-422F-8F4F-1800C80DB10C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9F685456-3336-422F-8F4F-1800C80DB10C}.Debug|x64.ActiveCfg = Debug|Any CPU + {9F685456-3336-422F-8F4F-1800C80DB10C}.Debug|x64.Build.0 = Debug|Any CPU + {9F685456-3336-422F-8F4F-1800C80DB10C}.Debug|x86.ActiveCfg = Debug|Any CPU + {9F685456-3336-422F-8F4F-1800C80DB10C}.Debug|x86.Build.0 = Debug|Any CPU + {9F685456-3336-422F-8F4F-1800C80DB10C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9F685456-3336-422F-8F4F-1800C80DB10C}.Release|Any CPU.Build.0 = Release|Any CPU + {9F685456-3336-422F-8F4F-1800C80DB10C}.Release|x64.ActiveCfg = Release|Any CPU + {9F685456-3336-422F-8F4F-1800C80DB10C}.Release|x64.Build.0 = Release|Any CPU + {9F685456-3336-422F-8F4F-1800C80DB10C}.Release|x86.ActiveCfg = Release|Any CPU + {9F685456-3336-422F-8F4F-1800C80DB10C}.Release|x86.Build.0 = Release|Any CPU + {B49DD477-1671-4FA1-87EC-5E0BFA76C3B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B49DD477-1671-4FA1-87EC-5E0BFA76C3B4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B49DD477-1671-4FA1-87EC-5E0BFA76C3B4}.Debug|x64.ActiveCfg = Debug|Any CPU + {B49DD477-1671-4FA1-87EC-5E0BFA76C3B4}.Debug|x64.Build.0 = Debug|Any CPU + {B49DD477-1671-4FA1-87EC-5E0BFA76C3B4}.Debug|x86.ActiveCfg = Debug|Any CPU + {B49DD477-1671-4FA1-87EC-5E0BFA76C3B4}.Debug|x86.Build.0 = Debug|Any CPU + {B49DD477-1671-4FA1-87EC-5E0BFA76C3B4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B49DD477-1671-4FA1-87EC-5E0BFA76C3B4}.Release|Any CPU.Build.0 = Release|Any CPU + {B49DD477-1671-4FA1-87EC-5E0BFA76C3B4}.Release|x64.ActiveCfg = Release|Any CPU + {B49DD477-1671-4FA1-87EC-5E0BFA76C3B4}.Release|x64.Build.0 = Release|Any CPU + {B49DD477-1671-4FA1-87EC-5E0BFA76C3B4}.Release|x86.ActiveCfg = Release|Any CPU + {B49DD477-1671-4FA1-87EC-5E0BFA76C3B4}.Release|x86.Build.0 = Release|Any CPU + {406046CF-F612-4E57-8DCD-31C4A2B1D455}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {406046CF-F612-4E57-8DCD-31C4A2B1D455}.Debug|Any CPU.Build.0 = Debug|Any CPU + {406046CF-F612-4E57-8DCD-31C4A2B1D455}.Debug|x64.ActiveCfg = Debug|Any CPU + {406046CF-F612-4E57-8DCD-31C4A2B1D455}.Debug|x64.Build.0 = Debug|Any CPU + {406046CF-F612-4E57-8DCD-31C4A2B1D455}.Debug|x86.ActiveCfg = Debug|Any CPU + {406046CF-F612-4E57-8DCD-31C4A2B1D455}.Debug|x86.Build.0 = Debug|Any CPU + {406046CF-F612-4E57-8DCD-31C4A2B1D455}.Release|Any CPU.ActiveCfg = Release|Any CPU + {406046CF-F612-4E57-8DCD-31C4A2B1D455}.Release|Any CPU.Build.0 = Release|Any CPU + {406046CF-F612-4E57-8DCD-31C4A2B1D455}.Release|x64.ActiveCfg = Release|Any CPU + {406046CF-F612-4E57-8DCD-31C4A2B1D455}.Release|x64.Build.0 = Release|Any CPU + {406046CF-F612-4E57-8DCD-31C4A2B1D455}.Release|x86.ActiveCfg = Release|Any CPU + {406046CF-F612-4E57-8DCD-31C4A2B1D455}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/C#/LevenshteinRatio/LevenshteinRatio.cs b/C#/LevenshteinRatio/LevenshteinRatio.cs new file mode 100644 index 0000000..318e60f --- /dev/null +++ b/C#/LevenshteinRatio/LevenshteinRatio.cs @@ -0,0 +1,61 @@ +namespace LevenshteinRatio; + +public static class Levenshtein { + /// + /// Compare to using Levenshtein Ratio. + /// + /// The string to compare with . + /// The string to compare with . + /// The Levenshtein distance ratio between and . + /// + /// + /// float ratio = Levenshtein.Ratio("exampel", "example"); + /// // ratio => 0.85714287 + /// + /// + public static float Ratio(string target, string source) { + // edge cases: source or target is empty, source equals target + if (source == target) { + return 1; + } + + if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(target)) { + return 0; + } + + // create array to store the distances between each character in the source and target strings + var distance = new int[source.Length + 1, target.Length + 1]; + + // Populate the distance matrix + for (int i = 0; i <= source.Length; i++) { + distance[i, 0] = i; + } + + for (int i = 0; i <= target.Length; i++) { + distance[0, i] = i; + } + + // Fill the rows and columns of the distance matrix by comparing the characters in the source + // and target strings and calculating the cost (1 if characters are the same) + for (int i = 1; i <= source.Length; i++) { + for (int j = 1; j <= target.Length; j++) { + int cost = target[j - 1] == source[i - 1] ? 0 : 1; + + distance[i, j] = + Math.Min( + Math.Min( + distance[i - 1, j] + 1, + distance[i, j - 1] + 1 + ), + distance[i - 1, j - 1] + cost + ); + } + } + + // Calculate the ratio of similarity by dividing the distance by the maximum length + // of the two strings and subtracting the result from 1.0 + var distanceAsFloat = Convert.ToSingle(distance[source.Length, target.Length]); + + return 1.0f - distanceAsFloat / Math.Max(source.Length, target.Length); + } +} diff --git a/C#/LevenshteinRatio/LevenshteinRatio.csproj b/C#/LevenshteinRatio/LevenshteinRatio.csproj new file mode 100644 index 0000000..125f4c9 --- /dev/null +++ b/C#/LevenshteinRatio/LevenshteinRatio.csproj @@ -0,0 +1,9 @@ + + + + net9.0 + enable + enable + + + diff --git a/Haskell/.gitignore b/Haskell/.gitignore new file mode 100644 index 0000000..c368d45 --- /dev/null +++ b/Haskell/.gitignore @@ -0,0 +1,2 @@ +.stack-work/ +*~ \ No newline at end of file diff --git a/Haskell/CHANGELOG.md b/Haskell/CHANGELOG.md new file mode 100644 index 0000000..8ea70cd --- /dev/null +++ b/Haskell/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog for `levenshteinRatio` + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to the +[Haskell Package Versioning Policy](https://pvp.haskell.org/). + +## Unreleased + +## 0.1.0.0 - YYYY-MM-DD diff --git a/Haskell/LICENSE b/Haskell/LICENSE new file mode 100644 index 0000000..ce36a7b --- /dev/null +++ b/Haskell/LICENSE @@ -0,0 +1,26 @@ +Copyright 2025 Wessel T + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Haskell/README.md b/Haskell/README.md new file mode 100644 index 0000000..42265b0 --- /dev/null +++ b/Haskell/README.md @@ -0,0 +1 @@ +# levenshteinRatio diff --git a/Haskell/Setup.hs b/Haskell/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/Haskell/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/Haskell/app/Main.hs b/Haskell/app/Main.hs new file mode 100644 index 0000000..563a71f --- /dev/null +++ b/Haskell/app/Main.hs @@ -0,0 +1,13 @@ +-- module Main where + +import Lib (levenshteinRatio) +import Text.Format + +main :: IO () +main = do + let source = "kitten" + target = "sitting" + + putStrLn $ format "Source\t{0}" [source] + putStrLn $ format "Target\t{0}" [target] + putStrLn $ format "Ratio\t{0}" [show (levenshteinRatio source target)] diff --git a/Haskell/bench/Bench.hs b/Haskell/bench/Bench.hs new file mode 100644 index 0000000..12213a1 --- /dev/null +++ b/Haskell/bench/Bench.hs @@ -0,0 +1,22 @@ +{-# LANGUAGE OverloadedStrings #-} +module Main (main) where + +import Criterion.Main +import Criterion.Types (Config (..)) +import Lib (levenshteinRatio) + +main :: IO () +main = + defaultMainWith config + [ bench "levenshteinRatio - short identical strings" $ nf (levenshteinRatio "test") "test", + bench "levenshteinRatio - short different strings" $ nf (levenshteinRatio "test") "abcd", + bench "levenshteinRatio - short similar strings" $ nf (levenshteinRatio "kitten") "sitting", + bench "levenshteinRatio - long identical strings" $ nf (levenshteinRatio longStringA) longStringA, + bench "levenshteinRatio - long different strings" $ nf (levenshteinRatio longStringA) longStringB, + bench "levenshteinRatio - long partially similar strings" $ nf (levenshteinRatio longStringC) longStringA + ] + where + config = defaultConfig {reportFile = Just "benchmark.html"} + longStringA = replicate 1000 'a' + longStringB = replicate 1000 'b' + longStringC = replicate 500 'a' ++ replicate 500 'b' diff --git a/Haskell/benchmark.zip b/Haskell/benchmark.zip new file mode 100644 index 0000000..cb0fe18 Binary files /dev/null and b/Haskell/benchmark.zip differ diff --git a/Haskell/levenshteinRatio.cabal b/Haskell/levenshteinRatio.cabal new file mode 100644 index 0000000..be77b89 --- /dev/null +++ b/Haskell/levenshteinRatio.cabal @@ -0,0 +1,94 @@ +cabal-version: 2.2 + +-- This file has been generated from package.yaml by hpack version 0.37.0. +-- +-- see: https://github.com/sol/hpack + +name: levenshteinRatio +version: 0.1.0.0 +description: Please see the README on GitHub at +homepage: https://github.com/wessel/levenshteinRatio#readme +bug-reports: https://github.com/wessel/levenshteinRatio/issues +author: Wessel T +maintainer: contact@wessel.gg +copyright: Wessel Tip <contact@wessel.gg> (https://wessel.gg/) +license: BSD-3-Clause +license-file: LICENSE +build-type: Simple +extra-source-files: + README.md + CHANGELOG.md + +source-repository head + type: git + location: https://github.com/wessel/levenshteinRatio + +library + exposed-modules: + Lib + other-modules: + Paths_levenshteinRatio + autogen-modules: + Paths_levenshteinRatio + hs-source-dirs: + src + ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints + build-depends: + array + , base >=4.7 && <5 + , text-format-simple + default-language: Haskell2010 + +executable levenshteinRatio-exe + main-is: Main.hs + other-modules: + Paths_levenshteinRatio + autogen-modules: + Paths_levenshteinRatio + hs-source-dirs: + app + ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N + build-depends: + array + , base >=4.7 && <5 + , levenshteinRatio + , text-format-simple + default-language: Haskell2010 + +test-suite levenshteinRatio-test + type: exitcode-stdio-1.0 + main-is: Spec.hs + other-modules: + LevenshteinRatioSpec + SpecHelper + Paths_levenshteinRatio + autogen-modules: + Paths_levenshteinRatio + hs-source-dirs: + test + ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N + build-depends: + array + , base >=4.7 && <5 + , hspec + , levenshteinRatio + , text-format-simple + default-language: Haskell2010 + +benchmark levenshteinRatio-bench + type: exitcode-stdio-1.0 + main-is: Bench.hs + other-modules: + Paths_levenshteinRatio + autogen-modules: + Paths_levenshteinRatio + hs-source-dirs: + bench + ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints + build-depends: + array + , base + , criterion + , levenshteinRatio + , text-format-simple + default-language: Haskell2010 diff --git a/Haskell/package.yaml b/Haskell/package.yaml new file mode 100644 index 0000000..e9e20d7 --- /dev/null +++ b/Haskell/package.yaml @@ -0,0 +1,71 @@ +name: levenshteinRatio +version: 0.1.0.0 +github: "wessel/levenshteinRatio" +license: BSD-3-Clause +author: "Wessel T" +maintainer: "contact@wessel.gg" +copyright: "Wessel Tip <contact@wessel.gg> (https://wessel.gg/)" + +extra-source-files: +- README.md +- CHANGELOG.md + +# Metadata used when publishing your package +# synopsis: Short description of your package +# category: Web + +# To avoid duplicated efforts in documentation and dealing with the +# complications of embedding Haddock markup inside cabal files, it is +# common to point users to the README.md file. +description: Please see the README on GitHub at + +dependencies: +- base >= 4.7 && < 5 +- array +- text-format-simple + +ghc-options: +- -Wall +- -Wcompat +- -Widentities +- -Wincomplete-record-updates +- -Wincomplete-uni-patterns +- -Wmissing-export-lists +- -Wmissing-home-modules +- -Wpartial-fields +- -Wredundant-constraints + +library: + source-dirs: src + +executables: + levenshteinRatio-exe: + main: Main.hs + source-dirs: app + ghc-options: + - -threaded + - -rtsopts + - -with-rtsopts=-N + dependencies: + - levenshteinRatio + +tests: + levenshteinRatio-test: + main: Spec.hs + source-dirs: test + ghc-options: + - -threaded + - -rtsopts + - -with-rtsopts=-N + dependencies: + - levenshteinRatio + - hspec + +benchmarks: + levenshteinRatio-bench: + main: Bench.hs + source-dirs: bench + dependencies: + - levenshteinRatio + - base + - criterion diff --git a/Haskell/profiler.sh b/Haskell/profiler.sh new file mode 100644 index 0000000..950eb56 --- /dev/null +++ b/Haskell/profiler.sh @@ -0,0 +1,5 @@ +rm deno-bench.json perf.data perf.data.txt + +sudo perf record -F MAX -g /home/wessel/Desktop/functional/Haskell/levenshteinRatio/.stack-work/dist/x86_64-linux/ghc-9.8.4/build/levenshteinRatio-bench/levenshteinRatio-bench +sudo chown $USER:$USER ./perf.data +perf script -i perf.data > perf.data.txt diff --git a/Haskell/src/Lib.hs b/Haskell/src/Lib.hs new file mode 100644 index 0000000..68296d1 --- /dev/null +++ b/Haskell/src/Lib.hs @@ -0,0 +1,56 @@ +module Lib (levenshteinRatio) where + +import Data.Array + +{-| + Compare `target` to `source` using LevenshteinRatio + + Arguments: + * `target` - The string to compare with `source` + * `source` - The string to compare with `target` + + Returns: + * The Levenshtein distance between `target` and `source` + + Example: + > levenshteinRatio "exampel" "example" == 0.7142857142857143 +-} +levenshteinRatio :: String -> String -> Double +levenshteinRatio source target + | source == target = 1.0 + | otherwise = + let distance = fromIntegral (calculateDistance source target) + maxLength = fromIntegral (max (length source) (length target)) + in 1.0 - distance / maxLength + +calculateDistance :: String -> String -> Int +calculateDistance source target = finalDistance sourceLength targetLength + where + sourceLength = length source + targetLength = length target + + -- create matrix to store the distances between each character in + -- the source and target strings and populate it + distanceMatrix = array + ((0, 0), (sourceLength, targetLength)) -- ((Starting Index), (Ending Index)) + [ + ((i, j), distanceAtIndices i j) | i <- [0 .. sourceLength], + j <- [0 .. targetLength] + ] -- Populate + + -- Base cases and recursive step + distanceAtIndices 0 j = j + distanceAtIndices i 0 = i + distanceAtIndices i j = + minimum + [ distanceMatrix ! (i - 1, j) + 1, + distanceMatrix ! (i, j - 1) + 1, + distanceMatrix ! (i - 1, j - 1) + cost i j + ] + + cost i j + | source !! (i - 1) == target !! (j - 1) = 0 + | otherwise = 1 + + -- The final distance (Last element of distanceMatrix) + finalDistance i j = distanceMatrix ! (i, j) diff --git a/Haskell/stack.yaml b/Haskell/stack.yaml new file mode 100644 index 0000000..04555ea --- /dev/null +++ b/Haskell/stack.yaml @@ -0,0 +1,68 @@ +# This file was automatically generated by 'stack init' +# +# Some commonly used options have been documented as comments in this file. +# For advanced use and comprehensive documentation of the format, please see: +# https://docs.haskellstack.org/en/stable/configure/yaml/ + +# A 'specific' Stackage snapshot or a compiler version. +# A snapshot resolver dictates the compiler version and the set of packages +# to be used for project dependencies. For example: +# +# snapshot: lts-23.0 +# snapshot: nightly-2024-12-13 +# snapshot: ghc-9.8.4 +# +# The location of a snapshot can be provided as a file or url. Stack assumes +# a snapshot provided as a file might change, whereas a url resource does not. +# +# snapshot: ./custom-snapshot.yaml +# snapshot: https://example.com/snapshots/2024-01-01.yaml +snapshot: + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/23/15.yaml + +# User packages to be built. +# Various formats can be used as shown in the example below. +# +# packages: +# - some-directory +# - https://example.com/foo/bar/baz-0.0.2.tar.gz +# subdirs: +# - auto-update +# - wai +packages: +- . +# Dependency packages to be pulled from upstream that are not in the snapshot. +# These entries can reference officially published versions as well as +# forks / in-progress versions pinned to a git hash. For example: +# +extra-deps: + - text-format-simple-1.1.0@sha256:5815236396328f556b9896fdcb949d15b485ef05394c9dc846e94b0306cb4036,735 +# - acme-missiles-0.3 +# - git: https://github.com/commercialhaskell/stack.git +# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a +# +# extra-deps: [] + +# Override default flag values for project packages and extra-deps +# flags: {} + +# Extra package databases containing global packages +# extra-package-dbs: [] + +# Control whether we use the GHC we find on the path +# system-ghc: true +# +# Require a specific version of Stack, using version ranges +# require-stack-version: -any # Default +# require-stack-version: ">=3.3" +# +# Override the architecture used by Stack, especially useful on Windows +# arch: i386 +# arch: x86_64 +# +# Extra directories used by Stack for building +# extra-include-dirs: [/path/to/dir] +# extra-lib-dirs: [/path/to/dir] +# +# Allow a newer minor version of GHC than the snapshot specifies +# compiler-check: newer-minor diff --git a/Haskell/stack.yaml.lock b/Haskell/stack.yaml.lock new file mode 100644 index 0000000..8eea336 --- /dev/null +++ b/Haskell/stack.yaml.lock @@ -0,0 +1,20 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/topics/lock_files + +packages: +- completed: + hackage: text-format-simple-1.1.0@sha256:5815236396328f556b9896fdcb949d15b485ef05394c9dc846e94b0306cb4036,735 + pantry-tree: + sha256: 026136165778e83cb04c587b3609d95731ccf35da07249c9eb0f29ceb6946cbb + size: 215 + original: + hackage: text-format-simple-1.1.0@sha256:5815236396328f556b9896fdcb949d15b485ef05394c9dc846e94b0306cb4036,735 +snapshots: +- completed: + sha256: 3020db98a5e35009543057d6e6b96890d285890fc97688933e1798da92c8bbde + size: 683815 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/23/15.yaml + original: + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/23/15.yaml diff --git a/Haskell/test/LevenshteinRatioSpec.hs b/Haskell/test/LevenshteinRatioSpec.hs new file mode 100644 index 0000000..4410244 --- /dev/null +++ b/Haskell/test/LevenshteinRatioSpec.hs @@ -0,0 +1,39 @@ +module LevenshteinRatioSpec (main, spec) where + +import Lib (levenshteinRatio) +import SpecHelper + +spec :: Spec +spec = + describe "levenshteinRatio" $ do + it "should return 1 for two empty strings" $ do + levenshteinRatio "" "" `shouldBe` 1.0 + + it "should return 0 if one string is empty" $ do + levenshteinRatio "" "test" `shouldBe` 0.0 + levenshteinRatio "test" "" `shouldBe` 0.0 + + it "should return 0 for completely different strings" $ do + levenshteinRatio "test" "example" `shouldBe` 0.0 + + it "should return 0 for long different strings" $ do + levenshteinRatio longStringA longStringB `shouldBe` 0.0 + + it "should return a value between 0 and 1 for similar strings" $ do + levenshteinRatio "kitten" "sitting" `shouldBe` 0.5714285714285714 + + it "should return 0.5 for long 50/50 similar strings" $ do + levenshteinRatio longStringA longStringC `shouldBe` 0.5 + + it "should return 1 for identical strings" $ do + levenshteinRatio "test" "test" `shouldBe` 1.0 + + it "should return 1 for long identical strings" $ do + levenshteinRatio longStringA longStringA `shouldBe` 1.0 + where + longStringA = replicate 1000 'a' + longStringB = replicate 1000 'b' + longStringC = replicate 500 'a' ++ replicate 500 'b' + +main :: IO () +main = hspec spec \ No newline at end of file diff --git a/Haskell/test/Spec.hs b/Haskell/test/Spec.hs new file mode 100644 index 0000000..52ef578 --- /dev/null +++ b/Haskell/test/Spec.hs @@ -0,0 +1 @@ +{-# OPTIONS_GHC -F -pgmF hspec-discover #-} \ No newline at end of file diff --git a/Haskell/test/SpecHelper.hs b/Haskell/test/SpecHelper.hs new file mode 100644 index 0000000..527fe0d --- /dev/null +++ b/Haskell/test/SpecHelper.hs @@ -0,0 +1,6 @@ +module SpecHelper + ( module Test.Hspec, + ) +where + +import Test.Hspec diff --git a/Report/.editorconfig b/Report/.editorconfig new file mode 100644 index 0000000..310f9a8 --- /dev/null +++ b/Report/.editorconfig @@ -0,0 +1,66 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +cpp_indent_braces=false +cpp_indent_multi_line_relative_to=innermost_parenthesis +cpp_indent_within_parentheses=indent +cpp_indent_preserve_within_parentheses=false +cpp_indent_case_labels=false +cpp_indent_case_contents=true +cpp_indent_case_contents_when_block=false +cpp_indent_lambda_braces_when_parameter=true +cpp_indent_goto_labels=one_left +cpp_indent_preprocessor=leftmost_column +cpp_indent_access_specifiers=false +cpp_indent_namespace_contents=true +cpp_indent_preserve_comments=false +cpp_new_line_before_open_brace_namespace=ignore +cpp_new_line_before_open_brace_type=ignore +cpp_new_line_before_open_brace_function=ignore +cpp_new_line_before_open_brace_block=ignore +cpp_new_line_before_open_brace_lambda=ignore +cpp_new_line_scope_braces_on_separate_lines=false +cpp_new_line_close_brace_same_line_empty_type=false +cpp_new_line_close_brace_same_line_empty_function=false +cpp_new_line_before_catch=true +cpp_new_line_before_else=true +cpp_new_line_before_while_in_do_while=false +cpp_space_before_function_open_parenthesis=remove +cpp_space_within_parameter_list_parentheses=false +cpp_space_between_empty_parameter_list_parentheses=false +cpp_space_after_keywords_in_control_flow_statements=true +cpp_space_within_control_flow_statement_parentheses=false +cpp_space_before_lambda_open_parenthesis=false +cpp_space_within_cast_parentheses=false +cpp_space_after_cast_close_parenthesis=false +cpp_space_within_expression_parentheses=false +cpp_space_before_block_open_brace=true +cpp_space_between_empty_braces=false +cpp_space_before_initializer_list_open_brace=false +cpp_space_within_initializer_list_braces=true +cpp_space_preserve_in_initializer_list=true +cpp_space_before_open_square_bracket=false +cpp_space_within_square_brackets=false +cpp_space_before_empty_square_brackets=false +cpp_space_between_empty_square_brackets=false +cpp_space_group_square_brackets=true +cpp_space_within_lambda_brackets=false +cpp_space_between_empty_lambda_brackets=false +cpp_space_before_comma=false +cpp_space_after_comma=true +cpp_space_remove_around_member_operators=true +cpp_space_before_inheritance_colon=true +cpp_space_before_constructor_colon=true +cpp_space_remove_before_semicolon=true +cpp_space_after_semicolon=false +cpp_space_remove_around_unary_operator=true +cpp_space_around_binary_operator=insert +cpp_space_around_assignment_operator=insert +cpp_space_pointer_reference_alignment=left +cpp_space_around_ternary_operator=insert +cpp_wrap_preserve_blocks=one_liners diff --git a/Report/.gitattributes b/Report/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/Report/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/Report/.github/CODEOWNERS b/Report/.github/CODEOWNERS new file mode 100644 index 0000000..bee82d5 --- /dev/null +++ b/Report/.github/CODEOWNERS @@ -0,0 +1 @@ +* @{{project.master}} diff --git a/Report/.github/CODE_OF_CONDUCT.md b/Report/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..45d257b --- /dev/null +++ b/Report/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,133 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[INSERT CONTACT METHOD]. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/Report/.github/COMMIT_CONVENTION.md b/Report/.github/COMMIT_CONVENTION.md new file mode 100644 index 0000000..68dfb06 --- /dev/null +++ b/Report/.github/COMMIT_CONVENTION.md @@ -0,0 +1,160 @@ +> This is adapted from [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). + +# Conventional Commits 1.0.0-beta.4 + +#### TL;DR: + +Messages must be matched by the following regex: + +```js +/^(revert: )?(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|types|wip)(\(.+\))?: .{1,72}/; +``` + +## Summary + +The Conventional Commits specification is a lightweight convention on top of commit messages. +It provides an easy set of rules for creating an explicit commit history; +which makes it easier to write automated tools on top of. +This convention dovetails with [SemVer](http://semver.org), +by describing the features, fixes, and breaking changes made in commit messages. + +The commit message should be structured as follows: + +--- + +``` +[optional scope]: + +[optional body] + +[optional footer] +``` +--- + +
+The commit contains the following structural elements, to communicate intent to the +consumers of your library: + +1. **fix:** a commit of the _type_ `fix` patches a bug in your codebase (this correlates with [`PATCH`](http://semver.org/#summary) in semantic versioning). +1. **feat:** a commit of the _type_ `feat` introduces a new feature to the codebase (this correlates with [`MINOR`](http://semver.org/#summary) in semantic versioning). +1. **BREAKING CHANGE:** a commit that has the text `BREAKING CHANGE:` at the beginning of its optional body or footer section introduces a breaking API change (correlating with [`MAJOR`](http://semver.org/#summary) in semantic versioning). +A BREAKING CHANGE can be part of commits of any _type_. +1. Others: commit _types_ other than `fix:` and `feat:` are allowed, for example [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional) (based on the [Angular convention](https://github.com/angular/angular/blob/68a6a07/CONTRIBUTING.md#commit)) recommends `chore:`, `docs:`, `style:`, `refactor:`, `perf:`, `test:`, and others. + +We also recommend `improvement` for commits that improve a current implementation without adding a new feature or fixing a bug. +Notice these types are not mandated by the conventional commits specification, and have no implicit effect in semantic versioning (unless they include a BREAKING CHANGE). +
+A scope may be provided to a commit's type, to provide additional contextual information and is contained within parenthesis, e.g., `feat(parser): add ability to parse arrays`. + +## Examples + +### Commit message with description and breaking change in body +``` +feat: allow provided config object to extend other configs + +BREAKING CHANGE: `extends` key in config file is now used for extending other config files +``` + +### Commit message with optional `!` to draw attention to breaking change +``` +chore!: drop Node 6 from testing matrix + +BREAKING CHANGE: dropping Node 6 which hits end of life in April +``` + +### Commit message with no body +``` +docs: correct spelling of CHANGELOG +``` + +### Commit message with scope +``` +feat(lang): add polish language +``` + +### Commit message for a fix using an (optional) issue number. +``` +fix: correct minor typos in code + +see the issue for details on the typos fixed + +closes issue #12 +``` + +## Specification + +The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). + +1. Commits MUST be prefixed with a type, which consists of a noun, `feat`, `fix`, etc., followed + by an OPTIONAL scope, and a REQUIRED terminal colon and space. +1. The type `feat` MUST be used when a commit adds a new feature to your application or library. +1. The type `fix` MUST be used when a commit represents a bug fix for your application. +1. A scope MAY be provided after a type. A scope MUST consist of a noun describing a + section of the codebase surrounded by parenthesis, e.g., `fix(parser):` +1. A description MUST immediately follow the space after the type/scope prefix. +The description is a short summary of the code changes, e.g., _fix: array parsing issue when multiple spaces were contained in string._ +1. A longer commit body MAY be provided after the short description, providing additional contextual information about the code changes. The body MUST begin one blank line after the description. +1. A footer of one or more lines MAY be provided one blank line after the body. The footer MUST contain meta-information +about the commit, e.g., related pull-requests, reviewers, breaking changes, with one piece of meta-information +per-line. +1. Breaking changes MUST be indicated at the very beginning of the body section, or at the beginning of a line in the footer section. A breaking change MUST consist of the uppercase text BREAKING CHANGE, followed by a colon and a space. +1. A description MUST be provided after the `BREAKING CHANGE: `, describing what has changed about the API, e.g., _BREAKING CHANGE: environment variables now take precedence over config files._ +1. Types other than `feat` and `fix` MAY be used in your commit messages. +1. The units of information that make up conventional commits MUST NOT be treated as case sensitive by implementors, with the exception of BREAKING CHANGE which MUST be uppercase. +1. A `!` MAY be appended prior to the `:` in the type/scope prefix, to further draw attention to breaking changes. `BREAKING CHANGE: description` MUST also be included in the body +or footer, along with the `!` in the prefix. + +## Why Use Conventional Commits + +* Automatically generating CHANGELOGs. +* Automatically determining a semantic version bump (based on the types of commits landed). +* Communicating the nature of changes to teammates, the public, and other stakeholders. +* Triggering build and publish processes. +* Making it easier for people to contribute to your projects, by allowing them to explore + a more structured commit history. + +## FAQ + +### How should I deal with commit messages in the initial development phase? + +We recommend that you proceed as if you've already released the product. Typically *somebody*, even if it's your fellow software developers, is using your software. They'll want to know what's fixed, what breaks etc. + +### Are the types in the commit title uppercase or lowercase? + +Any casing may be used, but it's best to be consistent. + +### What do I do if the commit conforms to more than one of the commit types? + +Go back and make multiple commits whenever possible. Part of the benefit of Conventional Commits is its ability to drive us to make more organized commits and PRs. + +### Doesn’t this discourage rapid development and fast iteration? + +It discourages moving fast in a disorganized way. It helps you be able to move fast long term across multiple projects with varied contributors. + +### Might Conventional Commits lead developers to limit the type of commits they make because they'll be thinking in the types provided? + +Conventional Commits encourages us to make more of certain types of commits such as fixes. Other than that, the flexibility of Conventional Commits allows your team to come up with their own types and change those types over time. + +### How does this relate to SemVer? + +`fix` type commits should be translated to `PATCH` releases. `feat` type commits should be translated to `MINOR` releases. Commits with `BREAKING CHANGE` in the commits, regardless of type, should be translated to `MAJOR` releases. + +### How should I version my extensions to the Conventional Commits Specification, e.g. `@jameswomack/conventional-commit-spec`? + +We recommend using SemVer to release your own extensions to this specification (and +encourage you to make these extensions!) + +### What do I do if I accidentally use the wrong commit type? + +#### When you used a type that's of the spec but not the correct type, e.g. `fix` instead of `feat` + +Prior to merging or releasing the mistake, we recommend using `git rebase -i` to edit the commit history. After release, the cleanup will be different according to what tools and processes you use. + +#### When you used a type *not* of the spec, e.g. `feet` instead of `feat` + +In a worst case scenario, it's not the end of the world if a commit lands that does not meet the conventional commit specification. It simply means that commit will be missed by tools that are based on the spec. + +### Do all my contributors need to use the conventional commit specification? + +No! If you use a squash based workflow on Git lead maintainers can clean up the commit messages as they're merged—adding no workload to casual committers. +A common workflow for this is to have your git system automatically squash commits from a pull request and present a form for the lead maintainer to enter the proper git commit message for the merge. \ No newline at end of file diff --git a/Report/.github/CONTRIBUTING.md b/Report/.github/CONTRIBUTING.md new file mode 100644 index 0000000..0706835 --- /dev/null +++ b/Report/.github/CONTRIBUTING.md @@ -0,0 +1,24 @@ +# Contributing + +If you wish to contribute to {{project.name}}, feel free to fork the repository and submit a pull request. +{{project.linter}} is enforced to correct most typo's you make and keep the code style the same throughout the whole project, +so it would be much appreciated if you installed {{project.linter}} to your editor of choice + +## Prerequisites +The following prerequisites must be met before installing {{project.name}}: +{{setup.prerequisites}} + +## Setup +To get ready to work on the codebase, please do the following: + +1. Fork & clone the repository, and make sure you are on the **master** branch +2. Run {{setup.install}} +3. Code your ideas and test them using {{setup.test}} +4. [Submit a pull request](https://github.com/{{project.master}}/{{project.name}}/compare) + +## Testing +When creating any new functions, please also create unit tests for them in the `tests` directory. +Use the library associated with the project when creating such tests. + +When modifying existing functions, make sure to test them before making a pull request, this will prevent +anything from breaking on the production environment. diff --git a/Report/.github/FUNDING.yml b/Report/.github/FUNDING.yml new file mode 100644 index 0000000..b3be161 --- /dev/null +++ b/Report/.github/FUNDING.yml @@ -0,0 +1 @@ +{{project.funding}} diff --git a/Report/.github/ISSUE_TEMPLATE/bug_report.yml b/Report/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..01b6643 --- /dev/null +++ b/Report/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,72 @@ +name: Bug report +description: Report incorrect or unexpected behavior of a package +labels: [bug, need repro] +body: + - type: dropdown + id: package + attributes: + label: Which part is this bug report for? + options: {{tree.parts}} + validations: + required: true + - type: textarea + id: description + attributes: + label: Issue description + description: | + Describe the issue in as much detail as possible. + + Tip: You can attach images or log files by clicking this area to highlight it and then dragging files into it. + placeholder: | + Steps to reproduce with below code sample. + validations: + required: true + - type: textarea + id: codesample + attributes: + label: Code sample + description: Include a reproducible, minimal code sample. This will be automatically formatted into code, so no need for backticks. + render: {{project.lang}} + placeholder: | + Your code sample should be... + ... Minimal - Use as little code as possible that still produces the same problem (and is understandable) + ... Complete - Provide all parts someone else needs to reproduce your problem + ... Reproducible - Test the code you're about to provide to make sure it reproduces the problem + - type: input + id: version + attributes: + label: Version + description: Which version of the package are you using? + validations: + required: true + - type: input + id: lang-version + attributes: + label: '{{project.lang}} version' + description: | + Which version of {{project.lang}} are you using? + validations: + required: true + - type: input + id: os + attributes: + label: Operating system + description: Which OS does your application run on? + - type: dropdown + id: priority + attributes: + label: Priority this issue should have + description: Please be realistic. If you need to elaborate on your reasoning, please use the Issue description field above. + options: + - Low (slightly annoying) + - Medium (should be fixed soon) + - High (immediate attention needed) + validations: + required: true + - type: input + id: dev-release + attributes: + label: I have tested this issue on a development release + placeholder: d23280c (commit hash) + description: | + The issue might already be fixed in a development release or main. This is not required, but helps us greatly. diff --git a/Report/.github/ISSUE_TEMPLATE/config.yml b/Report/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..a5f5423 --- /dev/null +++ b/Report/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,2 @@ +blank_issues_enabled: false +{{project.contact}} diff --git a/Report/.github/ISSUE_TEMPLATE/feature_request.yml b/Report/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..14a0911 --- /dev/null +++ b/Report/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,40 @@ +name: Feature request +description: Request a new feature +labels: [feature request] +body: + - type: markdown + attributes: + value: | + Please only use this form for submitting new, original ideas. + - type: dropdown + id: package + attributes: + label: Which part is this feature request for? + options: {{tree.parts}} + validations: + required: false + - type: textarea + id: description + attributes: + label: Feature + description: A clear and concise description of what the problem is, or what feature you want to be implemented. + placeholder: I'm always frustrated when..., A good addition would be... + validations: + required: true + - type: textarea + id: solution + attributes: + label: Ideal solution or implementation + description: A clear and concise description of what you want to happen. + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Alternative solutions or implementations + description: A clear and concise description of any alternative solutions or features you have considered. + - type: textarea + id: additional-context + attributes: + label: Other context + description: Any other context, screenshots, or file uploads that help us understand your feature request. diff --git a/Report/.github/PULL_REQUEST_TEMPLATE.md b/Report/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..f35130a --- /dev/null +++ b/Report/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,17 @@ +--- +name: Pull Request +about: Propose changes to {{project.name}} +title: "[PR] Your changes" +labels: pullrequest +--- + +**Please describe the changes this PR makes and why it should be merged:** + + +**Status** +- [ ] Code changes have been tested and there aren't any typos in it + +**Semantic versioning classification:** +- [ ] This PR changes {{project.name}} core codebase (methods or parameters added) + - [ ] This PR includes breaking changes (methods removed or renamed, parameters moved or removed) +- [ ] This PR **only** includes non-code changes, like changes to documentation, README, etc. diff --git a/Report/.github/auto_assign.yml b/Report/.github/auto_assign.yml new file mode 100644 index 0000000..3c8d1f2 --- /dev/null +++ b/Report/.github/auto_assign.yml @@ -0,0 +1,4 @@ +addReviewers: true +reviewers: {{project.reviewers}} +numberOfReviewers: 0 +runOnDraft: true diff --git a/Report/.github/labels.yml b/Report/.github/labels.yml new file mode 100644 index 0000000..00be3c8 --- /dev/null +++ b/Report/.github/labels.yml @@ -0,0 +1,62 @@ +- name: bug + color: d73a4a +- name: caching + color: 80c042 +- name: chore + color: ffffff +- name: ci + color: 0075ca +- name: dependencies + color: 276bd1 +- name: documentation + color: 0075ca +- name: duplicate + color: cfd3d7 +- name: error handling + color: 80c042 +- name: feature request + color: fcf95a +- name: good first issue + color: 7057ff +- name: has PR + color: 4b1f8e +- name: help wanted + color: '008672' +- name: in progress + color: ffccd7 +- name: in review + color: aed5fc +- name: interactions + color: 80c042 +- name: invalid + color: e4e669 +- name: need repro + color: c66037 +- name: priority:high + color: fc1423 +- name: question + color: d876e3 +- name: ratelimits + color: 80c042 +- name: refactor + color: 1d637f +- name: regression + color: ea8785 +- name: REST + color: 80c042 +- name: semver:major + color: c10f47 +- name: semver:minor + color: e4f486 +- name: semver:patch + color: e8be8b +- name: tests + color: f06dff +- name: threads + color: 80c042 +- name: typings + color: 80c042 +- name: utility + color: 80c042 +- name: wontfix + color: ffffff \ No newline at end of file diff --git a/Report/.gitignore b/Report/.gitignore new file mode 100644 index 0000000..ef0c0e8 --- /dev/null +++ b/Report/.gitignore @@ -0,0 +1,13 @@ +# LaTeX build files +**/tex/**/*.aux +**/tex/**/*.bbl +**/tex/**/*.blg +**/tex/**/*.fdb_latexmk +**/tex/**/*.fls +**/tex/**/*.log +**/tex/**/*.out +**/tex/**/*.toc +**/tex/**/*.synctex.* + +**/tmp/* +!.gitkeep diff --git a/Report/.vscode/LaTeX.code-snippets b/Report/.vscode/LaTeX.code-snippets new file mode 100644 index 0000000..112bcc8 --- /dev/null +++ b/Report/.vscode/LaTeX.code-snippets @@ -0,0 +1,31 @@ +{ + "Create Table": { + "prefix": "tbl", + "body": [ + "\\begin{table}[ht]", + " \\centering", + " \\begin{threeparttable}", + " \\begin{tabular}{p{2.5cm}|p{8.5cm}}", + " \\toprule", + " $1 & $2 \\\\\\\\", + " \\hline", + " $3 & $4 \\\\\\\\", + " \\bottomrule", + " \\end{tabular}", + " \\end{threeparttable}", + "\\end{table}" + ], + "description": "Create a table with two columns", + }, + "Create Figure": { + "prefix": "fig", + "body": [ + "\\begin{figure}[H]", + " \\includegraphics[width=1\\textwidth]{../img/$1}", + " \\caption{$2}", + " \\label{fig:$3}", + "\\end{figure}" + ], + "description": "Create a figure ", + } +} diff --git a/Report/.vscode/settings.json b/Report/.vscode/settings.json new file mode 100644 index 0000000..b154284 --- /dev/null +++ b/Report/.vscode/settings.json @@ -0,0 +1,112 @@ +{ + "latex-workshop.latex.autoBuild.cleanAndRetry.enabled": true, + "latex-workshop.latex.clean.subfolder.enabled": true, + "latex-workshop.latex.external.build.args": [ "--shell-escape" ], + "latex-workshop.latex.outDir": "tmp", + "latex-workshop.latex.tools": [ + { + "name": "latexmk", + "command": "latexmk", + "args": [ + "-synctex=1", + "-interaction=nonstopmode", + "-file-line-error", + "-pdf", + "-outdir=%OUTDIR%", + "%DOC%", + "--shell-escape", + ], + "env": {} + }, + { + "name": "lualatexmk", + "command": "latexmk", + "args": [ + "-synctex=1", + "-interaction=nonstopmode", + "-file-line-error", + "-lualatex", + "-outdir=%OUTDIR%", + "%DOC%" + ], + "env": {} + }, + { + "name": "xelatexmk", + "command": "latexmk", + "args": [ + "-synctex=1", + "-interaction=nonstopmode", + "-file-line-error", + "-xelatex", + "-outdir=%OUTDIR%", + "%DOC%" + ], + "env": {} + }, + { + "name": "latexmk_rconly", + "command": "latexmk", + "args": [ + "%DOC%" + ], + "env": {} + }, + { + "name": "pdflatex", + "command": "pdflatex", + "args": [ + "-synctex=1", + "-interaction=nonstopmode", + "-file-line-error", + "%DOC%" + ], + "env": {} + }, + { + "name": "bibtex", + "command": "bibtex", + "args": [ + "%DOCFILE%" + ], + "env": {} + }, + { + "name": "rnw2tex", + "command": "Rscript", + "args": [ + "-e", + "knitr::opts_knit$set(concordance = TRUE); knitr::knit('%DOCFILE_EXT%')" + ], + "env": {} + }, + { + "name": "jnw2tex", + "command": "julia", + "args": [ + "-e", + "using Weave; weave(\"%DOC_EXT%\", doctype=\"tex\")" + ], + "env": {} + }, + { + "name": "jnw2texmintex", + "command": "julia", + "args": [ + "-e", + "using Weave; weave(\"%DOC_EXT%\", doctype=\"texminted\")" + ], + "env": {} + }, + { + "name": "tectonic", + "command": "tectonic", + "args": [ + "--synctex", + "--keep-logs", + "%DOC%.tex" + ], + "env": {} + } + ] +} diff --git a/Report/LICENSE b/Report/LICENSE new file mode 100644 index 0000000..b4bba09 --- /dev/null +++ b/Report/LICENSE @@ -0,0 +1,22 @@ + +The MIT License (MIT) + +Copyright (c) {{project.license}} + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Report/LICENSES/.gitkeep b/Report/LICENSES/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Report/README.md b/Report/README.md new file mode 100644 index 0000000..020ea8d --- /dev/null +++ b/Report/README.md @@ -0,0 +1,12 @@ + + + +> {{project.name}} + +[![MIT License](https://img.shields.io/badge/license-MIT-007EC7.svg?style=flat-square)](/LICENSE) + +{{info.desc}} + +

+ +## Table of contents diff --git a/Report/init_repo.py b/Report/init_repo.py new file mode 100644 index 0000000..5527d89 --- /dev/null +++ b/Report/init_repo.py @@ -0,0 +1,86 @@ +import os +import yaml +import re +import datetime + +file_types = ['LICENSE', 'CODEOWNERS', '.md', '.yml'] +script_name = os.path.basename(__file__) + +def replace_placeholders(file_path, replacements): + with open(file_path, 'r', encoding='utf-8') as file: + content = file.read() + + for placeholder, replacement in replacements.items(): + content = re.sub(re.escape(placeholder), replacement, content) + + with open(file_path, 'w', encoding='utf-8') as file: + file.write(content) + +def initialize_repository(directory, replacements): + for root, _, files in os.walk(directory): + for file in files: + if file == script_name: + continue + if any(file.endswith(file_type) for file_type in file_types): + file_path = os.path.join(root, file) + replace_placeholders(file_path, replacements) + +def parse_input(prompt): + return [item.strip() for item in input(prompt).split(',')] + +def parse_contact(prompt): + contacts = [] + while True: + print(prompt) + name = input(f"\tName\t\t").strip() + if not name: + break + url = input(f"\tURL\t\t").strip() + about = input(f"\tAbout\t\t").strip() + contacts.append({'name': name, 'url': url, 'about': about}) + return {'contact_links': contacts} + +def parse_funding(prompt): + funding = {} + while True: + print(prompt) + key = input(f"\tKey\t\t").strip() + if not key: + break + value = input(f"\tValue\t\t").strip() + funding[key] = value + + return funding + +def main(): + current_year = str(datetime.datetime.now().year) + + replacements = { + "{{project.name}}": input("Project name\t\t"), + "{{info.desc}}": input("Project Description\t"), + "{{project.master}}": input("Master of the repo\t"), + "{{project.license}}": f"{current_year} " + input('License holder\t\t'), + + "{{tree.parts}}": yaml.dump(parse_input("Parts of the repo\t"), default_flow_style=True), + "{{project.lang}}": input("Language used\t\t"), + "{{project.linter}}": input("Linter used\t\t"), + + "{{setup.prerequisites}}": input("Prerequisites\t\t"), + "{{setup.install}}": input("Install command\t\t"), + "{{setup.test}}": input("Test command\t\t"), + + "{{project.logo}}": input("Project logo URL\t"), + "{{project.funding}}": yaml.dump(parse_funding("Funding methods\t\t"), default_flow_style=True), + "{{project.contact}}": yaml.dump(parse_contact("Contact information\t"), default_flow_style=False), + "{{project.reviewers}}": yaml.dump(parse_input("Auto-assign users (x,y)\t"), default_flow_style=True) + } + + directory = input("Initialize directory\t") or '.' + initialize_repository(directory, replacements) + + delete = input("Delete this script? (Y/n)\t") or "y" + if delete.lower() == "y": + os.remove(__file__) + +if __name__ == "__main__": + main() diff --git a/Report/tex/doc/.gitkeep b/Report/tex/doc/.gitkeep new file mode 100644 index 0000000..d47982b --- /dev/null +++ b/Report/tex/doc/.gitkeep @@ -0,0 +1 @@ +Contains any external documents such as PDFs diff --git a/Report/tex/doc/LevenshteinRatio.cs b/Report/tex/doc/LevenshteinRatio.cs new file mode 100644 index 0000000..52f9136 --- /dev/null +++ b/Report/tex/doc/LevenshteinRatio.cs @@ -0,0 +1,42 @@ +namespace LevenshteinRatio; + +public static class Levenshtein { + public static float Ratio(string target, string source) { + if (source == target) { + return 1; + } + + if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(target)) { + return 0; + } + + var distance = new int[source.Length + 1, target.Length + 1]; + + for (int i = 0; i <= source.Length; i++) { + distance[i, 0] = i; + } + + for (int i = 0; i <= target.Length; i++) { + distance[0, i] = i; + } + + for (int i = 1; i <= source.Length; i++) { + for (int j = 1; j <= target.Length; j++) { + int cost = target[j - 1] == source[i - 1] ? 0 : 1; + + distance[i, j] = + Math.Min( + Math.Min( + distance[i - 1, j] + 1, + distance[i, j - 1] + 1 + ), + distance[i - 1, j - 1] + cost + ); + } + } + + var distanceAsFloat = Convert.ToSingle(distance[source.Length, target.Length]); + + return 1.0f - distanceAsFloat / Math.Max(source.Length, target.Length); + } +} diff --git a/Report/tex/doc/LevenshteinRatio.hs b/Report/tex/doc/LevenshteinRatio.hs new file mode 100644 index 0000000..7110bbb --- /dev/null +++ b/Report/tex/doc/LevenshteinRatio.hs @@ -0,0 +1,39 @@ +module Lib (levenshteinRatio) where + +import Data.Array + +levenshteinRatio :: String -> String -> Double +levenshteinRatio source target + | source == target = 1.0 + | otherwise = + let distance = fromIntegral (calculateDistance source target) + maxLength = fromIntegral (max (length source) (length target)) + in 1.0 - distance / maxLength + +calculateDistance :: String -> String -> Int +calculateDistance source target = finalDistance sourceLength targetLength + where + sourceLength = length source + targetLength = length target + + distanceMatrix = array + ((0, 0), (sourceLength, targetLength)) + [ + ((i, j), distanceAtIndices i j) | i <- [0 .. sourceLength], + j <- [0 .. targetLength] + ] + + distanceAtIndices 0 j = j + distanceAtIndices i 0 = i + distanceAtIndices i j = + minimum + [ distanceMatrix ! (i - 1, j) + 1, + distanceMatrix ! (i, j - 1) + 1, + distanceMatrix ! (i - 1, j - 1) + cost i j + ] + + cost i j + | source !! (i - 1) == target !! (j - 1) = 0 + | otherwise = 1 + + finalDistance i j = distanceMatrix ! (i, j) diff --git a/Report/tex/doc/levenshteinRatio.ts b/Report/tex/doc/levenshteinRatio.ts new file mode 100644 index 0000000..8b5425a --- /dev/null +++ b/Report/tex/doc/levenshteinRatio.ts @@ -0,0 +1,30 @@ +export function levenshteinRatio(target: string, source: string): number { + if (source === null || target === null) return 0.0; + if (source === target) return 1.0; + if (source.length === 0 || target.length === 0) return 0.0; + + const distanceMatrix = new Array(source.length + 1); + for (let i = 0; i < distanceMatrix.length; i++) distanceMatrix[i] = new Array(target.length + 1); + + for (let i = 0; i <= source.length; distanceMatrix[i][0] = i++); + for (let i = 0; i <= target.length; distanceMatrix[0][i] = i++); + + for (let i = 1; i <= source.length; i++) { + for (let j = 1; j <= target.length; j++) { + const cost = target.charAt(j - 1) === source.charAt(i - 1) ? 0 : 1; + + distanceMatrix[i][j] = + Math.min( + Math.min( + distanceMatrix[i - 1][j] + 1, + distanceMatrix[i][j - 1] + 1 + ), + distanceMatrix[i - 1][j - 1] + cost + ); + } + } + + const totalDistance = distanceMatrix[source.length][target.length] / Math.max(source.length, target.length); + + return 1.0 - totalDistance; +}; diff --git a/Report/tex/img/.gitkeep b/Report/tex/img/.gitkeep new file mode 100644 index 0000000..af2222e --- /dev/null +++ b/Report/tex/img/.gitkeep @@ -0,0 +1 @@ +Contains any images used in the sections diff --git a/Report/tex/img/logo.png b/Report/tex/img/logo.png new file mode 100644 index 0000000..963245e Binary files /dev/null and b/Report/tex/img/logo.png differ diff --git a/Report/tex/img/logo.svg b/Report/tex/img/logo.svg new file mode 100644 index 0000000..fadedb1 --- /dev/null +++ b/Report/tex/img/logo.svg @@ -0,0 +1 @@ + diff --git a/Report/tex/main.tex b/Report/tex/main.tex new file mode 100644 index 0000000..404944f --- /dev/null +++ b/Report/tex/main.tex @@ -0,0 +1,48 @@ +\documentclass[9pt]{IEEEconf} + +\input{packages.tex} +\input{variables.tex} + +\begin{document} +\small +% \sffamily +% Front page containing title, author and date +\pagenumbering{gobble} +\input{sec/0 frontpage.tex} +\newpage + +% Set page numbering to arabic and show the table of contents, toc should not contain page number +\pagenumbering{arabic} +\thispagestyle{empty} +\tableofcontents +\newpage + +% Enable two column layout for the rest of the document +\twocolumn + +% Dictionary containing all the terms used in the document +\input{sec/0 dictionairy.tex} +\newpage + +% Abstract of the document +\input{sec/0 abstract.tex} + +% Sections of the document +\input{sec/1 introduction.tex} + +\section*{Acknowledgements} +\label{sec:acknowledgements} +The author would like to thank the following people for their contribution to this report: +\begin{itemize} + \item[] \makebox[3.2cm]{\textbf{Foppele, J.}\hfill} Supervisor + \item[] \makebox[3.2cm]{\textbf{Luciano, P.}\hfill} Haskell code review + \item[] \makebox[3.2cm]{\textbf{Ralph, D.}\hfill} TypeScript code review + \item[] \makebox[3.2cm]{\textbf{Siegmar , B.}\hfill} CSharp code review +\end{itemize} + +\label{sec:referenties} +\bibliography{references} +\nocite{*} + +\input{sec/2 appendice.tex} +\end{document} diff --git a/Report/tex/packages.tex b/Report/tex/packages.tex new file mode 100644 index 0000000..414ae97 --- /dev/null +++ b/Report/tex/packages.tex @@ -0,0 +1,28 @@ +%/ Use case: language and spell checking +\usepackage[utf8]{inputenc} +\usepackage[english]{babel} +\usepackage{caption} +%/ Use case: uppercase headers +\usepackage{titlecaps} +\usepackage{sectsty} +%/ Use case: text formatting +\usepackage{url} +\usepackage[newfloat,outputdir=tmp]{minted} +\usepackage[colorlinks=true, allcolors=teal]{hyperref} +\usepackage{textcomp} +\usepackage{amsmath} +\usepackage{float} +%/ Use case: images +\usepackage{graphicx} +\usepackage[export]{adjustbox} +\usepackage[font=small,labelfont=bf]{caption} +%/ Use case: tables +\usepackage{booktabs} +\usepackage[flushleft]{threeparttable} +\usepackage{pgfplots} +\usepackage{pgfplotstable} +%/ Use case: paragraph indentation +\usepackage{parskip} + +\usepackage{float} +\usepackage{pdflscape} diff --git a/Report/tex/references.bib b/Report/tex/references.bib new file mode 100644 index 0000000..e69de29 diff --git a/Report/tex/sec/0 abstract.tex b/Report/tex/sec/0 abstract.tex new file mode 100644 index 0000000..2bc5ad8 --- /dev/null +++ b/Report/tex/sec/0 abstract.tex @@ -0,0 +1,3 @@ +\begin{abstract} + +\end{abstract} diff --git a/Report/tex/sec/0 dictionairy.tex b/Report/tex/sec/0 dictionairy.tex new file mode 100644 index 0000000..0bc5ad8 --- /dev/null +++ b/Report/tex/sec/0 dictionairy.tex @@ -0,0 +1,15 @@ +\onecolumn +% todo(wessel) +\section*{Dictionairy} +\begin{table}[ht] + \raggedright + \begin{threeparttable} + \begin{tabular}{p{4cm}|p{11.5cm}} + \toprule + \textbf{Term} & \textbf{Meaning} \\ + \hline + \bottomrule + \end{tabular} + \end{threeparttable} +\end{table} +\twocolumn diff --git a/Report/tex/sec/0 frontpage.tex b/Report/tex/sec/0 frontpage.tex new file mode 100644 index 0000000..b62e32c --- /dev/null +++ b/Report/tex/sec/0 frontpage.tex @@ -0,0 +1,10 @@ +\onecolumn +\maketitle + +\begin{figure}[H] + \centering + \includegraphics[width=0.3\textwidth]{../img/logo.png} +\end{figure} + +% Push the content below to the bottom of the page +\vfill diff --git a/Report/tex/sec/1 introduction.tex b/Report/tex/sec/1 introduction.tex new file mode 100644 index 0000000..a26a33c --- /dev/null +++ b/Report/tex/sec/1 introduction.tex @@ -0,0 +1,34 @@ +\section{Introduction} +\label{sec:introduction} +This report will focus on understanding functional programming +languages and their differences compared to imperative languages. +The implementation of the Levenshtein ratio algorithm is discribed in three +different programming styles and compares the results on multiple fronts. + +The Levenshtein ratio algorithm is a commonly used +algorithm to measure the similarity between two strings. +It is applied in various fields such as spell checking, DNA sequencing, and plagiarism detection. +By implementing this algorithm in different programming languages, we can analyze the impact of +the programming paradigm on performance, code complexity, and maintainability. + +The following languages were chosen for this comparison, each representing a different paradigm: +\begin{itemize} + \item[-] \makebox[3.2cm]{\textbf{Haskell (Functional)}\hfill} A purely functional language that + emphasizes immutability and recursion. Known for its concise and expressive code. + \item[-] \makebox[3.2cm]{\textbf{Csharp (Imperative)}\hfill} An object-oriented language mainly + used to develop Windows applications and games. + \item[-] \makebox[3.2cm]{\textbf{TypeScript (Semi)}\hfill} A language that supports both imperative + and functional constructs. Known for its leniant interperter. +\end{itemize} + +The comparison is based on the following criteria: +\begin{enumerate} + \item[I.] Speed – time complexity and memory usage. + \item[II.] Readability – how simple and intuitive the code is. + \item[III.] Maintainability – how well the code scales and is extendable. + \item[IV.] Complexity of implementation – how difficult it is to correctly implement the algorithm in the chosen language. +\end{enumerate} + +To objectively test the implementations, identical test datasets are used. Multiple test cases are designed that increase in complexity and size, with an expected output. The correctness of the implementations is verified with asserts or unit tests. + +This approach provides insight into how different programming paradigms affect the practical implementation of a well-known algorithm. diff --git a/Report/tex/sec/2 appendice.tex b/Report/tex/sec/2 appendice.tex new file mode 100644 index 0000000..53dba7a --- /dev/null +++ b/Report/tex/sec/2 appendice.tex @@ -0,0 +1,128 @@ +\onecolumn +\begin{landscape} +\section{Appendice} + +\subsection*{Benchmark Summaries} +\begin{figure}[H] + \caption{Benchmark results for the TypeScript implementation using the Deno runtime.} + \label{code:benchmark-typescript} + \begin{minted}[fontsize=\footnotesize]{text} + CPU | AMD Ryzen 5 5600X 6-Core Processor + Runtime | Deno 2.0.0 (x86_64-unknown-linux-gnu) + + benchmark time/iter (avg) iter/s (min … max) p75 p99 p995 + --------------------------------------------------- ----------------------------- --------------------- -------------------------- + levenshteinRatio - short identical strings 5.1 ns 195,400,000 ( 5.0 ns … 24.6 ns) 5.0 ns 7.5 ns 9.2 ns + levenshteinRatio - short different strings 144.9 ns 6,904,000 (137.0 ns … 182.7 ns) 148.7 ns 173.1 ns 182.5 ns + levenshteinRatio - short similar strings 323.3 ns 3,093,000 (299.4 ns … 613.6 ns) 325.8 ns 465.5 ns 613.6 ns + levenshteinRatio - long identical strings 5.3 ns 187,100,000 ( 5.1 ns … 145.6 ns) 5.1 ns 7.9 ns 9.0 ns + levenshteinRatio - long different strings 7.0 ms 142.0 ( 6.5 ms … 12.3 ms) 6.9 ms 12.3 ms 12.3 ms + levenshteinRatio - long partially similar strings 7.5 ms 133.6 ( 7.2 ms … 8.1 ms) 7.6 ms 8.1 ms 8.1 ms + \end{minted} +\end{figure} + +\hfill + +\begin{figure}[H] + \caption{Benchmark results for the CSharp implementation using BenchmarkDotNet.} + \label{code:benchmark-csharp} + \begin{minted}[fontsize=\footnotesize]{text} + Runtime = .NET 9.0.3 (9.0.325.11113), X64 RyuJIT AVX2; GC = Concurrent Workstation + Mean = 3.233 ms, StdErr = 0.004 ms (0.14%), N = 14, StdDev = 0.017 ms + Min = 3.204 ms, Q1 = 3.221 ms, Median = 3.233 ms, Q3 = 3.246 ms, Max = 3.259 ms + IQR = 0.025 ms, LowerFence = 3.184 ms, UpperFence = 3.283 ms + ConfidenceInterval = [3.214 ms; 3.252 ms] (CI 99.9%), Margin = 0.019 ms (0.59% of Mean) + Skewness = -0.19, Kurtosis = 1.65, MValue = 2 + + BenchmarkDotNet v0.14.0, Debian GNU/Linux 12 (bookworm) (container) + AMD Ryzen 5 5600X, 1 CPU, 12 logical and 6 physical cores + .NET SDK 9.0.201 + + | Method | Mean | Error | StdDev | + |---------------------------- |-----------------:|---------------:|---------------:| + | ShortIdenticalStrings | 1.410 ns | 0.0510 ns | 0.0793 ns | + | ShortDifferentStrings | 112.147 ns | 1.4472 ns | 1.3537 ns | + | ShortSimilarStrings | 193.013 ns | 1.8653 ns | 1.7448 ns | + | LongIdenticalStrings | 1.097 ns | 0.0221 ns | 0.0196 ns | + | LongDifferentStrings | 3,234,542.032 ns | 34,662.1297 ns | 32,422.9776 ns | + | LongPartiallySimilarStrings | 3,233,473.960 ns | 18,980.6706 ns | 16,825.8701 ns | + + Mean : Arithmetic mean of all measurements + Error : Half of 99.9% confidence interval + StdDev : Standard deviation of all measurements + 1 ns : 1 Nanosecond (0.000000001 sec) + + Run time: 00:02:27 (147.1 sec), executed benchmarks: 6 + + Global total time: 00:03:08 (188.25 sec), executed benchmarks: 6 + \end{minted} +\end{figure} +\hfill + +\begin{figure}[H] + \caption{Benchmark results for the Haskell implementation using Criterion.} + \label{code:benchmark-haskell} + \begin{minted}[fontsize=\footnotesize]{text} + benchmarking levenshteinRatio - short identical strings + time 20.15 ns (19.87 ns .. 20.38 ns) + 0.999 R² (0.998 R² .. 0.999 R²) + mean 20.15 ns (20.00 ns .. 20.36 ns) + std dev 604.4 ps (497.4 ps .. 753.7 ps) + + benchmarking levenshteinRatio - short different strings + time 966.6 ns (953.2 ns .. 985.3 ns) + 0.996 R² (0.991 R² .. 0.999 R²) + mean 992.3 ns (970.7 ns .. 1.036 μs) + std dev 97.98 ns (50.78 ns .. 187.7 ns) + + benchmarking levenshteinRatio - short similar strings + time 2.410 μs (2.386 μs .. 2.436 μs) + 0.999 R² (0.999 R² .. 1.000 R²) + mean 2.391 μs (2.374 μs .. 2.417 μs) + std dev 69.63 ns (50.30 ns .. 104.4 ns) + + benchmarking levenshteinRatio - long identical strings + time 3.786 μs (3.765 μs .. 3.815 μs) + 1.000 R² (0.999 R² .. 1.000 R²) + mean 3.815 μs (3.795 μs .. 3.842 μs) + std dev 79.62 ns (63.85 ns .. 103.2 ns) + + benchmarking levenshteinRatio - long different strings + time 1.178 s (847.8 ms .. 1.411 s) + 0.991 R² (0.970 R² .. 1.000 R²) + mean 1.174 s (1.121 s .. 1.245 s) + std dev 68.38 ms (32.52 ms .. 85.07 ms) + + benchmarking levenshteinRatio - long partially similar strings + time 1.159 s (816.3 ms .. 1.381 s) + 0.990 R² (0.968 R² .. 1.000 R²) + mean 1.158 s (1.120 s .. 1.214 s) + std dev 53.67 ms (17.17 ms .. 70.20 ms) + \end{minted} +\end{figure} +\hfill + +\subsection*{Source Code} +\begin{figure}[H] + \caption{TypeScript implementation of the Levenshtein distance algorithm.} + \label{code:typescript} + \inputminted[fontsize=\footnotesize]{typescript}{./doc/levenshteinRatio.ts} +\end{figure} + +\hfill + +\begin{figure}[H] + \caption{C\# implementation of the Levenshtein distance algorithm.} + \label{code:csharp} + \inputminted[fontsize=\footnotesize]{csharp}{./doc/LevenshteinRatio.cs} +\end{figure} + +\hfill + +\begin{figure}[H] + \caption{Haskell implementation of the Levenshtein distance algorithm.} + \label{code:haskell} + \inputminted[fontsize=\footnotesize]{haskell}{./doc/LevenshteinRatio.hs} +\end{figure} + +\end{landscape} diff --git a/Report/tex/tmp/.gitkeep b/Report/tex/tmp/.gitkeep new file mode 100644 index 0000000..c2931ef --- /dev/null +++ b/Report/tex/tmp/.gitkeep @@ -0,0 +1 @@ +Contains build files diff --git a/Report/tex/variables.tex b/Report/tex/variables.tex new file mode 100644 index 0000000..268fbef --- /dev/null +++ b/Report/tex/variables.tex @@ -0,0 +1,26 @@ +\graphicspath{ {./img/} } +\pgfplotsset{compat=1.18} + +\title{\titlecap{\scshape Comparison of the Levenshtein Ratio Algorithm in Haskell, C\# and TypeScript}} +\author{Wessel Tip $<$contact@wessel.gg$>$ (\url{https://wessel.gg/})\\ +\\ +Minor Advanced Software Engineering \\ +NHL Stenden University of Applied Sciences \\ +Year 3, Semester 2 (Jan. 2025 - Jun. 2025)} + +% Empty date +\date{\today} + +% Sets the description name of code blocks to "Source Code" +\newenvironment{code}{\captionsetup{type=listing}}{} +\SetupFloatingEnvironment{listing}{name=Source Code} + +\renewcommand{\theFancyVerbLine}{\sffamily +\textcolor[rgb]{0.5,0.5,1.0}{\scriptsize +\oldstylenums{\arabic{FancyVerbLine}}}} + +% Sets the bibliography style to IEEE +\bibliographystyle{IEEEtran} + +% Disables the no citations error +\nocite{*} diff --git a/Typescript/benchmark.zip b/Typescript/benchmark.zip new file mode 100644 index 0000000..f01a196 Binary files /dev/null and b/Typescript/benchmark.zip differ diff --git a/Typescript/levenshteinRatio.bench.ts b/Typescript/levenshteinRatio.bench.ts new file mode 100644 index 0000000..7f364db --- /dev/null +++ b/Typescript/levenshteinRatio.bench.ts @@ -0,0 +1,29 @@ +import { levenshteinRatio } from "./levenshteinRatio.ts"; + +const longStringA = new Array(1000).fill('a').join(''); +const longStringB = new Array(1000).fill('b').join(''); +const longStringC = new Array(500).fill('a').join('') + new Array(500).fill('b').join(''); + +Deno.bench("levenshteinRatio - short identical strings", () => { + levenshteinRatio("test", "test"); +}); + +Deno.bench("levenshteinRatio - short different strings", () => { + levenshteinRatio("test", "abcd"); +}); + +Deno.bench("levenshteinRatio - short similar strings", () => { + levenshteinRatio("kitten", "sitting"); +}); + +Deno.bench("levenshteinRatio - long identical strings", () => { + levenshteinRatio(longStringA, longStringA); +}); + +Deno.bench("levenshteinRatio - long different strings", () => { + levenshteinRatio(longStringA, longStringB); +}); + +Deno.bench("levenshteinRatio - long partially similar strings", () => { + levenshteinRatio(longStringC, longStringA); +}); diff --git a/Typescript/levenshteinRatio.test.ts b/Typescript/levenshteinRatio.test.ts new file mode 100644 index 0000000..e8312c1 --- /dev/null +++ b/Typescript/levenshteinRatio.test.ts @@ -0,0 +1,40 @@ +import { assertEquals } from "jsr:@std/assert"; +import { levenshteinRatio } from "./levenshteinRatio.ts"; + +Deno.test("levenshteinRatio should return 1 for empty strings", () => { + assertEquals(levenshteinRatio("", ""), 1); +}); + +Deno.test("levenshteinRatio should return 0 if one string is empty", () => { + assertEquals(levenshteinRatio("", "test"), 0); + assertEquals(levenshteinRatio("test", ""), 0); +}); + +Deno.test("levenshteinRatio should return 0 if one string is null", () => { + assertEquals(levenshteinRatio("test", null!), 0); + assertEquals(levenshteinRatio(null!, ""), 0); + assertEquals(levenshteinRatio(null!, null!), 0); +}); + +Deno.test("levenshteinRatio should return 1 for identical strings", () => { + assertEquals(levenshteinRatio("test", "test"), 1); +}); + +Deno.test("levenshteinRatio should return 1 for long identical strings", () => { + const longString = new Array(10000).fill('a').join(''); + assertEquals(levenshteinRatio(longString, longString), 1); +}); + +Deno.test("levenshteinRatio should return 0 for different strings", () => { + assertEquals(levenshteinRatio("test", "example"), 0); +}); + +Deno.test("levenshteinRatio should return 0 for long different strings", () => { + const longStringA = new Array(10000).fill('a').join(''); + const longStringB = new Array(10000).fill('b').join(''); + assertEquals(levenshteinRatio(longStringA, longStringB), 0); +}); + +Deno.test("levenshteinRatio should return a value between 0 and 1 for similar strings", () => { + assertEquals(levenshteinRatio("kitten", "sitting"), 0.5714285714285714); +}); \ No newline at end of file diff --git a/Typescript/levenshteinRatio.ts b/Typescript/levenshteinRatio.ts new file mode 100644 index 0000000..e246858 --- /dev/null +++ b/Typescript/levenshteinRatio.ts @@ -0,0 +1,48 @@ +/** + * Compare `target` to `source` using LevenshteinRatio + * + * @param {string} target The string to compare with `source` + * @param {string} source The string to compare with `target` + * @returns {number} The Levenshtein distance between `target` and `source` + * @example + * + * levenshteinRatio('exampel', 'example') + * // => 0.7142857142857143 + */ +export function levenshteinRatio(target: string, source: string): number { + // edge cases: source or target is empty, source equals target + if (source === null || target === null) return 0.0; + if (source === target) return 1.0; + if (source.length === 0 || target.length === 0) return 0.0; + + // create matrix to store the distances between each character in + // the source and target strings and populate it + const distanceMatrix = new Array(source.length + 1); + for (let i = 0; i < distanceMatrix.length; i++) distanceMatrix[i] = new Array(target.length + 1); + + for (let i = 0; i <= source.length; distanceMatrix[i][0] = i++); + for (let i = 0; i <= target.length; distanceMatrix[0][i] = i++); + + // Fill the rows and columns of the distance matrix by comparing the characters in the source + // and target strings and calculating the cost (1 if characters are the same) + for (let i = 1; i <= source.length; i++) { + for (let j = 1; j <= target.length; j++) { + const cost = target.charAt(j - 1) === source.charAt(i - 1) ? 0 : 1; + + distanceMatrix[i][j] = + Math.min( + Math.min( + distanceMatrix[i - 1][j] + 1, + distanceMatrix[i][j - 1] + 1 + ), + distanceMatrix[i - 1][j - 1] + cost + ); + } + } + + // Calculate the ratio of similarity by dividing the distance by the maximum length + // of the two strings and subtracting the result from 1.0 + const totalDistance = distanceMatrix[source.length][target.length] / Math.max(source.length, target.length); + + return 1.0 - totalDistance; +}; \ No newline at end of file diff --git a/Typescript/profiler.sh b/Typescript/profiler.sh new file mode 100644 index 0000000..7e1498e --- /dev/null +++ b/Typescript/profiler.sh @@ -0,0 +1,5 @@ +rm deno-bench.json perf.data perf.data.txt + +sudo perf record -F MAX -g /home/wessel/.deno/bin/deno bench --json > deno-bench.json +sudo chown $USER:$USER ./perf.data +perf script -i perf.data > perf.data.txt