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

Remove char[] allocations from RegistryKey #66918

Merged
merged 2 commits into from
Jul 23, 2022

Conversation

stephentoub
Copy link
Member

Replace char[] allocations with stackalloc'd memory, or ArrayPool as a fallback if the size is too large.

I also noticed that the handler for REG_EXPAND_SZ was identical to the handler for REG_SZ save for one block, so I just collapsed the two and added an additional condition to that one block.

@ghost
Copy link

ghost commented Mar 21, 2022

Tagging subscribers to this area: @dotnet/area-microsoft-win32
See info in area-owners.md if you want to be subscribed.

Issue Details

Replace char[] allocations with stackalloc'd memory, or ArrayPool as a fallback if the size is too large.

I also noticed that the handler for REG_EXPAND_SZ was identical to the handler for REG_SZ save for one block, so I just collapsed the two and added an additional condition to that one block.

Author: stephentoub
Assignees: stephentoub
Labels:

area-Microsoft.Win32

Milestone: -

@stephentoub stephentoub added the tenet-performance Performance related issue label Mar 21, 2022
@stephentoub
Copy link
Member Author

stephentoub commented Mar 23, 2022

I rewrote InternalGetValueCore. It now starts with a stackalloc'd buffer, and if that's large enough, doesn't make any further calls. It also checks the return value of RegQueryValueEx for any calls it makes, and it removes a bunch of duplicated code.

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using Microsoft.Win32;

[MemoryDiagnoser]
public class Program
{
    static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);

    private static readonly RegistryKey s_netFramework = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\.NETFramework");
    private static readonly RegistryKey s_hardwareCurrent = Registry.LocalMachine.OpenSubKey(@"System\HardwareConfig\Current");

    [Benchmark] public string RegSz() => (string)s_netFramework.GetValue("InstallRoot");
    [Benchmark] public int RegDword() => (int)s_netFramework.GetValue("Enable64Bit");
    [Benchmark] public string[] RegMultiSz() => (string[])s_hardwareCurrent.GetValue("SystemBiosVersion");
}
Method Toolchain Mean Ratio Allocated
RegSz \main\corerun.exe 5.702 us 1.00 200 B
RegSz \pr\corerun.exe 2.949 us 0.52 96 B
RegDword \main\corerun.exe 5.495 us 1.00 24 B
RegDword \pr\corerun.exe 2.903 us 0.53 24 B
RegMultiSz \main\corerun.exe 5.930 us 1.00 368 B
RegMultiSz \pr\corerun.exe 3.102 us 0.52 256 B

@jkotas
Copy link
Member

jkotas commented Mar 23, 2022

Build breaks in CoreLib...

@stephentoub
Copy link
Member Author

Build breaks in CoreLib...

Ah, I'd searched for this file in *.csproj, forgot *.projitems.

@stephentoub stephentoub force-pushed the registryalloc branch 3 times, most recently from 04857b9 to 36d955d Compare March 23, 2022 22:08
Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@stephentoub stephentoub force-pushed the registryalloc branch 3 times, most recently from 12f8169 to f3fd756 Compare March 25, 2022 01:47
@stephentoub stephentoub force-pushed the registryalloc branch 3 times, most recently from 097bf82 to b14f724 Compare April 3, 2022 00:14
@danmoseley
Copy link
Member

@stephentoub are you still working on this one?

@stephentoub
Copy link
Member Author

are you still working on this one?

Yes.

@stephentoub stephentoub force-pushed the registryalloc branch 4 times, most recently from bbbf5d7 to 104caf3 Compare July 13, 2022 03:28
@stephentoub stephentoub force-pushed the registryalloc branch 3 times, most recently from ee4c949 to c509ede Compare July 22, 2022 17:49
Reduces typical number of syscalls as well as avoids allocation (or uses the ArrayPool otherwise).

Also updates Corelib's copy of RegistryKey to match (with things like perf key support removed).
@stephentoub
Copy link
Member Author

I believe I finally figured out the issues that were causing failures here; perf keys are special and have undocumented requirements (or at least requirements I couldn't find), like the input buffer has to be zero'd.

@jkotas, could you re-review?

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@stephentoub stephentoub merged commit cbfc549 into dotnet:main Jul 23, 2022
@stephentoub stephentoub deleted the registryalloc branch July 23, 2022 11:01
@ghost ghost locked as resolved and limited conversation to collaborators Aug 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants