Skip to content

Instantly share code, notes, and snippets.

@admir-live
Created May 21, 2024 18:21
Show Gist options
  • Save admir-live/db304653649bd55f5f4eebba3d29d537 to your computer and use it in GitHub Desktop.
Save admir-live/db304653649bd55f5f4eebba3d29d537 to your computer and use it in GitHub Desktop.
Object Pool Benchmark Results
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.ObjectPool;
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
[MemoryDiagnoser]
public class ObjectPoolBenchmarks
{
private ObjectPool<ReusableBuffer> _bufferPool;
private readonly string _sampleText = "The Test Text...";
[GlobalSetup]
public void Setup()
{
var services = new ServiceCollection();
services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
services.AddSingleton<ObjectPool<ReusableBuffer>>(serviceProvider =>
{
var provider = serviceProvider.GetRequiredService<ObjectPoolProvider>();
var policy = new DefaultPooledObjectPolicy<ReusableBuffer>();
return provider.Create(policy);
});
var serviceProvider = services.BuildServiceProvider();
_bufferPool = serviceProvider.GetRequiredService<ObjectPool<ReusableBuffer>>();
}
[Benchmark]
public string ComputeHashWithoutPooling()
{
var buffer = new byte[1024 * 1024]; // 1 MB
for (var i = 0; i < _sampleText.Length; i++)
{
buffer[i] = (byte)_sampleText[i];
}
Span<byte> hash = stackalloc byte[32];
SHA256.HashData(buffer.AsSpan(0, _sampleText.Length), hash);
return Convert.ToHexString(hash);
}
[Benchmark]
public string ComputeHashWithPooling()
{
var buffer = _bufferPool.Get();
try
{
for (var i = 0; i < _sampleText.Length; i++)
{
buffer.Data[i] = (byte)_sampleText[i];
}
Span<byte> hash = stackalloc byte[32];
SHA256.HashData(buffer.Data.AsSpan(0, _sampleText.Length), hash);
return Convert.ToHexString(hash);
}
finally
{
_bufferPool.Return(buffer);
}
}
}
public class ReusableBuffer : IResettable
{
public byte[] Data { get; } = new byte[1024 * 1024];
public bool TryReset()
{
Array.Clear(Data);
return true;
}
}
public class Program
{
public static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<ObjectPoolBenchmarks>();
}
}
@admir-live
Copy link
Author

Object Pool Benchmark Results

Overview

This benchmark compares the performance of computing SHA256 hashes with and without using an object pool for buffer reuse. The objective is to measure the time taken and memory allocated for each method.

Benchmark Setup

  • Buffer Size: 1 MB
  • Sample Text: "BenchmarkDotNetSampleText"
  • Hash Algorithm: SHA256
  • Object Pool: ObjectPool<ReusableBuffer>

Methods

  1. ComputeHashWithoutPooling:

    • Allocates a new 1 MB buffer each time.
    • Computes the SHA256 hash.
  2. ComputeHashWithPooling:

    • Uses an object pool to reuse a 1 MB buffer.
    • Computes the SHA256 hash.
    • Returns the buffer to the pool after use.

Results

Method Mean (us) Error (us) StdDev (us) Gen0 Gen1 Gen2 Allocated (B)
ComputeHashWithoutPooling 21.51 0.406 0.417 333.3130 333.3130 333.3130 1048862
ComputeHashWithPooling 11.63 0.168 0.157 0.0153 - - 152

Key Takeaways

  • Performance:

    • With Pooling: Faster (11.63 us)
    • Without Pooling: Slower (21.51 us)
  • Memory Allocation:

    • With Pooling: Significantly lower (152 B)
    • Without Pooling: Much higher (1048862 B)

Conclusion

Using an object pool for buffer reuse greatly improves performance and reduces memory allocation. This is beneficial for scenarios where large buffers are frequently needed and can be reused, leading to more efficient resource utilization.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment