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

Extract ConcurrentLfuCore with generic node and policy #520

Merged
merged 11 commits into from
Dec 3, 2023

Conversation

bitfaster
Copy link
Owner

@bitfaster bitfaster commented Dec 2, 2023

To prepare for time-based expiry in #516, add the extension points for different node type and policy.

Considerations:

  • Keep implementation details internal, only expose ConcurrentLfu
  • Since LfuNode is used extensively in arrays (buffers), ensure the array type is sealed to avoid array covariance check on write.
  • Preserve existing perf without any regression. Options are:
    • Make ConcurrentLfuCore a base class similar to ConcurrentLruCore core. This means that all types involved in the inheritance chain must be public, and the consumer sees all the messy generics.
    • Make ConcurrentLfuCore a class as a data member of ConcurrentLfu. This introduces another method call that appears to incur overhead even when inlnied.
    • Make ConcurrentLfuCore a mutable struct as a data member of ConcurrentLfu, so it is effectively embedded inside ConcurrentLfu. This means more weird tricks, but keeps a clean API for the consumer with all details internal. Later it can be switched to a more conventional approach if needed. This way it is possible to preserve perf and hide details.

Baseline

Method Runtime Mean Error Ratio
ConcurrentDictionary .NET 6.0 7.408 ns 0.0840 ns 1.00
ConcurrentLfuBackground .NET 6.0 25.191 ns 0.4176 ns 3.40
ConcurrentLfuForeround .NET 6.0 54.582 ns 0.1453 ns 7.37
ConcurrentLfuThreadPool .NET 6.0 52.433 ns 1.0606 ns 7.08
ConcurrentLfuNull .NET 6.0 22.916 ns 0.0724 ns 3.09
ConcurrentDictionary .NET Framework 4.8 13.660 ns 0.1253 ns 1.00
ConcurrentLfuBackground .NET Framework 4.8 53.615 ns 0.7679 ns 3.92
ConcurrentLfuForeround .NET Framework 4.8 85.688 ns 0.4863 ns 6.27
ConcurrentLfuThreadPool .NET Framework 4.8 53.179 ns 0.6894 ns 3.91
ConcurrentLfuNull .NET Framework 4.8 34.872 ns 0.0943 ns 2.56

Composition, class with inlined method:

Method Runtime Mean Error Ratio
ConcurrentDictionary .NET 6.0 7.674 ns 0.1271 ns 1.00
ConcurrentLfuBackground .NET 6.0 27.493 ns 0.5544 ns 3.56
ConcurrentLfuForeround .NET 6.0 56.669 ns 0.2408 ns 7.38
ConcurrentLfuThreadPool .NET 6.0 56.861 ns 1.0975 ns 7.46
ConcurrentLfuNull .NET 6.0 24.793 ns 0.1747 ns 3.23
ConcurrentDictionary .NET Framework 4.8 14.160 ns 0.0499 ns 1.00
ConcurrentLfuBackground .NET Framework 4.8 57.114 ns 0.5622 ns 4.03
ConcurrentLfuForeround .NET Framework 4.8 91.424 ns 0.2424 ns 6.46
ConcurrentLfuThreadPool .NET Framework 4.8 41.091 ns 0.5140 ns 2.90
ConcurrentLfuNull .NET Framework 4.8 36.338 ns 0.3480 ns 2.57

Composition, struct:

Method Runtime Mean Error Ratio
ConcurrentDictionary .NET 6.0 7.425 ns 0.0346 ns 1.00
ConcurrentLfuBackground .NET 6.0 25.875 ns 0.5423 ns 3.48
ConcurrentLfuForeround .NET 6.0 55.217 ns 0.1233 ns 7.44
ConcurrentLfuThreadPool .NET 6.0 46.655 ns 0.9456 ns 6.23
ConcurrentLfuNull .NET 6.0 24.009 ns 0.1620 ns 3.23
ConcurrentDictionary .NET Framework 4.8 13.654 ns 0.0517 ns 1.00
ConcurrentLfuBackground .NET Framework 4.8 53.155 ns 0.6734 ns 3.89
ConcurrentLfuForeround .NET Framework 4.8 91.844 ns 0.8469 ns 6.73
ConcurrentLfuThreadPool .NET Framework 4.8 55.283 ns 1.1236 ns 4.13
ConcurrentLfuNull .NET Framework 4.8 36.005 ns 0.4577 ns 2.64
Method Runtime Mean Error StdDev Ratio Allocated
ConcurrentDictionary .NET 6.0 7.946 ns 0.0697 ns 0.0652 ns 1.00 -
ConcurrentLfuBackground .NET 6.0 24.142 ns 0.5005 ns 0.4915 ns 3.04 -
ConcurrentLfuForeround .NET 6.0 55.121 ns 0.2244 ns 0.1989 ns 6.94 -
ConcurrentLfuThreadPool .NET 6.0 47.264 ns 0.3649 ns 0.3413 ns 5.95 -
ConcurrentLfuNull .NET 6.0 23.108 ns 0.0716 ns 0.0670 ns 2.91 -
ConcurrentDictionary .NET Framework 4.8 13.624 ns 0.1048 ns 0.0929 ns 1.00 -
ConcurrentLfuBackground .NET Framework 4.8 53.769 ns 0.9205 ns 0.8610 ns 3.95 -
ConcurrentLfuForeround .NET Framework 4.8 90.028 ns 0.5291 ns 0.4418 ns 6.61 -
ConcurrentLfuThreadPool .NET Framework 4.8 54.531 ns 1.1134 ns 2.0637 ns 4.17 -
ConcurrentLfuNull .NET Framework 4.8 37.841 ns 0.1223 ns 0.1144 ns 2.78 -

@coveralls
Copy link

coveralls commented Dec 2, 2023

Coverage Status

coverage: 99.177% (+0.03%) from 99.146%
when pulling cb8ce8d on users/alexpeck/genericnode
into fc969c8 on main.

@bitfaster bitfaster marked this pull request as ready for review December 3, 2023 05:20
@bitfaster bitfaster merged commit e3cddc7 into main Dec 3, 2023
18 checks passed
@bitfaster bitfaster deleted the users/alexpeck/genericnode branch December 5, 2023 08:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants