Skip to content

Instantly share code, notes, and snippets.

@tsvx
Last active January 24, 2017 12:32
Show Gist options
  • Save tsvx/5861b47719b6535d7f8520d05c1ceffb to your computer and use it in GitHub Desktop.
Save tsvx/5861b47719b6535d7f8520d05c1ceffb to your computer and use it in GitHub Desktop.
Measure accumulator implementations on .NET 4
using System;
using System.Linq;
using System.Diagnostics;
using System.Collections.Concurrent;
using System.Collections.Generic;
public interface IAccum
{
IEnumerable<int> Keys { get; }
void Inc(int key);
int this[int key] { get; set; }
}
public class DummyAccum : IAccum
{
public DummyAccum() {}
public IEnumerable<int> Keys { get { yield break; } }
public void Inc(int key) {}
public int this[int key] {
get { return 0; }
set {}
}
}
public class ArrayAccum : IAccum
{
int[] arr;
public ArrayAccum(int max) { arr = new int[max]; }
public IEnumerable<int> Keys { get { return arr.Select((v,i) => new KeyValuePair<int,int>(i,v)).Where(p => p.Value > 0).Select(p => p.Key); } }
public void Inc(int key) {
arr[key]++;
}
public int this[int key] {
get {
return arr[key];
}
set {
arr[key]=value;
}
}
}
public class DictionaryAccum : Dictionary<int, int>, IAccum
{
public DictionaryAccum() { }
new public IEnumerable<int> Keys { get { return base.Keys; } }
public void Inc(int key) {
int val;
this.TryGetValue(key, out val);
this[key] = val+1;
}
}
public class DictionaryAccum2 : Dictionary<int, int>, IAccum
{
public DictionaryAccum2() { }
new public IEnumerable<int> Keys { get { return base.Keys; } }
public void Inc(int key) {
if (this.ContainsKey(key))
this[key]++;
else
this[key] = 1;
}
}
public class SortedDictionaryAccum : SortedDictionary<int, int>, IAccum
{
public SortedDictionaryAccum() { }
new public IEnumerable<int> Keys { get { return base.Keys; } }
public void Inc(int key) {
int val;
this.TryGetValue(key, out val);
this[key] = val+1;
}
}
public class ConcurrentDictionaryAccum : ConcurrentDictionary<int, int>, IAccum
{
public ConcurrentDictionaryAccum() { }
new public IEnumerable<int> Keys { get { return base.Keys; } }
public void Inc(int key) {
this.AddOrUpdate(key, 1, (k,v) => v+1);
}
}
static class Proga
{
const int N = 10000000, maxKey=1000;
static void TestAnAccum(IAccum acc)
{
Console.Write("Testing {0,25} ...", acc);
Stopwatch sw = Stopwatch.StartNew();
for (int i=0; i<N; i++)
acc.Inc(i % maxKey);
sw.Stop();
Console.WriteLine(" {0,4} keys, sum {1,8}, {2,6:F2} ns/inc",
acc.Keys.Count(), acc.Keys.Sum(i => acc[i]), sw.Elapsed.TotalMilliseconds*1e6/N);
}
static void Main()
{
TestAnAccum(new DummyAccum());
TestAnAccum(new ArrayAccum(maxKey));
TestAnAccum(new DictionaryAccum());
TestAnAccum(new DictionaryAccum2());
TestAnAccum(new SortedDictionaryAccum());
TestAnAccum(new ConcurrentDictionaryAccum());
}
}

Results on Win7x64 Intel Core i5-3470 3.2GHz

(several runs, accuracy turned out to be \pm 1ns)

Debug

Testing                DummyAccum ...    0 keys, sum        0,   7,14 ns/inc
Testing                ArrayAccum ... 1000 keys, sum 10000000,  11,55 ns/inc
Testing           DictionaryAccum ... 1000 keys, sum 10000000,  32,60 ns/inc
Testing          DictionaryAccum2 ... 1000 keys, sum 10000000,  53,74 ns/inc
Testing     SortedDictionaryAccum ... 1000 keys, sum 10000000, 195,82 ns/inc
Testing ConcurrentDictionaryAccum ... 1000 keys, sum 10000000,  96,96 ns/inc

Release

Testing                DummyAccum ...    0 keys, sum        0,   4,05 ns/inc
Testing                ArrayAccum ... 1000 keys, sum 10000000,   4,86 ns/inc
Testing           DictionaryAccum ... 1000 keys, sum 10000000,  30,03 ns/inc
Testing          DictionaryAccum2 ... 1000 keys, sum 10000000,  39,89 ns/inc
Testing     SortedDictionaryAccum ... 1000 keys, sum 10000000, 194,98 ns/inc
Testing ConcurrentDictionaryAccum ... 1000 keys, sum 10000000,  82,29 ns/inc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment