Created
November 18, 2016 16:25
-
-
Save Dissimilis/60598df31c01d7c5349848e5d416ead6 to your computer and use it in GitHub Desktop.
Simple circular buffer counter per time
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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