-
Notifications
You must be signed in to change notification settings - Fork 318
UTF8 caching for v0.4 #9434
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
UTF8 caching for v0.4 #9434
Conversation
This change adds UTF-8 encoding caching to optimize v0.4 payload construction. Since String#getBytes is intrinsified these caches actually perform worse throughput wise than an uncached conversion. However, the caches are useful in reducing allocation from UTF-8 conversions. For tags, a "simple" cache is used. The simple cache is a single level cache -- that uses hashing combined with linear probing. To avoid, cache churn and unnecessary allocation of a CacheEntry, the simple cache uses a first request marking scheme that typically avoids creating a CacheEntry for values that are requested only once. Eviction from the "simple" cache is done based on LFU policy. For tag values, a more complicated generational cache is used. The generational cache combines the delayed CacheEntry logic of the simple cache with a 2nd-level for resilience. Frequently used entries are "promoted" to the higher level cache. The 1st level of the generational cache uses a LFU eviction policy. The 2nd of the generational cache uses a LRU eviction policy. For the value use cache, the generational policy provided 2x increase in hit rate over the simple cache.
|
Hi! 👋 Thanks for your pull request! 🎉 To help us review it, please make sure to:
If you need help, please check our contributing guidelines. |
|
🎯 Code Coverage 🔗 Commit SHA: c923194 | Docs | Was this helpful? Give us feedback! |
BenchmarksStartupParameters
See matching parameters
SummaryFound 0 performance improvements and 0 performance regressions! Performance is the same for 48 metrics, 11 unstable metrics. Startup time reports for insecure-bankgantt
title insecure-bank - global startup overhead: candidate=1.53.0-SNAPSHOT~c923194dea, baseline=1.54.0-SNAPSHOT~cb08250ba1
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.049 s) : 0, 1049365
Total [baseline] (8.64 s) : 0, 8640041
Agent [candidate] (1.049 s) : 0, 1049146
Total [candidate] (8.622 s) : 0, 8622132
section iast
Agent [baseline] (1.181 s) : 0, 1180887
Total [baseline] (9.376 s) : 0, 9376388
Agent [candidate] (1.179 s) : 0, 1179162
Total [candidate] (9.345 s) : 0, 9344784
gantt
title insecure-bank - break down per module: candidate=1.53.0-SNAPSHOT~c923194dea, baseline=1.54.0-SNAPSHOT~cb08250ba1
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.472 ms) : 0, 1472
crashtracking [candidate] (1.455 ms) : 0, 1455
BytebuddyAgent [baseline] (733.392 ms) : 0, 733392
BytebuddyAgent [candidate] (733.688 ms) : 0, 733688
GlobalTracer [baseline] (242.546 ms) : 0, 242546
GlobalTracer [candidate] (242.79 ms) : 0, 242790
AppSec [baseline] (30.168 ms) : 0, 30168
AppSec [candidate] (30.342 ms) : 0, 30342
Debugger [baseline] (6.12 ms) : 0, 6120
Debugger [candidate] (6.115 ms) : 0, 6115
Remote Config [baseline] (693.257 µs) : 0, 693
Remote Config [candidate] (683.187 µs) : 0, 683
Telemetry [baseline] (13.822 ms) : 0, 13822
Telemetry [candidate] (12.943 ms) : 0, 12943
section iast
crashtracking [baseline] (1.468 ms) : 0, 1468
crashtracking [candidate] (1.46 ms) : 0, 1460
BytebuddyAgent [baseline] (852.548 ms) : 0, 852548
BytebuddyAgent [candidate] (851.452 ms) : 0, 851452
GlobalTracer [baseline] (233.84 ms) : 0, 233840
GlobalTracer [candidate] (232.649 ms) : 0, 232649
AppSec [baseline] (26.277 ms) : 0, 26277
AppSec [candidate] (28.41 ms) : 0, 28410
Debugger [baseline] (7.589 ms) : 0, 7589
Debugger [candidate] (5.833 ms) : 0, 5833
Remote Config [baseline] (606.262 µs) : 0, 606
Remote Config [candidate] (601.351 µs) : 0, 601
Telemetry [baseline] (9.034 ms) : 0, 9034
Telemetry [candidate] (8.31 ms) : 0, 8310
IAST [baseline] (28.455 ms) : 0, 28455
IAST [candidate] (29.443 ms) : 0, 29443
Startup time reports for petclinicgantt
title petclinic - global startup overhead: candidate=1.53.0-SNAPSHOT~c923194dea, baseline=1.54.0-SNAPSHOT~cb08250ba1
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.053 s) : 0, 1052555
Total [baseline] (10.66 s) : 0, 10659586
Agent [candidate] (1.055 s) : 0, 1054881
Total [candidate] (10.779 s) : 0, 10779448
section appsec
Agent [baseline] (1.224 s) : 0, 1223817
Total [baseline] (10.825 s) : 0, 10824728
Agent [candidate] (1.226 s) : 0, 1225537
Total [candidate] (10.835 s) : 0, 10834796
section iast
Agent [baseline] (1.18 s) : 0, 1179517
Total [baseline] (10.926 s) : 0, 10925848
Agent [candidate] (1.197 s) : 0, 1196517
Total [candidate] (10.956 s) : 0, 10956493
section profiling
Agent [baseline] (1.2 s) : 0, 1200377
Total [baseline] (10.92 s) : 0, 10920058
Agent [candidate] (1.197 s) : 0, 1197289
Total [candidate] (10.957 s) : 0, 10956898
gantt
title petclinic - break down per module: candidate=1.53.0-SNAPSHOT~c923194dea, baseline=1.54.0-SNAPSHOT~cb08250ba1
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.489 ms) : 0, 1489
crashtracking [candidate] (1.466 ms) : 0, 1466
BytebuddyAgent [baseline] (736.799 ms) : 0, 736799
BytebuddyAgent [candidate] (736.685 ms) : 0, 736685
GlobalTracer [baseline] (243.911 ms) : 0, 243911
GlobalTracer [candidate] (243.963 ms) : 0, 243963
AppSec [baseline] (30.513 ms) : 0, 30513
AppSec [candidate] (30.2 ms) : 0, 30200
Debugger [baseline] (6.091 ms) : 0, 6091
Debugger [candidate] (6.099 ms) : 0, 6099
Remote Config [baseline] (698.916 µs) : 0, 699
Remote Config [candidate] (684.464 µs) : 0, 684
Telemetry [baseline] (11.829 ms) : 0, 11829
Telemetry [candidate] (14.567 ms) : 0, 14567
section appsec
crashtracking [baseline] (1.478 ms) : 0, 1478
crashtracking [candidate] (1.46 ms) : 0, 1460
BytebuddyAgent [baseline] (755.039 ms) : 0, 755039
BytebuddyAgent [candidate] (756.641 ms) : 0, 756641
GlobalTracer [baseline] (235.291 ms) : 0, 235291
GlobalTracer [candidate] (235.871 ms) : 0, 235871
AppSec [baseline] (168.4 ms) : 0, 168400
AppSec [candidate] (170.346 ms) : 0, 170346
Debugger [baseline] (8.913 ms) : 0, 8913
Debugger [candidate] (5.788 ms) : 0, 5788
Remote Config [baseline] (627.226 µs) : 0, 627
Remote Config [candidate] (620.475 µs) : 0, 620
Telemetry [baseline] (9.29 ms) : 0, 9290
Telemetry [candidate] (10.031 ms) : 0, 10031
IAST [baseline] (23.645 ms) : 0, 23645
IAST [candidate] (23.588 ms) : 0, 23588
section iast
crashtracking [baseline] (1.472 ms) : 0, 1472
crashtracking [candidate] (1.478 ms) : 0, 1478
BytebuddyAgent [baseline] (851.0 ms) : 0, 851000
BytebuddyAgent [candidate] (865.571 ms) : 0, 865571
GlobalTracer [baseline] (233.08 ms) : 0, 233080
GlobalTracer [candidate] (235.541 ms) : 0, 235541
AppSec [baseline] (26.27 ms) : 0, 26270
AppSec [candidate] (27.605 ms) : 0, 27605
Debugger [baseline] (6.671 ms) : 0, 6671
Debugger [candidate] (6.67 ms) : 0, 6670
Remote Config [baseline] (608.66 µs) : 0, 609
Remote Config [candidate] (599.662 µs) : 0, 600
Telemetry [baseline] (8.345 ms) : 0, 8345
Telemetry [candidate] (8.351 ms) : 0, 8351
IAST [baseline] (30.96 ms) : 0, 30960
IAST [candidate] (29.387 ms) : 0, 29387
section profiling
crashtracking [baseline] (1.434 ms) : 0, 1434
crashtracking [candidate] (1.431 ms) : 0, 1431
BytebuddyAgent [baseline] (762.988 ms) : 0, 762988
BytebuddyAgent [candidate] (761.431 ms) : 0, 761431
GlobalTracer [baseline] (223.142 ms) : 0, 223142
GlobalTracer [candidate] (222.721 ms) : 0, 222721
AppSec [baseline] (30.765 ms) : 0, 30765
AppSec [candidate] (30.388 ms) : 0, 30388
Debugger [baseline] (6.232 ms) : 0, 6232
Debugger [candidate] (6.231 ms) : 0, 6231
Remote Config [baseline] (732.382 µs) : 0, 732
Remote Config [candidate] (690.823 µs) : 0, 691
Telemetry [baseline] (16.553 ms) : 0, 16553
Telemetry [candidate] (16.311 ms) : 0, 16311
ProfilingAgent [baseline] (108.002 ms) : 0, 108002
ProfilingAgent [candidate] (107.603 ms) : 0, 107603
Profiling [baseline] (108.665 ms) : 0, 108665
Profiling [candidate] (108.253 ms) : 0, 108253
LoadParameters
See matching parameters
SummaryFound 2 performance improvements and 1 performance regressions! Performance is the same for 9 metrics, 12 unstable metrics.
Request duration reports for petclinicgantt
title petclinic - request duration [CI 0.99] : candidate=1.53.0-SNAPSHOT~c923194dea, baseline=1.54.0-SNAPSHOT~cb08250ba1
dateFormat X
axisFormat %s
section baseline
no_agent (37.777 ms) : 37477, 38076
. : milestone, 37777,
appsec (48.389 ms) : 47967, 48811
. : milestone, 48389,
code_origins (44.699 ms) : 44316, 45081
. : milestone, 44699,
iast (44.868 ms) : 44478, 45259
. : milestone, 44868,
profiling (48.322 ms) : 47868, 48775
. : milestone, 48322,
tracing (43.549 ms) : 43192, 43905
. : milestone, 43549,
section candidate
no_agent (36.958 ms) : 36654, 37262
. : milestone, 36958,
appsec (46.792 ms) : 46374, 47209
. : milestone, 46792,
code_origins (45.682 ms) : 45273, 46091
. : milestone, 45682,
iast (44.765 ms) : 44382, 45148
. : milestone, 44765,
profiling (46.867 ms) : 46443, 47291
. : milestone, 46867,
tracing (44.16 ms) : 43793, 44527
. : milestone, 44160,
Request duration reports for insecure-bankgantt
title insecure-bank - request duration [CI 0.99] : candidate=1.53.0-SNAPSHOT~c923194dea, baseline=1.54.0-SNAPSHOT~cb08250ba1
dateFormat X
axisFormat %s
section baseline
no_agent (4.122 ms) : 4071, 4173
. : milestone, 4122,
iast (9.243 ms) : 9087, 9399
. : milestone, 9243,
iast_FULL (13.887 ms) : 13614, 14161
. : milestone, 13887,
iast_GLOBAL (10.557 ms) : 10371, 10744
. : milestone, 10557,
profiling (8.769 ms) : 8628, 8911
. : milestone, 8769,
tracing (7.515 ms) : 7407, 7623
. : milestone, 7515,
section candidate
no_agent (4.469 ms) : 4417, 4521
. : milestone, 4469,
iast (9.578 ms) : 9416, 9741
. : milestone, 9578,
iast_FULL (14.351 ms) : 14064, 14638
. : milestone, 14351,
iast_GLOBAL (10.321 ms) : 10132, 10510
. : milestone, 10321,
profiling (8.893 ms) : 8747, 9038
. : milestone, 8893,
tracing (7.672 ms) : 7562, 7781
. : milestone, 7672,
DacapoParameters
See matching parameters
SummaryFound 0 performance improvements and 0 performance regressions! Performance is the same for 11 metrics, 1 unstable metrics. Execution time for tomcatgantt
title tomcat - execution time [CI 0.99] : candidate=1.53.0-SNAPSHOT~c923194dea, baseline=1.54.0-SNAPSHOT~cb08250ba1
dateFormat X
axisFormat %s
section baseline
no_agent (1.473 ms) : 1461, 1484
. : milestone, 1473,
appsec (3.621 ms) : 3406, 3836
. : milestone, 3621,
iast (2.2 ms) : 2137, 2264
. : milestone, 2200,
iast_GLOBAL (2.242 ms) : 2178, 2306
. : milestone, 2242,
profiling (2.054 ms) : 2003, 2106
. : milestone, 2054,
tracing (2.037 ms) : 1987, 2087
. : milestone, 2037,
section candidate
no_agent (1.472 ms) : 1460, 1484
. : milestone, 1472,
appsec (3.608 ms) : 3395, 3821
. : milestone, 3608,
iast (2.202 ms) : 2139, 2266
. : milestone, 2202,
iast_GLOBAL (2.246 ms) : 2182, 2310
. : milestone, 2246,
profiling (2.066 ms) : 2013, 2119
. : milestone, 2066,
tracing (2.016 ms) : 1966, 2065
. : milestone, 2016,
Execution time for biojavagantt
title biojava - execution time [CI 0.99] : candidate=1.53.0-SNAPSHOT~c923194dea, baseline=1.54.0-SNAPSHOT~cb08250ba1
dateFormat X
axisFormat %s
section baseline
no_agent (14.95 s) : 14950000, 14950000
. : milestone, 14950000,
appsec (14.913 s) : 14913000, 14913000
. : milestone, 14913000,
iast (18.504 s) : 18504000, 18504000
. : milestone, 18504000,
iast_GLOBAL (17.744 s) : 17744000, 17744000
. : milestone, 17744000,
profiling (15.537 s) : 15537000, 15537000
. : milestone, 15537000,
tracing (14.887 s) : 14887000, 14887000
. : milestone, 14887000,
section candidate
no_agent (15.543 s) : 15543000, 15543000
. : milestone, 15543000,
appsec (14.868 s) : 14868000, 14868000
. : milestone, 14868000,
iast (18.8 s) : 18800000, 18800000
. : milestone, 18800000,
iast_GLOBAL (17.985 s) : 17985000, 17985000
. : milestone, 17985000,
profiling (15.896 s) : 15896000, 15896000
. : milestone, 15896000,
tracing (14.774 s) : 14774000, 14774000
. : milestone, 14774000,
|
PerfectSlayer
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't check at the cache implementation but posting some quick feedback first:
🎯 suggestion: I don't have the full context but should we apply it to the dictionary mapper for V05 too?
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapperV0_4.java
Outdated
Show resolved
Hide resolved
dd-trace-core/src/jmh/java/datadog/trace/common/writer/ddagent/Utf8Benchmark.java
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/GenerationalUtf8Cache.java
Outdated
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/GenerationalUtf8Cache.java
Outdated
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/GenerationalUtf8Cache.java
Outdated
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/GenerationalUtf8Cache.java
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/GenerationalUtf8Cache.java
Outdated
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/GenerationalUtf8Cache.java
Outdated
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/SimpleUtf8Cache.java
Outdated
Show resolved
Hide resolved
- implementing review feedback - experimenting with exact hash based marking scheme - fixed issue with not updating entry after hit in simple cache - re-enabling cache by default for benchmarking - spotless
- altered marking strategy to use a bloom filter of previously requested values, once a new entry hits the filter the filter is reset to zero - tweaking cache sizes
…a into dougqh/utf8-caching
Yes, I think we should. To do that, I'm going to have to make some bigger changes to v0.5, so I might leave that for another PR. |
|
Just a question out of the blue. Couldn't the simple cache reuse the Yeah, I think that's a possibility. I honestly haven't quite determined if the protection against eagerly creating CacheEntry-s is essential for tag names. I'd started with a different approach where I generated the UTF8 representations of the known tag names first, but I shelved that because it is a bit hard to incorporate / maintain. |
- clean-up based on review feedback - making naming consistent - some vestiges of prior names for second level cache updated - tweaked generational cache to check tenured entries first -
…a into dougqh/utf8-caching
- switching generational cache to use different probe lengths for eden vs tenured generation - these settings are neutral or better throughput wise for petclinic for 64m, 80m, 96m, and 128m heaps
…a into dougqh/utf8-caching
bric3
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First wave of comments, I haven't looked at GenerationalUtf8Cache yet
| public final class SimpleUtf8Cache implements EncodingCache { | ||
| private static final int MAX_PROBES = 4; | ||
|
|
||
| private final int SIZE = 128; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Why 128 in particular ? And not 256 ?
IIC this needs to be a power of two to be used as a bitmask for the modulo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, power 2 so that the bitmask calculations works for the bucket calculation.
As for why 128? I mostly just played with cache sizes, probe lengths, etc to come up with something that was good at multiple heap sizes. These values gave nice gains in throughput at higher heap sizes and were neutral on throughput at lower heap sizes.
Or to put it more succinctly, I usually aim to make the cache as small as I can without compromising the hit rate. Admittedly, there is a danger of overfitting to the benchmark load.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also might be worth adding a comment pointing to where this modulo happens (initialBucketIndex methods)
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/SimpleUtf8Cache.java
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/SimpleUtf8Cache.java
Outdated
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/SimpleUtf8Cache.java
Outdated
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/SimpleUtf8Cache.java
Outdated
Show resolved
Hide resolved
| String tag = nextTag(); | ||
| String value = nextValue(tag); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Out of curiosity, should it it be better to generate a tag / value dataset outside the the benchmark methods ? Maybe this could allow to have datasets with wider range of values.
I believe some customers have wide chars values (e.g. in korean) in their tag, would it be useful to have a benchmark for that, could the gains be more pronounced in this case ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, probably. I need to experiment some more to figure out what's possible with JMH.
The x_baseline methods exist, so that I can do a comparison to the "same" logic without the encoding.
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/GenerationalUtf8Cache.java
Outdated
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/GenerationalUtf8Cache.java
Outdated
Show resolved
Hide resolved
| newEntry.hit(lookupTimeMs); | ||
| newEntry.hit(lookupTimeMs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Won't it amplify hits anytime this entry is "accessed" after the first use (which is a mark) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, in a sense, this provides the incorrect first access time, but only the last access time is stored.
Also, I'm not precisely tracking time because I don't want to constantly call System#currentTimeMills.
Instead I just update the access time once each time a payload is being constructed, so times are somewhat deliberately imprecise.
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/GenerationalUtf8Cache.java
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/GenerationalUtf8Cache.java
Outdated
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/GenerationalUtf8Cache.java
Outdated
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/GenerationalUtf8Cache.java
Outdated
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/GenerationalUtf8Cache.java
Outdated
Show resolved
Hide resolved
| public final class SimpleUtf8Cache implements EncodingCache { | ||
| private static final int MAX_PROBES = 4; | ||
|
|
||
| private final int SIZE = 128; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also might be worth adding a comment pointing to where this modulo happens (initialBucketIndex methods)
Should be using adjHash not value.hashCode
- more explanatory comments - more naming updates: local -> eden
- adding protections against storing large strings in cache - fixed errant use of CacheEntry.utf8(String) instead of entry.utf8() - removed unnecessary lookupTimeMs variable
…a into dougqh/utf8-caching
Added tests to verify that big strings are not cached
bric3
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pre-approving
dd-trace-core/src/jmh/java/datadog/trace/common/writer/ddagent/Utf8Benchmark.java
Outdated
Show resolved
Hide resolved
dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/SimpleUtf8Cache.java
Outdated
Show resolved
Hide resolved
…/Utf8Benchmark.java Co-authored-by: Brice Dutheil <brice.dutheil@gmail.com>
- added ability to configure cache size - for both tag names & values - factored shared code into Caching static utility class - added tests for Caching class & size determination logic
bric3
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, the configurable capacity is a nice touch !
dd-trace-core/src/jmh/java/datadog/trace/common/writer/ddagent/Utf8Benchmark.java
Outdated
Show resolved
Hide resolved
d6ceffb to
bd17af9
Compare
What Does This Do
This change adds UTF-8 encoding caching to optimize v0.4 payload construction. (Support for v0.5 will likely be done separately, since it requires more significant changes.)
Since
String#getBytesis already highly optimized, so these caches actually perform worse throughput-wise than an uncached encoding. However, the caches are useful in reducing allocation from UTF-8 encoding providing more headroom for the host application - which allows for improvements in throughput of the host application.For tags, a "simple" cache is used. The simple cache is a single level cache -- that uses hashing combined with linear probing. To avoid, cache churn and unnecessary allocation of a
CacheEntry, the simple cache uses a first request marking scheme that typically avoids creating aCacheEntryfor values that are requested only once. Eviction from the simple cache is done based on LFU policy.For tag values, a more complicated generational cache is used. The generational cache combines the delayed
CacheEntrycreation logic of the simple cache with a 2nd-level for resilience.Frequently used entries are "promoted" to the higher level cache. The 1st level of the generational cache uses a LFU eviction policy. The 2nd level of the generational cache uses a LRU eviction policy.
For the tag value use case, the generational policy provides a 2x increase in hit rate over the simple cache.
Motivation
This change reduces the memory allocation overhead caused by UTF-8 encoding.
In systems with ample heap, this change provides a 25-75% improvement in throughput reduction by reducing GC cycles.
In systems with limited heap, this change is net neutral.