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

Special-case Dictionary for string keys #99990

Closed
wants to merge 1 commit into from

Conversation

EgorBo
Copy link
Member

@EgorBo EgorBo commented Mar 20, 2024

Just an experiment. I see FindValue way too often in various perf traces and considering that string is, probably, the most popular key type (among ref types), maybe we can special case it? It gives us:

  1. We can inline the hash code function
  2. We can inline the string compare function (when hash matches)
  3. Maybe we can even intrinsify hashcode for known string literals?

Currently PGO can't devirtualize anything inside FindValue due to known limitations.

In my benchmarks this improves Lookup (indexer/TryGetValue) by 30%

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 20, 2024
@EgorBo
Copy link
Member Author

EgorBo commented Mar 20, 2024

@EgorBot

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkSwitcher.FromAssembly(typeof(MyBench).Assembly).Run(args);

public class MyBench
{
    Dictionary<string, int> _d = Enumerable
        .Range(1000, 1000)
        .ToDictionary(i => i.ToString(), i => i);

    [Benchmark]
    public int Indexer() => _d["1500"];

    [Benchmark]
    public bool TryGetValue() => _d.TryGetValue("1500", out _);
}

@EgorBot
Copy link

EgorBot commented Mar 20, 2024

@EgorBo

BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 8.0.203
  [Host]     : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
  Job-QOAUUT : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
  Job-FRDIAS : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Method Toolchain Mean Ratio
Indexer /Main/corerun 14.29 ns 1.00
Indexer /PR/corerun 10.09 ns 0.71
TryGetValue /Main/corerun 13.34 ns 1.00
TryGetValue /PR/corerun 10.28 ns 0.77

@huoyaoyuan
Copy link
Member

Maybe more fundamentally, can we do limited generic specialization for reference types? Or in contrast, can we use shared generic for value types with same size?

JIT shouldn't automatically do that without any instruction. Have the capability would be nice.

@EgorBo
Copy link
Member Author

EgorBo commented Mar 20, 2024

Maybe more fundamentally, can we do limited generic specialization for reference types?

This will require a ton of work in runtime in various of its places, there are some related proposals like #9682

@EgorBo
Copy link
Member Author

EgorBo commented Mar 20, 2024

With the current shape we see +30% perf for lookup for the default case (when it's not yet switched to randomized hashing), but other types of comparers (e.g. OrdinalIgnoreCase or custom) will recieve a small penalty (type check for comparer) so not sure if it's worth duplicating code for them as well.

@EgorBo EgorBo closed this Mar 20, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Apr 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants