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

Add cached boxed boolean values to BooleanType #3230

Merged
merged 3 commits into from
Feb 13, 2023

Conversation

wilbit
Copy link
Contributor

@wilbit wilbit commented Feb 6, 2023

Problem

In one of our app we use a long lived NHibernate session. I know that is not by the design of NHibernate, but anyway.
Just when the app is started, it creates a lot of objects in Heap, one of the biggest (by number of object) allocations is "boxed booleans", created by BooleanType.Get (around ~300k of objects, ~6.87MB).
The only related discussion I have found is #2187

PR description

BooleanType contains pre-boxed true/false values, and returns them instead of boxing of booleans each time.
It is:

  • faster (benchmarks are below);
  • allocates no memory.

Benchmarks

BenchmarkDotNet=v0.13.4, OS=Windows 11 (10.0.22621.1105)
AMD Ryzen 7 5700U with Radeon Graphics, 1 CPU, 16 logical and 8 physical cores
[Host] : .NET Framework 4.8.1 (4.8.9105.0), X64 RyuJIT VectorSize=256
.NET 6.0 : .NET 6.0.13 (6.0.1322.58009), X64 RyuJIT AVX2
.NET 7.0 : .NET 7.0.2 (7.0.222.60605), X64 RyuJIT AVX2
.NET Framework 4.8 : .NET Framework 4.8.1 (4.8.9105.0), X64 RyuJIT VectorSize=256

Method Job Runtime Value Mean Error StdDev Ratio Gen0 Allocated Alloc Ratio
BoxAnReturn .NET 6.0 .NET 6.0 False 2.0651 ns 0.0246 ns 0.0218 ns 1.00 0.0115 24 B 1.00
ReturnCached .NET 6.0 .NET 6.0 False 0.4737 ns 0.0112 ns 0.0104 ns 0.23 - - 0.00
BoxAnReturn .NET 7.0 .NET 7.0 False 3.4490 ns 0.0274 ns 0.0257 ns 1.00 0.0115 24 B 1.00
ReturnCached .NET 7.0 .NET 7.0 False 1.1805 ns 0.0114 ns 0.0106 ns 0.34 - - 0.00
BoxAnReturn .NET Framework 4.8 .NET Framework 4.8 False 2.1046 ns 0.0632 ns 0.0560 ns 1.00 0.0115 24 B 1.00
ReturnCached .NET Framework 4.8 .NET Framework 4.8 False 0.2624 ns 0.0057 ns 0.0054 ns 0.12 - - 0.00
BoxAnReturn .NET 6.0 .NET 6.0 True 1.9441 ns 0.0284 ns 0.0266 ns 1.00 0.0115 24 B 1.00
ReturnCached .NET 6.0 .NET 6.0 True 0.2446 ns 0.0083 ns 0.0078 ns 0.13 - - 0.00
BoxAnReturn .NET 7.0 .NET 7.0 True 3.4946 ns 0.0377 ns 0.0504 ns 1.00 0.0115 24 B 1.00
ReturnCached .NET 7.0 .NET 7.0 True 0.9321 ns 0.0470 ns 0.0367 ns 0.27 - - 0.00
BoxAnReturn .NET Framework 4.8 .NET Framework 4.8 True 2.1148 ns 0.0522 ns 0.0463 ns 1.00 0.0115 24 B 1.00
ReturnCached .NET Framework 4.8 .NET Framework 4.8 True 0.2691 ns 0.0096 ns 0.0090 ns 0.13 - - 0.00

Benchmark code

Program.cs
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;

namespace TestBoxing
{
    public static class Program
    {
        public static void Main()
        {
            BenchmarkRunner.Run<Boxing>();
        }
    }

    [SimpleJob(RuntimeMoniker.Net48)]
    [SimpleJob(RuntimeMoniker.Net60)]
    [SimpleJob(RuntimeMoniker.Net70)]
    [MemoryDiagnoser]
    public class Boxing
    {
        private static readonly object TrueObject = true;
        private static readonly object FalseObject = false;

        [Params(true, false)]
        public bool Value;

        [Benchmark(Baseline = true)]
        public object BoxAnReturn()
        {
            return Value;
        }

        [Benchmark]
        public object ReturnCached()
        {
            return GetBooleanAsObject(Value);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static object GetBooleanAsObject(bool value)
        {
            return value ? TrueObject : FalseObject;
        }
    }
}
csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworks>net48;net6.0;net7.0</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="BenchmarkDotNet" Version="0.13.4" />
  </ItemGroup>

</Project>

@wilbit wilbit changed the title added cached boxed boolean values to BooleanType WIP added cached boxed boolean values to BooleanType Feb 6, 2023
@wilbit wilbit force-pushed the cache-boxed-booleans branch from a4b00bc to 7c9539f Compare February 6, 2023 11:01
@wilbit wilbit changed the title WIP added cached boxed boolean values to BooleanType added cached boxed boolean values to BooleanType Feb 6, 2023
@wilbit wilbit force-pushed the cache-boxed-booleans branch from 7c9539f to 288d978 Compare February 6, 2023 11:05
@wilbit
Copy link
Contributor Author

wilbit commented Feb 6, 2023

Do I need to do with the failed "Generate Async code" check?
I don't see any mentions of nhibernate-bot in CONTRIBUTING.md.
Intrigma/nhibernate-core is a public fork. Where is a problem?

@bahusoid
Copy link
Member

bahusoid commented Feb 6, 2023

failed "Generate Async code" check

You need to enable Allow edits and access to secrets by maintainers in your PR

@wilbit
Copy link
Contributor Author

wilbit commented Feb 6, 2023

Thanks for pointing me to the right direction, @bahusoid .
But I'm afraid I don't see such option in PR, and the documentation does not explain why. I guess it is because my fork is created under organization account, not personal.

@wilbit
Copy link
Contributor Author

wilbit commented Feb 6, 2023

I have generated async files locally.

@fredericDelaporte
Copy link
Member

Here is how the option appears on my side. That is the bottom most checkbox.
image

@wilbit
Copy link
Contributor Author

wilbit commented Feb 6, 2023

Thanks, @fredericDelaporte, I have seen how it should look like in the documentation.
But that's how it looks like on my side =)

Screenshot

image

@wilbit wilbit force-pushed the cache-boxed-booleans branch from 25fb45c to 3ff4371 Compare February 7, 2023 11:28
@wilbit wilbit force-pushed the cache-boxed-booleans branch from 3ff4371 to 166ec54 Compare February 9, 2023 06:04
@bahusoid bahusoid merged commit f560f7d into nhibernate:master Feb 13, 2023
@wilbit wilbit deleted the cache-boxed-booleans branch February 13, 2023 13:04
@fredericDelaporte fredericDelaporte added this to the 5.5 milestone Feb 15, 2023
@fredericDelaporte fredericDelaporte changed the title added cached boxed boolean values to BooleanType Add cached boxed boolean values to BooleanType Feb 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants