Skip to content

Instantly share code, notes, and snippets.

@Dissimilis
Created November 18, 2016 16:25
Show Gist options
  • Save Dissimilis/60598df31c01d7c5349848e5d416ead6 to your computer and use it in GitHub Desktop.
Save Dissimilis/60598df31c01d7c5349848e5d416ead6 to your computer and use it in GitHub Desktop.
Simple circular buffer counter per time
/*
This is stripped version of https://gist.github.com/Dissimilis/b1e848524c841c1617b0
It is not thread safe to only some extent, but we don't care in this use case
*/
public class CircularBufferCounter
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct SecondCount
{
public SecondCount(long ticks, int count)
{
Ticks = ticks;
Count = count;
}
public int Count;
public long Ticks; //possibility to make this int32 and compress ticks
}
private readonly object _syncRoot = new object();
private SecondCount[] _buffer;
private int _head;
private int _tail;
private int _elementCount;
private int _granularityParts;
private long _capacity;
public CircularBufferCounter(TimeSpan period, int granularityParts = 10)
{
_capacity = period.Ticks;
_granularityParts = granularityParts;
_buffer = new SecondCount[granularityParts];
_head = granularityParts-1;
}
public void Increment()
{
var ticks = DateTime.UtcNow.Ticks;
if (_buffer[_head].Ticks / _granularityParts == ticks / _granularityParts)
{
Interlocked.Increment(ref _buffer[_head].Count);
}
else
{
lock (_syncRoot)
{
if (_buffer[_head].Ticks / _granularityParts != ticks / _granularityParts) //double check if head must advance
{
_head = (_head + 1) % _buffer.Length;
_buffer[_head] = new SecondCount(ticks, 1);
if (_elementCount == _buffer.Length)
_tail = (_tail + 1) % _buffer.Length;
else
++_elementCount;
}
}
}
}
public int Count()
{
int sum = 0;
long min = DateTime.UtcNow.Ticks - _capacity;
for (long i = 0; i < _elementCount; i++)
{
var item = this[i];
if (item.Ticks >= min)
sum += this[i].Count;
}
return sum;
}
private SecondCount this[long index]
{
get { return _buffer[(_tail + index) % _buffer.Length]; }
set { _buffer[(_tail + index) % _buffer.Length] = value; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment