Repository navigation
HdrHistogram_c 0.12.1
7 merged pull requests since 0.12.0. A bug-fix release: no function was added or removed, and the layout of every public struct is unchanged, so existing code and binaries keep working. Several fixes change what a function returns for an empty histogram or for an out-of-range percentile; read Behaviour changes before upgrading if you test for those results.
Performance: unchanged since 0.12.0, much faster than 0.11.10
No regression: 0.12.1 against 0.12.0 on the benchmark fleet, write, read and the batch call all within about 1% of 0.12.0 (the batch call is a little faster). Against 0.11.10, percentile queries are about 2x faster as single calls and 15 to 20x faster as a batch; recording is unchanged. Both comparisons come from the same harness on the same machines.
| 0.12.1 speed relative to 0.12.0 (higher is faster) | Intel Xeon (Sapphire Rapids) | AMD EPYC (Zen 5) | AWS Graviton (Neoverse V2) |
|---|---|---|---|
hdr_record_value (write) |
1.000x | 1.002x | 1.000x |
hdr_value_at_percentile, 4 percentiles as single calls |
1.001x | 1.005x | 0.999x |
hdr_value_at_percentile, repository read driver |
1.000x | 1.006x | 1.000x |
hdr_value_at_percentiles, 4 percentiles (batch) |
1.038x | 1.011x | 0.998x |
| 0.12.1 speed relative to 0.11.10 (higher is faster) | Intel Xeon (Sapphire Rapids) | AMD EPYC (Zen 5) | AWS Graviton (Neoverse V2) |
|---|---|---|---|
hdr_record_value (write) |
1.018x | 1.011x | 0.984x |
hdr_value_at_percentile, 4 percentiles as single calls |
1.95x | 2.05x | 2.10x |
hdr_value_at_percentile, repository read driver |
1.74x | 2.14x | 2.17x |
hdr_value_at_percentiles, 4 percentiles (batch) |
15.3x | 15.4x | 20.4x |
Against 0.12.0 everything is inside the run-to-run spread except the batch call on Intel (3.8% faster, runs tightly grouped) and, marginally, on AMD; treat those as no change you should rely on. Against 0.11.10, write is within 2% either way (0.984x on Graviton is a small, stable difference, not something to expect in an application). The read driver prints only two decimals, so its ratio resolves to about 2 to 4%; the single-call row is the precise read-path figure. The batch ratios here (15 to 20x) differ from the 33x, 29x and 20x in the 0.12.0 notes because this is a different batch loop and histogram (a 1M-sample lognormal histogram, four percentiles); compare numbers only within one table.
Each figure is the median of six runs per release (three interleaved old/new/new/old blocks, one session per comparison) pinned to one core, built with GCC 13.3 in the default Release configuration, using the repository's own write and read drivers plus a small batch timing loop. These are microbenchmarks, not application throughput. Compared at 0.11.10, 0.12.0 (8885476) and the release commit (30e9ce6).
Bug fixes
- Batch percentiles no longer leak internal values. For an empty histogram,
hdr_value_at_percentilesreturned1in every slot (its internal rank target) and reported success (#174, fixed by #176). Present since the batch call was added in 0.11.3. - Batch p0 agrees with the single call.
hdr_value_at_percentilesreturned the top of the first populated bucket for percentile0, whilehdr_value_at_percentilereturned the bottom (which is alsohdr_min) (#173, #175). The two disagreed from 0.11.9 to 0.12.0. - Empty histograms report 0 for every percentile. With a lowest discernible value above 1,
hdr_value_at_percentilereturned a value that was never recorded (63 at lowest 100, 511 at lowest 1000) (#116, #177). Affected every release up to 0.12.0. The single, batch and packed calls now agree. hdr_minof an empty histogram is 0, ashdr_maxalready was, in both the dense and packed types (#125, #178). It returnedINT64_MAXin every earlier release.hdr_meanandhdr_stddevof an empty histogram are 0.0, matching the packed type (#182, #183). The dense functions returned NaN.- Percentile rank conversion is well defined (#181, #180, #184):
- The rank was an unchecked double-to-
int64_tcast, which is undefined behaviour for a percentile of-INFINITYand for a histogram holdingINT64_MAXobservations queried at p100 (UBSan reports both). - With more than 2^53 observations, p100 could be wrong: 2^53+3 observations of one value returned 0 from the single call and a leaked rank from the batch call.
- The rank is now clamped to
[1, total_count]before the cast, and p100 returns the last observation exactly. Results that were already correct do not change: a before/after comparison over 15,000 random histograms with 16 percentiles each, queried through both calls (480,000 results, counts below 2^53), found no differences. - Present in the single call since 0.0.1 and in the batch call since 0.11.3.
- The rank was an unchecked double-to-
There are no security fixes in this release; the undefined behaviour above needed a negative-infinite percentile or an INT64_MAX observation count, and no CVE has been assigned.
Behaviour changes to know about when upgrading
| Call | 0.12.0 | 0.12.1 | PR |
|---|---|---|---|
hdr_value_at_percentile, empty histogram, lowest discernible value above 1 |
highest_equivalent_value(0), e.g. 63 at lowest 100 |
0 | #177 |
hdr_value_at_percentiles, empty histogram |
the rank target (1) in every slot | 0 in every slot | #176, #177 |
hdr_value_at_percentiles, percentile exactly 0.0, non-empty |
top of the first populated bucket | bottom of it (equals hdr_value_at_percentile(h, 0) and hdr_min) |
#175 |
hdr_min, hdr_packed_min, empty histogram |
INT64_MAX |
0 | #178 |
hdr_mean, hdr_stddev, empty dense histogram |
NaN | 0.0 | #183 |
| p100 above 2^53 observations | could be 0, an earlier bucket, or a leaked rank | the last observation | #184 |
- If you test for an empty histogram with
hdr_min(h) == INT64_MAXorisnan(hdr_mean(h)), switch tohdr_total_count(h) == 0. A recorded value of 0 also gives a minimum of 0, so the minimum alone cannot tell the two apart. - A percentile of NaN still selects p100 (and
-INFINITYor any negative still selects the first recorded value); this release only makes those conversions defined. The Java, Go and Rust ports send NaN to the first bucket instead; that difference is unchanged. - A recorded value of 0 is a real observation and behaves as before in every call above.
Build and packaging
- On targets without native 64-bit atomics (for example 32-bit ARM, RISC-V and MIPS), the CMake build now probes whether the library's
__atomicbuiltins link, and linkslibatomic(and lists-latomicinLibs.privateofhdr_histogram.pc) when they do not (#98, #179). Targets that inline the builtins, including x86-64, arm64 and macOS, are unchanged. This is verified on x86-64 only, with a CI job that forces the new branch; it has not been confirmed on real 32-bit ARM or RISC-V hardware. If you build the amalgamated file instead of using CMake, add-latomicyourself on such targets (seedocs/AMALGAMATION.md). - Shared library: 6.5.4 (
SONAME.so.6unchanged; no interface was added or removed).
Full Changelog: 0.12.0...0.12.1


