diff --git a/BitFaster.Caching.HitRateAnalysis/Analysis.cs b/BitFaster.Caching.HitRateAnalysis/Analysis.cs new file mode 100644 index 00000000..18215b2a --- /dev/null +++ b/BitFaster.Caching.HitRateAnalysis/Analysis.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BitFaster.Caching.HitRateAnalysis +{ + public class Analysis + { + public int N { get; set; } + + public double s { get; set; } + + public int Samples { get; set; } + + public double CacheSizePercent { get; set; } + + public void WriteSummaryToConsole() + { + Console.WriteLine($"Analyzing with N={N}, s={s}, Samples={Samples}, Cache Size ={CacheSizePercent*100.0}%"); + } + } +} diff --git a/BitFaster.Caching.HitRateAnalysis/AnalysisResult.cs b/BitFaster.Caching.HitRateAnalysis/AnalysisResult.cs new file mode 100644 index 00000000..2c86f155 --- /dev/null +++ b/BitFaster.Caching.HitRateAnalysis/AnalysisResult.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; +using ConsoleTables; +using CsvHelper; + +namespace BitFaster.Caching.HitRateAnalysis +{ + public class AnalysisResult + { + public string Cache { get; set; } + + public int N { get; set; } + + public double s { get; set; } + + public int Samples { get; set; } + + public double CacheSizePercent { get; set; } + + public double HitRatio { get; set; } + + public static void WriteToFile(string path, IEnumerable results) + { + using (var writer = new StreamWriter(path)) + using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) + { + csv.WriteRecords(results); + } + } + + public static void WriteToConsole(IEnumerable results) + { + ConsoleTable + .From(results) + .Configure(o => o.NumberAlignment = Alignment.Right) + .Write(Format.Alternative); + } + } +} diff --git a/BitFaster.Sampling/BitFaster.Sampling.csproj b/BitFaster.Caching.HitRateAnalysis/BitFaster.Caching.HitRateAnalysis.csproj similarity index 80% rename from BitFaster.Sampling/BitFaster.Sampling.csproj rename to BitFaster.Caching.HitRateAnalysis/BitFaster.Caching.HitRateAnalysis.csproj index 71495a29..8ad95104 100644 --- a/BitFaster.Sampling/BitFaster.Sampling.csproj +++ b/BitFaster.Caching.HitRateAnalysis/BitFaster.Caching.HitRateAnalysis.csproj @@ -10,6 +10,8 @@ + + diff --git a/BitFaster.Caching.HitRateAnalysis/Program.cs b/BitFaster.Caching.HitRateAnalysis/Program.cs new file mode 100644 index 00000000..12f1d276 --- /dev/null +++ b/BitFaster.Caching.HitRateAnalysis/Program.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using BitFaster.Caching.HitRateAnalysis; +using BitFaster.Caching.Lru; +using MathNet.Numerics; +using MathNet.Numerics.Distributions; + +namespace BitFaster.Sampling +{ + class Program + { + // Test methodolopy from 2Q paper: + // http://www.vldb.org/conf/1994/P439.PDF + + // s = 0.5 and s = 0.86. + // If there are N items, the probability of accessing an item numbered i or less is (i / N)^s. + // A setting of (s = 0.86 gives an 80 / 20 distribution, while a setting of (s = 0.5 give a less skewed + // distribution (about 45 / 20). + + // Took 1 million samples + const int sampleCount = 1000000; + + // Simulated a database of 50,000 pages and + // buffer sizes ranging from 2,500 (5%) items to 20,000 + // (40%) items. + const int n = 50000; + + static void Main(string[] args) + { + double[] sValues = { 0.5, 0.86 }; + + // % of total number of items + double[] cacheSizes = { 0.025, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4 }; + + List analysis = new List(); + + foreach (var sValue in sValues) + { + foreach (var cacheSize in cacheSizes) + { + analysis.Add(new Analysis { + N = n, + s = sValue, + Samples = sampleCount, + CacheSizePercent = cacheSize + }); + } + } + + int[][] zipdfDistribution = new int[sValues.Length][]; + + for (int i = 0; i < sValues.Length; i++) + { + Console.WriteLine($"Generating Zipfan distribution with {sampleCount} samples, s = {sValues[i]}, N = {n}"); + zipdfDistribution[i] = new int[sampleCount]; + Zipf.Samples(zipdfDistribution[i], sValues[i], n); + } + + List results = new List(); + Func func = x => x; + + foreach (var a in analysis) + { + a.WriteSummaryToConsole(); + + int cacheSize = (int)(a.N * a.CacheSizePercent); + + var concurrentLru = new ConcurrentLru(1, cacheSize, EqualityComparer.Default); + var classicLru = new ClassicLru(1, cacheSize, EqualityComparer.Default); + + var d = a.s == 0.5 ? 0 : 1; + + for (int i = 0; i < sampleCount; i++) + { + concurrentLru.GetOrAdd(zipdfDistribution[d][i], func); + classicLru.GetOrAdd(zipdfDistribution[d][i], func); + } + + results.Add(new AnalysisResult + { + Cache = "ClassicLru", + N = a.N, + s = a.s, + CacheSizePercent = a.CacheSizePercent * 100.0, + Samples = a.Samples, + HitRatio = classicLru.HitRatio * 100.0, + }); + + results.Add(new AnalysisResult + { + Cache = "ConcurrentLru", + N = a.N, + s = a.s, + CacheSizePercent = a.CacheSizePercent * 100.0, + Samples = a.Samples, + HitRatio = concurrentLru.HitRatio * 100.0, + }); + } + + AnalysisResult.WriteToConsole(results); + AnalysisResult.WriteToFile("results.csv", results); + + Console.ReadLine(); + } + } +} diff --git a/BitFaster.Sampling/Program.cs b/BitFaster.Sampling/Program.cs deleted file mode 100644 index 3f3bec04..00000000 --- a/BitFaster.Sampling/Program.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Collections.Generic; -using BitFaster.Caching.Lru; -using MathNet.Numerics.Distributions; - -namespace BitFaster.Sampling -{ - class Program - { - // Test methodolopy from 2Q paper: - // http://www.vldb.org/conf/1994/P439.PDF - - // s = 0.5 and s = 0.86. - // If there are N items, the probability of accessing an item numbered i or less is (i / N)^s. - // A setting of (s = 0.86 gives an 80 / 20 distribution, while a setting of (s = 0.5 give a less skewed - // distribution (about 45 / 20). - const double s = 0.86; - // const double s = 0.5; - - // Took 1 million samples - const int sampleCount = 20000; - - // We simulated a database of 50,000 pages and - // buffer sizes ranging from 2,500 (5%) items to 20,000 - // (40%) items. - const int n = 50000; - - const double cacheSizeRatio = 0.05; - - const int cacheSize = (int)(n * cacheSizeRatio); - - static void Main(string[] args) - { - Console.WriteLine($"Generating Zipfan distribution with {sampleCount} samples, s = {s}, N = {n}"); - - var samples = new int[sampleCount]; - Zipf.Samples(samples, s, n); - - var concurrentLru = new ConcurrentLru(1, cacheSize, EqualityComparer.Default); - var classicLru = new ClassicLru(1, cacheSize, EqualityComparer.Default); - - Func func = x => x; - Console.WriteLine($"Running {sampleCount} iterations"); - - for (int i = 0; i < sampleCount; i++) - { - concurrentLru.GetOrAdd(samples[i], func); - classicLru.GetOrAdd(samples[i], func); - } - - Console.WriteLine($"ConcurrentLru hit ratio {concurrentLru.HitRatio * 100.0}%"); - Console.WriteLine($"ClassicLru hit ratio {classicLru.HitRatio * 100.0}%"); - - Console.ReadLine(); - } - } -} diff --git a/BitFaster.sln b/BitFaster.sln index 1c48cf2f..2480daa6 100644 --- a/BitFaster.sln +++ b/BitFaster.sln @@ -14,7 +14,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BitFaster.Caching.UnitTests EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BitFaster.Caching.Benchmarks", "BitFaster.Caching.Benchmarks\BitFaster.Caching.Benchmarks.csproj", "{8CDE3FA5-B08A-4375-9EF0-F1F044B841C4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitFaster.Sampling", "BitFaster.Sampling\BitFaster.Sampling.csproj", "{EAAE8DD3-EA1C-4BDF-920B-A0C858E853CB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BitFaster.Caching.HitRateAnalysis", "BitFaster.Caching.HitRateAnalysis\BitFaster.Caching.HitRateAnalysis.csproj", "{12AAE7FB-09F5-4A87-838E-891ACEF5722B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -34,10 +34,10 @@ Global {8CDE3FA5-B08A-4375-9EF0-F1F044B841C4}.Debug|Any CPU.Build.0 = Debug|Any CPU {8CDE3FA5-B08A-4375-9EF0-F1F044B841C4}.Release|Any CPU.ActiveCfg = Release|Any CPU {8CDE3FA5-B08A-4375-9EF0-F1F044B841C4}.Release|Any CPU.Build.0 = Release|Any CPU - {EAAE8DD3-EA1C-4BDF-920B-A0C858E853CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EAAE8DD3-EA1C-4BDF-920B-A0C858E853CB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EAAE8DD3-EA1C-4BDF-920B-A0C858E853CB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EAAE8DD3-EA1C-4BDF-920B-A0C858E853CB}.Release|Any CPU.Build.0 = Release|Any CPU + {12AAE7FB-09F5-4A87-838E-891ACEF5722B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {12AAE7FB-09F5-4A87-838E-891ACEF5722B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {12AAE7FB-09F5-4A87-838E-891ACEF5722B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {12AAE7FB-09F5-4A87-838E-891ACEF5722B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE