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 struct
gives best performance in all considerations if one is careful to always pass it around using thein
parameter.Basic code
Tick stream code
Benchmarking code
Member access results (used to determine whether there accessing members via
TickPointer
is too slow, show that its best not to use theTickPointer
idea 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!