Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Array sampling, object pooling & more #10

Merged
merged 12 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2023 Christian Klutz
Copyright (c) 2024 Christian Klutz

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
41 changes: 41 additions & 0 deletions src/ManagedObjectSize.Benchmarks/ArraySamplingBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnostics.Windows.Configs;

namespace ManagedObjectSize.Benchmarks
{
[MemoryDiagnoser, EtwProfiler]
public class ArraySamplingBenchmarks
{
[Params(20, 100)] public int N;

private GraphObject m_graphData = null!;
private int[] m_intData = null!;
private string[] m_stringData = null!;

private ObjectSizeOptions m_samplingOptions = null!;

[GlobalSetup]
public void GlobalSetup()
{
m_graphData = GraphObject.CreateObjectGraph(N);
m_intData = new int[N];
m_stringData = new string[N];

for (int i = 0; i < N; i++)
{
m_intData[i] = i;
m_stringData[i] = "string#" + i;
}

m_samplingOptions = new() { ArraySampleCount = N / 10 };
}

[Benchmark] public long NoSampling_Int32() => ObjectSize.GetObjectInclusiveSize(m_intData);
[Benchmark] public long NoSampling_String() => ObjectSize.GetObjectInclusiveSize(m_stringData);
[Benchmark] public long NoSampling_Graph() => ObjectSize.GetObjectInclusiveSize(m_graphData);

[Benchmark] public long Sampling_Int32() => ObjectSize.GetObjectInclusiveSize(m_intData, m_samplingOptions);
[Benchmark] public long Sampling_String() => ObjectSize.GetObjectInclusiveSize(m_stringData, m_samplingOptions);
[Benchmark] public long Sampling_Graph() => ObjectSize.GetObjectInclusiveSize(m_graphData, m_samplingOptions);
}
}
50 changes: 50 additions & 0 deletions src/ManagedObjectSize.Benchmarks/GraphData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
namespace ManagedObjectSize.Benchmarks
{
internal class GraphObject
{
public static GraphObject CreateObjectGraph(int num, bool inner = false)
{
var graph = new GraphObject
{
ListField = new List<GraphNodeObject>(num)
};

int digits = (int)Math.Log10(num) + 1;
var options = new ParallelOptions { MaxDegreeOfParallelism = (inner || num < 100) ? 1 : Environment.ProcessorCount };
Parallel.For(0, num, options,
() => new List<GraphNodeObject>(),
(i, state, local) =>
{
var node = new GraphNodeObject { StringField = "Node#" };
if (!inner)
{
node.ObjectField = CreateObjectGraph(100, true);
}
local.Add(node);
return local;
},
local =>
{
lock (graph.ListField)
{
graph.ListField.AddRange(local);
}
});

return graph;
}

#pragma warning disable CS0649

public int IntField;
public List<GraphNodeObject> ListField = null!;

public class GraphNodeObject
{
public double DoubleField;
public int IntField;
public string StringField = null!;
public GraphObject ObjectField = null!;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.13.12" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ManagedObjectSize.ObjectPool\ManagedObjectSize.ObjectPool.csproj" />
<ProjectReference Include="..\ManagedObjectSize\ManagedObjectSize.csproj" />
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions src/ManagedObjectSize.Benchmarks/ObjectPoolBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using BenchmarkDotNet.Attributes;
using ManagedObjectSize.ObjectPool;

namespace ManagedObjectSize.Benchmarks
{
[MemoryDiagnoser]
public class ObjectPoolBenchmarks
{
[Params(100, 1000)] public int N;

private GraphObject m_graphData = null!;
private ObjectSizeOptions m_options = null!;

[GlobalSetup]
public void GlobalSetup()
{
m_graphData = GraphObject.CreateObjectGraph(N);
m_options = new ObjectSizeOptions().UseMicrosoftExtensionsObjectPool();
}

[Benchmark] public long NoPool() => ObjectSize.GetObjectInclusiveSize(m_graphData);

[Benchmark] public long Pool() => ObjectSize.GetObjectInclusiveSize(m_graphData, m_options);
}
}
15 changes: 15 additions & 0 deletions src/ManagedObjectSize.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;

namespace ManagedObjectSize.Benchmarks
{
internal class Program
{
public static void Main(string[] args)
{
var xargs = new List<string>(args);
var config = ManualConfig.Create(DefaultConfig.Instance);
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(xargs.ToArray(), config);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>

<IsPackable>true</IsPackable>
<PackageId>ManagedObjectSize.ObjectPool</PackageId>
<Version>0.0.6</Version>
<Authors>Christian Klutz</Authors>
<Description>
Adapts Microsoft.Extensions.ObjectPool to be used with ManagedObjectSize package.
</Description>
<InformationalVersion>$(Version).0</InformationalVersion>
<FileVersion>$(Version).0</FileVersion>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<RepositoryUrl>https://github.com/cklutz/ManagedObjectSize</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>

<ItemGroup>
<None Include="..\..\LICENSE.txt" Link="LICENSE.txt">
<PackagePath>\</PackagePath>
<Pack>true</Pack>
</None>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ManagedObjectSize\ManagedObjectSize.csproj" />
</ItemGroup>


<ItemGroup>
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="8.0.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using ManagedObjectSize.Pooling;
using Microsoft.Extensions.ObjectPool;

namespace ManagedObjectSize.ObjectPool
{
/// <summary>
/// Adapts a <see cref="Microsoft.Extensions.ObjectPool.ObjectPool"/> to be used
/// as <see cref="ObjectSizeOptions.PoolProvider"/>.
/// </summary>
public class MicrosoftExtensionsObjectPoolPoolProvider : PoolProvider
{
private class PolicyAdapter<T> : IPooledObjectPolicy<T> where T : notnull
{
private readonly IPoolPolicy<T> m_policy;
public PolicyAdapter(IPoolPolicy<T> policy) => m_policy = policy;
public T Create() => m_policy.Create();
public bool Return(T obj) => m_policy.Return(obj);
}

private class PoolAdapter<T> : Pool<T> where T : class
{
private readonly ObjectPool<T> m_pool;
public PoolAdapter(ObjectPool<T> pool) => m_pool = pool;
public override T Get() => m_pool.Get();
public override void Return(T obj) => m_pool.Return(obj);
}

private readonly ObjectPoolProvider m_provider;

public MicrosoftExtensionsObjectPoolPoolProvider()
: this(new DefaultObjectPoolProvider())
{
}

public MicrosoftExtensionsObjectPoolPoolProvider(ObjectPoolProvider objectPoolProvider)
{
m_provider = objectPoolProvider ?? throw new ArgumentNullException(nameof(objectPoolProvider));
}

public override Pool<T> Create<T>(IPoolPolicy<T> policy)
{
return new PoolAdapter<T>(m_provider.Create(new PolicyAdapter<T>(policy)));
}
}
}
28 changes: 28 additions & 0 deletions src/ManagedObjectSize.ObjectPool/ObjectPoolExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Microsoft.Extensions.ObjectPool;

namespace ManagedObjectSize.ObjectPool
{
public static class ObjectPoolExtensions
{
/// <summary>
/// Configures <see cref="ObjectSizeOptions"/> to use an object pool based on <see cref="ObjectPoolProvider"/>.
/// </summary>
/// <param name="options">The options instance.</param>
/// <param name="provider">
/// The <see cref="ObjectPoolProvider"/> to be used. If <c>null</c>, an instance of the <see cref="DefaultObjectPoolProvider"/> will be used.</param>
/// <returns>The options instanced given as <paramref name="options"/>.</returns>
public static ObjectSizeOptions UseMicrosoftExtensionsObjectPool(this ObjectSizeOptions options, ObjectPoolProvider? provider = null)
{
if (provider == null)
{
options.PoolProvider = new MicrosoftExtensionsObjectPoolPoolProvider();
}
else
{
options.PoolProvider = new MicrosoftExtensionsObjectPoolPoolProvider(provider);
}

return options;
}
}
}
3 changes: 2 additions & 1 deletion src/ManagedObjectSize.Tests/ManagedObjectSize.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Diagnostics.Runtime.Utilities" Version="2.3.405501" />
<PackageReference Include="Microsoft.Diagnostics.Runtime.Utilities" Version="3.0.442202" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
Expand All @@ -19,6 +19,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ManagedObjectSize.ObjectPool\ManagedObjectSize.ObjectPool.csproj" />
<ProjectReference Include="..\ManagedObjectSize\ManagedObjectSize.csproj" />
</ItemGroup>

Expand Down
19 changes: 19 additions & 0 deletions src/ManagedObjectSize.Tests/ObjectSizeOptionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;

namespace ManagedObjectSize.Tests
{
[TestClass]
public class ObjectSizeOptionsTests
{
[DataTestMethod]
[DataRow(0.95, 5, 100, 80)]
[DataRow(0.99, 5, 100, 87)]
[DataRow(0.95, 5, 100_000_000, 384)]
[DataRow(0.99, 5, 100_000_000, 663)]
public void CalculateSampleCount(double confidenceLevel, int confidenceInterval, int populationSize, int expectedSampleSize)
{
int actualSampleSize = Utils.CalculateSampleCount(confidenceLevel, confidenceInterval, populationSize);
Assert.AreEqual(expectedSampleSize, actualSampleSize);
}
}
}
Loading
Loading