Skip to content
Merged

thru #247

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions BitFaster.Caching.ThroughputAnalysis/CacheFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BitFaster.Caching.Lfu;
using BitFaster.Caching.Lru;
using BitFaster.Caching.Scheduler;

namespace BitFaster.Caching.ThroughputAnalysis
{
public interface ICacheFactory
{
(IScheduler, ICache<int, int>) Create(int threadCount);

public string Name { get; }

DataRow DataRow { get; set; }
}

public class FastConcurrentLruFactory : ICacheFactory
{
private int capacity;

public FastConcurrentLruFactory(int capacity)
{
this.capacity = capacity;
}

public string Name => "FsTConcLRU";

public DataRow DataRow { get; set; }

public (IScheduler, ICache<int, int>) Create(int threadCount)
{
var cache = new FastConcurrentLru<int, int>(threadCount, capacity, EqualityComparer<int>.Default);

return (null, cache);
}
}

public class ConcurrentLruFactory : ICacheFactory
{
private int capacity;

public ConcurrentLruFactory(int capacity)
{
this.capacity = capacity;
}

public string Name => "ConcurrLRU";

public DataRow DataRow { get; set; }

public (IScheduler, ICache<int, int>) Create(int threadCount)
{
var cache = new ConcurrentLru<int, int>(threadCount, capacity, EqualityComparer<int>.Default);

return (null, cache);
}
}

public class MemoryCacheFactory : ICacheFactory
{
private int capacity;

public MemoryCacheFactory(int capacity)
{
this.capacity = capacity;
}

public string Name => "MemryCache";

public DataRow DataRow { get; set; }

public (IScheduler, ICache<int, int>) Create(int threadCount)
{
var cache = new MemoryCacheAdaptor<int, int>(capacity);

return (null, cache);
}
}

public class ConcurrentLfuFactory : ICacheFactory
{
private int capacity;

public ConcurrentLfuFactory(int capacity)
{
this.capacity = capacity;
}

public string Name => "ConcurrLFU";

public DataRow DataRow { get; set; }

public (IScheduler, ICache<int, int>) Create(int threadCount)
{
var scheduler = new BackgroundThreadScheduler();
var cache = new ConcurrentLfu<int, int>(
concurrencyLevel: threadCount,
capacity: capacity,
scheduler: scheduler,
EqualityComparer<int>.Default);

return (scheduler, cache);
}
}

public class ClassicLruFactory : ICacheFactory
{
private int capacity;

public ClassicLruFactory(int capacity)
{
this.capacity = capacity;
}

public string Name => "ClassicLru";

public DataRow DataRow { get; set; }

public (IScheduler, ICache<int, int>) Create(int threadCount)
{
var cache = new ClassicLru<int, int>(threadCount, capacity, EqualityComparer<int>.Default);

return (null, cache);
}
}
}
34 changes: 34 additions & 0 deletions BitFaster.Caching.ThroughputAnalysis/ConfigFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BitFaster.Caching.ThroughputAnalysis
{
public class ConfigFactory
{
const double s = 0.86; // Zipf s parameter, controls distribution
const int n = 500; // number of unique items for Zipf
const int maxThreads = 52;
const int sampleCount = 2000;

public static (ThroughputBenchmarkBase, IThroughputBenchConfig, int) Create(Mode mode, int repeatCount)
{
switch (mode)
{
case Mode.Read:
return (new ReadThroughputBenchmark(), new ZipfConfig(repeatCount, sampleCount, s, n), n);
case Mode.ReadWrite:
// cache holds 10% of all items
return (new ReadThroughputBenchmark(), new ZipfConfig(repeatCount, sampleCount, s, n), n / 10);
case Mode.Update:
return (new UpdateThroughputBenchmark(), new ZipfConfig(repeatCount, sampleCount, s, n), n);
case Mode.Evict:
return (new ReadThroughputBenchmark(), new EvictionConfig(repeatCount, sampleCount, maxThreads), n);
}

throw new InvalidOperationException();
}
}
}
71 changes: 71 additions & 0 deletions BitFaster.Caching.ThroughputAnalysis/Exporter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CsvHelper;

namespace BitFaster.Caching.ThroughputAnalysis
{
public class Exporter
{
DataTable resultTable = new DataTable();

public Exporter(int maxThreads)
{
// output:
// ThreadCount 1 2 3 4 5
// Classic 5 6 7 7 8
// Concurrent 5 6 7 7 8

resultTable.Clear();
resultTable.Columns.Add("ThreadCount");
foreach (var tc in Enumerable.Range(1, maxThreads).ToArray())
{
resultTable.Columns.Add(tc.ToString());
}
}

public void Initialize(IEnumerable<ICacheFactory> caches)
{
foreach (var c in caches)
{
c.DataRow = resultTable.NewRow();
c.DataRow["ThreadCount"] = c.Name;
}
}

public void CaptureRows(IEnumerable<ICacheFactory> caches)
{
foreach (var c in caches)
{
resultTable.Rows.Add(c.DataRow);
}
}

public void ExportCsv(Mode mode)
{
using (var textWriter = File.CreateText($"Results{mode}.csv"))
using (var csv = new CsvWriter(textWriter, CultureInfo.InvariantCulture))
{
foreach (DataColumn column in resultTable.Columns)
{
csv.WriteField(column.ColumnName);
}
csv.NextRecord();

foreach (DataRow row in resultTable.Rows)
{
for (var i = 0; i < resultTable.Columns.Count; i++)
{
csv.WriteField(row[i]);
}
csv.NextRecord();
}
}
}
}
}
5 changes: 3 additions & 2 deletions BitFaster.Caching.ThroughputAnalysis/MemoryCacheAdaptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ public MemoryCacheAdaptor(int capacity)

public ICollection<K> Keys => throw new NotImplementedException();

private static readonly MemoryCacheEntryOptions SizeOne = new MemoryCacheEntryOptions() { Size = 1 };

public void AddOrUpdate(K key, V value)
{
throw new NotImplementedException();
exMemoryCache.Set(key, value, SizeOne);
}

public void Clear()
Expand All @@ -48,7 +50,6 @@ public IEnumerator<KeyValuePair<K, V>> GetEnumerator()

public V GetOrAdd(K key, Func<K, V> valueFactory)
{

if (!exMemoryCache.TryGetValue(key, out object result))
{
using ICacheEntry entry = exMemoryCache.CreateEntry(key);
Expand Down
16 changes: 16 additions & 0 deletions BitFaster.Caching.ThroughputAnalysis/Mode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BitFaster.Caching.ThroughputAnalysis
{
public enum Mode
{
Read,
ReadWrite,
Evict,
Update,
}
}
43 changes: 43 additions & 0 deletions BitFaster.Caching.ThroughputAnalysis/ParallelBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace BitFaster.Caching.ThroughputAnalysis
{
public class ParallelBenchmark
{
public static TimeSpan Run(Action<int> action, int threads)
{
Task[] tasks = new Task[threads];
ManualResetEventSlim mre = new ManualResetEventSlim();

Action<int> syncStart = taskId =>
{
mre.Wait();
action(taskId);
};

for (int i = 0; i < tasks.Length; i++)
{
int index = i;
tasks[i] = Task.Factory.StartNew(() => syncStart(index), TaskCreationOptions.LongRunning);
}

// try to mitigate spam from MemoryCache
for (int i = 0; i < 3; i++)
{
GC.Collect();
}

var sw = Stopwatch.StartNew();
mre.Set();
Task.WaitAll(tasks);
return sw.Elapsed;
}
}
}
Loading