save progress

This commit is contained in:
StellaOps Bot
2026-01-06 09:42:02 +02:00
parent 94d68bee8b
commit 37e11918e0
443 changed files with 85863 additions and 897 deletions

View File

@@ -0,0 +1,89 @@
// <copyright file="ConcurrentHlcBenchmarks.cs" company="StellaOps">
// Copyright (c) StellaOps. Licensed under AGPL-3.0-or-later.
// </copyright>
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;
using Microsoft.Extensions.Time.Testing;
namespace StellaOps.HybridLogicalClock.Benchmarks;
/// <summary>
/// Benchmarks for concurrent HLC operations.
/// Measures thread contention and scalability under parallel access.
/// </summary>
[MemoryDiagnoser]
[SimpleJob(RunStrategy.Monitoring, iterationCount: 5)]
public class ConcurrentHlcBenchmarks
{
private HybridLogicalClock _clock = null!;
private InMemoryHlcStateStore _stateStore = null!;
private FakeTimeProvider _timeProvider = null!;
[Params(1, 2, 4, 8)]
public int ThreadCount { get; set; }
[GlobalSetup]
public void Setup()
{
_timeProvider = new FakeTimeProvider(DateTimeOffset.UtcNow);
_stateStore = new InMemoryHlcStateStore();
_clock = new HybridLogicalClock(
_timeProvider,
"concurrent-benchmark-node",
_stateStore);
// Initialize the clock
_ = _clock.Tick();
}
/// <summary>
/// Benchmark concurrent tick operations.
/// Each thread generates 1000 ticks; measures total throughput and contention.
/// </summary>
[Benchmark]
public void ConcurrentTicks_1000PerThread()
{
const int ticksPerThread = 1000;
Parallel.For(0, ThreadCount, threadIndex =>
{
for (int i = 0; i < ticksPerThread; i++)
{
_clock.Tick();
}
});
}
/// <summary>
/// Benchmark mixed concurrent operations (ticks and receives).
/// Simulates real-world distributed scenario.
/// </summary>
[Benchmark]
public void ConcurrentMixed_TicksAndReceives()
{
const int operationsPerThread = 500;
Parallel.For(0, ThreadCount, threadId =>
{
for (int i = 0; i < operationsPerThread; i++)
{
if (i % 3 == 0)
{
// Every third operation is a receive
var remote = new HlcTimestamp
{
PhysicalTime = _timeProvider.GetUtcNow().ToUnixTimeMilliseconds(),
NodeId = $"remote-node-{threadId}",
LogicalCounter = i
};
_clock.Receive(remote);
}
else
{
_clock.Tick();
}
}
});
}
}

View File

@@ -0,0 +1,104 @@
// <copyright file="HlcBenchmarks.cs" company="StellaOps">
// Copyright (c) StellaOps. Licensed under AGPL-3.0-or-later.
// </copyright>
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;
using Microsoft.Extensions.Time.Testing;
namespace StellaOps.HybridLogicalClock.Benchmarks;
/// <summary>
/// Benchmarks for Hybrid Logical Clock operations.
/// HLC-010: Measures tick throughput and memory allocation.
///
/// To run: dotnet run -c Release
/// </summary>
[MemoryDiagnoser]
[SimpleJob(RunStrategy.Throughput, iterationCount: 10)]
public class HlcBenchmarks
{
private HybridLogicalClock _clock = null!;
private InMemoryHlcStateStore _stateStore = null!;
private FakeTimeProvider _timeProvider = null!;
private HlcTimestamp _remoteTimestamp;
[GlobalSetup]
public void Setup()
{
_timeProvider = new FakeTimeProvider(DateTimeOffset.UtcNow);
_stateStore = new InMemoryHlcStateStore();
_clock = new HybridLogicalClock(
_timeProvider,
"benchmark-node-1",
_stateStore);
// Pre-initialize the clock
_ = _clock.Tick();
// Create a remote timestamp for Receive benchmarks
_remoteTimestamp = new HlcTimestamp
{
PhysicalTime = _timeProvider.GetUtcNow().ToUnixTimeMilliseconds(),
NodeId = "remote-node-1",
LogicalCounter = 5
};
}
/// <summary>
/// Benchmark single Tick operation throughput.
/// Measures the raw performance of generating a new HLC timestamp.
/// </summary>
[Benchmark(Baseline = true)]
public HlcTimestamp Tick()
{
return _clock.Tick();
}
/// <summary>
/// Benchmark Tick with time advancement.
/// Simulates real-world usage where physical time advances between ticks.
/// </summary>
[Benchmark]
public HlcTimestamp Tick_WithTimeAdvance()
{
_timeProvider.Advance(TimeSpan.FromMilliseconds(1));
return _clock.Tick();
}
/// <summary>
/// Benchmark Receive operation.
/// Measures performance of merging a remote timestamp.
/// </summary>
[Benchmark]
public HlcTimestamp Receive()
{
return _clock.Receive(_remoteTimestamp);
}
/// <summary>
/// Benchmark batch of 100 ticks.
/// Simulates high-throughput job scheduling scenarios.
/// </summary>
[Benchmark(OperationsPerInvoke = 100)]
public void Tick_Batch100()
{
for (int i = 0; i < 100; i++)
{
_ = _clock.Tick();
}
}
/// <summary>
/// Benchmark batch of 1000 ticks.
/// Stress test for very high throughput scenarios.
/// </summary>
[Benchmark(OperationsPerInvoke = 1000)]
public void Tick_Batch1000()
{
for (int i = 0; i < 1000; i++)
{
_ = _clock.Tick();
}
}
}

