Skip to content

Commit b62af9b

Browse files
authored
Update README.md
1 parent 477da40 commit b62af9b

File tree

1 file changed

+6
-27
lines changed

1 file changed

+6
-27
lines changed

README.md

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -199,13 +199,11 @@ FastConcurrentLru does not allocate and is approximately 10x faster than System.
199199
| RuntimeMemoryCache | 280.16 ns | 5.607 ns | 7.486 ns | 16.59 | 0.0153 | 32 B |
200200
| ExtensionsMemoryCache | 342.72 ns | 3.729 ns | 3.114 ns | 20.29 | 0.0114 | 24 B |
201201

202-
## Meta-programming using structs for JIT dead code removal and inlining
202+
## Meta-programming using structs and JIT value type optimization
203203

204-
TemplateConcurrentLru features injectable policies defined as structs. Since structs are subject to special JIT optimizations, the implementation is much faster than if these policies were defined as classes. Using this technique, 'Fast' versions without hit counting are within 30% of the speed of a ConcurrentDictionary.
204+
TemplateConcurrentLru features injectable behaviors defined as structs. Structs are subject to special JIT optimizations, and the .NET JIT compiler can inline, eliminate dead code and propogate JIT time constants based on structs. Using this technique, the TemplateConcurrentLru can be customized to support LRU and TLRU policies without compromising execution speed.
205205

206-
Since DateTime.UtcNow is around 4x slower than a ConcurrentDictionary lookup, policies that involve time based expiry are significantly slower. Since these are injected as structs and the slow code is optimized away, it is possible maintain the fastest possible speed for the non-TTL policy.
207-
208-
### TemplateConcurrentLru.TryGet
206+
### Example: TemplateConcurrentLru.TryGet
209207

210208
This is the source code for the TryGet method. It calls into two value type generic type arguments: policy (1) and hitcounter (2).
211209

@@ -236,7 +234,7 @@ public bool TryGet(K key, out V value)
236234

237235
### FastConcurrentLru (LruPolicy & NullHitCounter)
238236

239-
LruPolicy is hardcoded to never discard items, so the branch and subsequent code for ShouldDiscard are completely eliminated by JIT (1).
237+
The LruPolicy used by FastConcurrentLru/ConcurrentLru is hardcoded to never discard items.
240238

241239
```csharp
242240
public readonly struct LruPolicy<K, V> : IPolicy<K, V, LruItem<K, V>>
@@ -251,26 +249,7 @@ LruPolicy is hardcoded to never discard items, so the branch and subsequent code
251249
}
252250
```
253251

254-
Hit count methods are no-op, so are completely eliminated by the jit (2).
255-
256-
```csharp
257-
public struct NullHitCounter : IHitCounter
258-
{
259-
public double HitRatio => 0.0;
260-
261-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
262-
public void IncrementMiss()
263-
{
264-
}
265-
266-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
267-
public void IncrementHit()
268-
{
269-
}
270-
}
271-
```
272-
273-
The JITted assembly code for the TryGet method with these value type implementations is 76 bytes:
252+
The branch and enclosed code for ShouldDiscard are completely eliminated by JIT (1). Since the below code is from FastConcurrentLru, the hit counting calls (2) are also eliminated. The assembly code for the FastConcurrentLru.TryGet method with LruPolicy and NullHitCounter is 76 bytes:
274253

275254
```assembly
276255
; BitFaster.Caching.Lru.TemplateConcurrentLru`5[[System.Int32, System.Private.CoreLib],[System.Int32, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[BitFaster.Caching.Lru.LruPolicy`2[[System.Int32, System.Private.CoreLib],[System.Int32, System.Private.CoreLib]], BitFaster.Caching],[BitFaster.Caching.Lru.NullHitCounter, BitFaster.Caching]].TryGet(Int32, Int32 ByRef)
@@ -305,7 +284,7 @@ M01_L00:
305284

306285
### FastConcurrentTLru (TLruLongTicksPolicy & NullHitCounter)
307286

308-
The policy for TLru can expire items, so the branch 2 is not eliminated.
287+
The struct TLruLongTicksPolicy used in FastConcurrentTLru can expire items.
309288

310289
```csharp
311290
public readonly struct TLruLongTicksPolicy<K, V> : IPolicy<K, V, LongTickCountLruItem<K, V>>

0 commit comments

Comments
 (0)