I would like to solve the massive allocation costs of a c# application.
The application itself can be represented by the TickUser class at the bottom, and I'd like to know how to implement the TickStream object and the DoWork and ProcessTick methods to use allocation-free data.
using System;
using System.Collections.Generic;
namespace Ticks {
public interface ITick {
double Price { get; }
double Bid { get; }
double Ask { get; }
double Volume { get; }
DateTime TimeStamp { get; }
}
/// <summary>
/// Allows allocation-free creation of an <see cref="ITick"/>,
/// but is inefficient to pass from method to method because it is large.
/// </summary>
public readonly struct Tick : ITick {
public double Price { get; }
public double Bid { get; }
public double Ask { get; }
public double Volume { get; }
public DateTime TimeStamp { get; }
public Tick(double price, double bid, double ask, double volume, DateTime timeStamp) {
Price = price;
Bid = bid;
Ask = ask;
Volume = volume;
TimeStamp = timeStamp;
}
}
/// <summary>
/// Also allows allocation-free creation of an <see cref="ITick"/>,
/// but this is efficient to pass from method to method because it is small,
/// containing only a single pointer.
/// It requires a <see cref="Tick"/> to be created once and guaranteed "pinned" to a location on the stack.
/// </summary>
public unsafe readonly struct TickPointer : ITick {
readonly Tick* Ptr;
public double Price => Ptr->Price;
public double Bid => Ptr->Bid;
public double Ask => Ptr->Ask;
public double Volume => Ptr->Volume;
public DateTime TimeStamp => Ptr->TimeStamp;
public TickPointer(Tick* ptr) {
Ptr = ptr;
}
}
/// <summary>
/// Generates the data stream.
/// </summary>
public class TickStream {
/// <summary>
/// Typically returns hundreds of millions of <see cref="ITick"/> values.
/// To avoid massive allocation/deallocation costs, we want to yield objects that
/// can only exist on the stack.
/// </summary>
public IEnumerable<ITick> GetTicks() {
// How to implement??
}
}
public class TickUser {
public void DoWork() {
var stream = new TickStream();
foreach (var tick in stream.GetTicks()) {
ProcessTick(tick);
}
}
void ProcessTick(ITick tick) {
}
}
}
Inside the TickStream class, I'm ok with removing the IEnumerable<Tick> GetTicks() method and replacing it with the MoveNext() / Current { get; } / Current()pattern.
Perhaps ref readonly TickPointer Current()?
Ok, I figured it out and performed tests with a number of alternate scenarios. It turns out that creating the tick as a
ref readonly structgives best performance in all considerations if one is careful to always pass it around using theinparameter.Basic code
Tick stream code
Benchmarking code
Member access results (used to determine whether there accessing members via
TickPointeris too slow, show that its best not to use theTickPointeridea unless absolutely necessary)Allocation and passing around results (used to determine the best way to pass ticks from method to method as well as rapidly consume hundreds of millions of them from a stream without high allocations)
In summary, here is the best way I found to code the tick:
Here is the best way I found to code the stream:
Here is the best way that I found to consume the stream:
If you can show some ways to improve this code, please share!