View File

@@ -0,0 +1,131 @@
// <copyright file="HlcTimestampBenchmarks.cs" company="StellaOps">
// Copyright (c) StellaOps. Licensed under AGPL-3.0-or-later.
// </copyright>
using System.Text.Json;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;
namespace StellaOps.HybridLogicalClock.Benchmarks;
/// <summary>
/// Benchmarks for HlcTimestamp operations.
/// Measures parsing, serialization, and comparison performance.
/// </summary>
[MemoryDiagnoser]
[SimpleJob(RunStrategy.Throughput, iterationCount: 10)]
public class HlcTimestampBenchmarks
{
private HlcTimestamp _timestamp;
private string _sortableString = null!;
private string _jsonString = null!;
private HlcTimestamp[] _timestamps = null!;
private static readonly JsonSerializerOptions JsonOptions = new();
[GlobalSetup]
public void Setup()
{
_timestamp = new HlcTimestamp
{
PhysicalTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
NodeId = "scheduler-east-1",
LogicalCounter = 42
};
_sortableString = _timestamp.ToSortableString();
_jsonString = JsonSerializer.Serialize(_timestamp, JsonOptions);
// Generate array of timestamps for sorting benchmark
_timestamps = new HlcTimestamp[1000];
var random = new Random(42);
for (int i = 0; i < _timestamps.Length; i++)
{
_timestamps[i] = new HlcTimestamp
{
PhysicalTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + random.Next(-1000, 1000),
NodeId = $"node-{random.Next(1, 10)}",
LogicalCounter = random.Next(0, 1000)
};
}
}
/// <summary>
/// Benchmark ToSortableString serialization.
/// </summary>
[Benchmark]
public string ToSortableString()
{
return _timestamp.ToSortableString();
}
/// <summary>
/// Benchmark Parse from sortable string.
/// </summary>
[Benchmark]
public HlcTimestamp Parse()
{
return HlcTimestamp.Parse(_sortableString);
}
/// <summary>
/// Benchmark TryParse from sortable string.
/// </summary>
[Benchmark]
public bool TryParse()
{
return HlcTimestamp.TryParse(_sortableString, out _);
}
/// <summary>
/// Benchmark full round-trip: serialize then parse.
/// </summary>
[Benchmark]
public HlcTimestamp RoundTrip()
{
var str = _timestamp.ToSortableString();
return HlcTimestamp.Parse(str);
}
/// <summary>
/// Benchmark JSON serialization.
/// </summary>
[Benchmark]
public string JsonSerialize()
{
return JsonSerializer.Serialize(_timestamp, JsonOptions);
}
/// <summary>
/// Benchmark JSON deserialization.
/// </summary>
[Benchmark]
public HlcTimestamp JsonDeserialize()
{
return JsonSerializer.Deserialize<HlcTimestamp>(_jsonString, JsonOptions);
}
/// <summary>
/// Benchmark CompareTo operation.
/// </summary>
[Benchmark]
public int CompareTo()
{
var other = new HlcTimestamp
{
PhysicalTime = _timestamp.PhysicalTime + 1,
NodeId = _timestamp.NodeId,
LogicalCounter = 0
};
return _timestamp.CompareTo(other);
}
/// <summary>
/// Benchmark sorting 1000 timestamps.
/// </summary>
[Benchmark]
public void Sort1000Timestamps()
{
var copy = (HlcTimestamp[])_timestamps.Clone();
Array.Sort(copy);
}
}

View File

@@ -0,0 +1,31 @@
// <copyright file="Program.cs" company="StellaOps">
// Copyright (c) StellaOps. Licensed under AGPL-3.0-or-later.
// </copyright>
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;
namespace StellaOps.HybridLogicalClock.Benchmarks;
/// <summary>
/// Entry point for HLC benchmarks.
/// </summary>
public static class Program
{
/// <summary>
/// Run benchmarks.
/// Usage:
/// dotnet run -c Release # Run all benchmarks
/// dotnet run -c Release --filter "Tick" # Run only Tick benchmarks
/// dotnet run -c Release --list flat # List available benchmarks
/// </summary>
public static void Main(string[] args)
{
var config = DefaultConfig.Instance
.WithOptions(ConfigOptions.DisableOptimizationsValidator);
BenchmarkSwitcher
.FromAssembly(typeof(Program).Assembly)
.Run(args, config);
}
}

View File

@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" />
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.HybridLogicalClock\StellaOps.HybridLogicalClock.csproj" />
</ItemGroup>
</Project>