Low-cost generation of performance percentiles (p50, p90, p99, p99.9, etc.).
- Introduction
- How It Works
- Performance & Trade-offs
- Installation
- Components
- Examples
- Project Information
p99 is a lightweight, low-overhead library designed for generating real-time performance percentiles in high-frequency or latency-sensitive environments.
p99.Go is the Go implementation.
Histogram is a low-overhead, zero-allocation, fixed-size structure designed to track event durations (typically in nanoseconds) using 64 logarithmic buckets.
-
Logarithmic Bucketing: The bucket boundaries are spaced as powers of two:
- Bucket
0represents[0, 1]nanoseconds; - Bucket
1represents[2, 3]nanoseconds; - Bucket
2represents[4, 7]nanoseconds; - Bucket
irepresents[2^i, 2^(i+1) - 1]nanoseconds.
- Bucket
-
Branchless Indexing: Finding the correct bucket index for an incoming duration is extremely fast. It is computed in a few CPU instructions using
bits.Len64. - Linear Interpolation: Percentile queries iterate through the buckets to find the target rank and perform linear interpolation within the matching bucket to approximate the exact percentile duration.
-
Zero Allocation:
Histogramdoes not allocate memory on the heap during creation, event insertion, or percentile queries under normal operation. It is a compact structure that can reside entirely on the stack or be embedded in other structures. -
Ultra-Low Latency Insertion: Recording a latency measurement (
PushEventTimeNs) is designed for minimal overhead. -
Fast Queries: Querying percentiles (such as
ValueAtP99()) is designed to terminate early when events cluster in lower-indexed buckets.
-
Logarithmic Precision: To achieve zero allocation and constant-time operations,
Histogramsacrifices exact precision. It does not store individual event times. - Approximation: Percentile values are approximated using linear interpolation within the bucket boundaries. For very large values, the bucket width is wider, which leads to a wider approximation range.
Install:
go get "github.com/synesissoftware/p99.Go"Use:
import "github.com/synesissoftware/p99.Go"| Name | Value | Description |
|---|---|---|
BucketCount |
64 |
Number of logarithmic buckets in a Histogram
|
VersionMajor |
0 |
Major version number |
VersionMinor |
2 |
Minor version number |
VersionPatch |
0 |
Patch version number |
VersionAB |
ver2go.Release (0xFFFF) |
Final-release αβ-designator |
| Function | Description |
|---|---|
New() |
Returns a zero-initialized histogram |
Version() |
Returns the packed 64-bit library version |
VersionString() |
Returns the string form of the library version |
BucketIndex(timeInNs uint64) int |
Calculates the bucket index for a duration |
BucketRange(index int) (bool, uint64, uint64) |
Returns the inclusive nanosecond range for a bucket |
A low-cost, zero-allocation, 64-bucket logarithmic histogram designed for recording event durations in nanoseconds and querying high-resolution percentiles.
package main
import (
"github.com/synesissoftware/p99.Go"
"fmt"
"time"
)
func main() {
h := p99.New()
h.PushEventTimeNs(150)
h.PushEventTimeUs(5)
h.PushEventTimeMs(10)
h.PushEventDuration(250 * time.Nanosecond)
fmt.Println("events:", h.EventCount())
if ok, p99val := h.ValueAtP99(); ok {
fmt.Printf("p99: %d ns\n", p99val)
}
}Examples are provided in the examples directory, along with a markdown description for each. A detailed list of them is provided in EXAMPLES.md.
Defect reports, feature requests, and pull requests are welcome on https://github.com/synesissoftware/p99.Go.
p99.Go is released under the 3-clause BSD license. See LICENSE for details.