p99-ruby 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/AUTHORS.md +21 -0
- data/CHANGES.md +35 -0
- data/CONTRIBUTING.md +36 -0
- data/EXAMPLES.md +9 -0
- data/FAQ.md +28 -0
- data/INSTALL.md +41 -0
- data/NEWS.md +10 -0
- data/README.md +55 -7
- data/SECURITY.md +22 -0
- data/TODO.md +20 -0
- data/docs/components/histogram.md +116 -0
- data/docs/guides/README.md +18 -0
- data/docs/guides/recording-and-reading-percentiles.md +134 -0
- data/docs/reference/README.md +39 -0
- data/examples/build_histogram.md +57 -0
- data/examples/build_histogram.rb +149 -0
- data/examples/measure_batch_latency.md +54 -0
- data/examples/measure_batch_latency.rb +87 -0
- data/lib/p99/histogram/pure.rb +666 -0
- data/lib/p99/histogram.rb +85 -0
- data/lib/p99/version.rb +2 -2
- data/lib/p99.rb +1 -0
- data/test/unit/tc_histogram.rb +317 -0
- data/test/unit/tc_version.rb +0 -0
- data/test/unit/ts_all.rb +0 -0
- metadata +24 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8bdde9c07f1b5d11d8e2d57e1fbc021d3115c5f574ac0b21cb9326cfa3c0f1db
|
|
4
|
+
data.tar.gz: 0b3123844e720c310a7599a0c44bcec319bbdc9ea3e23668eea825138bd4bf11
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3d38cc27f0a13cf6786940b5925d41c37cd9d509fe3bf86a72fece9112e1420b593c1321f1d1d8ec0cc895506e6cea96ccc09de733f4f82edbe4f06a4339033c
|
|
7
|
+
data.tar.gz: 80170c0a7d40cab847c2a21644c117aca97da7bc18f24b4dc2770e59e07d1b954d7f5e3a7751c094ce0f31da04e6d4936e0ca6e3dcc39181b81ff160c3d40b13
|
data/AUTHORS.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# p99.Ruby - Authors <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Major Contributors
|
|
5
|
+
|
|
6
|
+
| Name | GitHub |
|
|
7
|
+
| ----------- | --------------------------------- |
|
|
8
|
+
| Matt Wilson | [mwsis](https://github.com/mwsis) |
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Defect reports, fixes and suggestions (for which we are very grateful)
|
|
12
|
+
|
|
13
|
+
| Name | GitHub |
|
|
14
|
+
| ----------- | --------------------------------- |
|
|
15
|
+
| \<none> | |
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
Contributions are welcomed.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
<!-- ########################### end of file ########################### -->
|
data/CHANGES.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# p99.Ruby - Changes <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## 0.1.0 - 30th August 2026
|
|
5
|
+
|
|
6
|
+
* added pure-Ruby **P99::Histogram** (log2 buckets, push helpers, percentile queries);
|
|
7
|
+
* added unit tests for Histogram behaviour;
|
|
8
|
+
* added **examples/build_histogram** runnable example;
|
|
9
|
+
* added **EXAMPLES.md** catalogue;
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## 0.0.1 - 28th August 2026
|
|
13
|
+
|
|
14
|
+
* added `# frozen_string_literal: true` to all **lib/** sources;
|
|
15
|
+
* added **AUTHORS.md**, **CONTRIBUTING.md**, **EXAMPLES.md**, **FAQ.md**,
|
|
16
|
+
**INSTALL.md**, and **SECURITY.md**;
|
|
17
|
+
* added Ruby 2.0 and MinGW CI coverage, warning-mode tests, and gem
|
|
18
|
+
build/install smoke tests to **.github/workflows/ruby.yml**;
|
|
19
|
+
* improved gem metadata, URL handling, and bounded the **xqsr3** development
|
|
20
|
+
dependency;
|
|
21
|
+
* modernised the test runner's argument handling, library loading, and
|
|
22
|
+
Ruby-version support;
|
|
23
|
+
* documented the currently available root module and version metadata in
|
|
24
|
+
**README.md**;
|
|
25
|
+
* added Windows helpers and shared editor, Git, Vim, and project configuration;
|
|
26
|
+
* updated **Gemfile**, **Rakefile**, and RDoc configuration for the revised
|
|
27
|
+
development workflow;
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## 0.0.0 - 4th August 2026
|
|
31
|
+
|
|
32
|
+
* initial project scaffolding;
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
<!-- ########################### end of file ########################### -->
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# p99.Ruby - Contributing <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Table of Contents <!-- omit in toc -->
|
|
5
|
+
|
|
6
|
+
- [Defects and features](#defects-and-features)
|
|
7
|
+
- [Pull requests](#pull-requests)
|
|
8
|
+
- [Tests](#tests)
|
|
9
|
+
- [License](#license)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## Defects and features
|
|
13
|
+
|
|
14
|
+
Open an issue on https://github.com/synesissoftware/p99.Ruby/issues.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## Pull requests
|
|
18
|
+
|
|
19
|
+
Pull requests are welcome on https://github.com/synesissoftware/p99.Ruby. Keep diffs local to the change; match existing indentation (2 spaces in Ruby) and the Synesis markdown set (**README.md**, **CHANGES.md**, **NEWS.md**, **TODO.md**, **INSTALL.md**, **CONTRIBUTING.md**, **SECURITY.md**).
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## Tests
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
bundle exec rake test
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
or `./run_all_unit_tests.sh`.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
## License
|
|
32
|
+
|
|
33
|
+
Contributions are accepted under the 3-clause BSD license. See [LICENSE](./LICENSE).
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
<!-- ########################### end of file ########################### -->
|
data/EXAMPLES.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# p99.Ruby Examples <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
| Name | Source & Description | Summary |
|
|
4
|
+
| --- | --- | --- |
|
|
5
|
+
| **build_histogram** | [examples/build_histogram.rb](./examples/build_histogram.rb)<br/>[examples/build_histogram.md](./examples/build_histogram.md) | Records timed `sleep` delays under a simple PRNG into `P99::Histogram`, then prints a summary and percentile approximations (`P99_TRIES` controls iteration count) |
|
|
6
|
+
| **measure_batch_latency** | [examples/measure_batch_latency.rb](./examples/measure_batch_latency.rb)<br/>[examples/measure_batch_latency.md](./examples/measure_batch_latency.md) | Measures simulated batch-operation latency with a monotonic clock, records nanoseconds, and prints fixed percentile results |
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<!-- ########################### end of file ########################### -->
|
data/FAQ.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# p99.Ruby - FAQ <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
The FAQ list is under (constant) development. If you post a question on the
|
|
4
|
+
[Issues](https://github.com/synesissoftware/p99.Ruby/issues) forum
|
|
5
|
+
it will be used to create one.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## Table of Contents <!-- omit in toc -->
|
|
9
|
+
|
|
10
|
+
- [Q1: "How do I install this library?"](#q1-how-do-i-install-this-library)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# FAQs: <!-- omit in toc -->
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## Q1: "How do I install this library?"
|
|
17
|
+
|
|
18
|
+
Install via **gem**:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
gem install p99-ruby
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
See [README.md](./README.md) for usage.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
<!-- ########################### end of file ########################### -->
|
data/INSTALL.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# p99.Ruby - Installation and Use <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Table of Contents <!-- omit in toc -->
|
|
5
|
+
|
|
6
|
+
- [Install the gem](#install-the-gem)
|
|
7
|
+
- [From a source checkout](#from-a-source-checkout)
|
|
8
|
+
- [Using the library](#using-the-library)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Install the gem
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
gem install p99-ruby
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
or add to a **Gemfile**:
|
|
18
|
+
|
|
19
|
+
```Ruby
|
|
20
|
+
gem 'p99-ruby'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
then `bundle install`.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## From a source checkout
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
bundle install
|
|
30
|
+
bundle exec rake test
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
## Using the library
|
|
35
|
+
|
|
36
|
+
```Ruby
|
|
37
|
+
require 'p99'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
<!-- ########################### end of file ########################### -->
|
data/NEWS.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# p99.Ruby - News <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
| Date | News Item |
|
|
4
|
+
| ---------------- | ------------------------------------------------------------------------------------ |
|
|
5
|
+
| 30th August 2026 | [**p99.Ruby** 0.1.0](https://github.com/synesissoftware/p99.Ruby/releases/tag/0.1.0) |
|
|
6
|
+
| 28th August 2026 | [**p99.Ruby** 0.0.1](https://github.com/synesissoftware/p99.Ruby/releases/tag/0.0.1) |
|
|
7
|
+
| 4th August 2026 | [**p99.Ruby** 0.0.0](https://github.com/synesissoftware/p99.Ruby/releases/tag/0.0.0) |
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
<!-- ########################### end of file ########################### -->
|
data/README.md
CHANGED
|
@@ -15,13 +15,15 @@ Low-cost generation of performance percentiles (p50, p90, p99, p99.9, etc.), for
|
|
|
15
15
|
- [Introduction](#introduction)
|
|
16
16
|
- [Installation](#installation)
|
|
17
17
|
- [Components](#components)
|
|
18
|
+
- [`P99::Histogram`](#p99histogram)
|
|
19
|
+
- [Examples](#examples)
|
|
18
20
|
- [Project Information](#project-information)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
- [Where to get help](#where-to-get-help)
|
|
22
|
+
- [Contribution guidelines](#contribution-guidelines)
|
|
23
|
+
- [Dependencies](#dependencies)
|
|
24
|
+
- [Development Dependencies](#development-dependencies)
|
|
25
|
+
- [Related projects](#related-projects)
|
|
26
|
+
- [License](#license)
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
## Introduction
|
|
@@ -50,7 +52,53 @@ require 'p99'
|
|
|
50
52
|
|
|
51
53
|
## Components
|
|
52
54
|
|
|
53
|
-
|
|
55
|
+
|
|
56
|
+
### `P99::Histogram`
|
|
57
|
+
|
|
58
|
+
Low-cost, fixed-size histogram for recording event durations (nanoseconds and
|
|
59
|
+
common larger units) and querying high-resolution percentiles (p50, p90, p99,
|
|
60
|
+
and beyond).
|
|
61
|
+
|
|
62
|
+
This release provides a **pure-Ruby** implementation. A C-extension backend
|
|
63
|
+
(with automatic fallback) is planned.
|
|
64
|
+
|
|
65
|
+
See the [Histogram component guide](./docs/components/histogram.md) for
|
|
66
|
+
loading, recording, statistics, percentile, and backend details. The
|
|
67
|
+
[generated API reference](./docs/reference/README.md) provides the complete
|
|
68
|
+
source-level method documentation.
|
|
69
|
+
|
|
70
|
+
The [task-oriented guides](./docs/guides/README.md) provide practical
|
|
71
|
+
workflows for recording and reading percentiles.
|
|
72
|
+
|
|
73
|
+
```Ruby
|
|
74
|
+
require 'p99'
|
|
75
|
+
|
|
76
|
+
h = P99::Histogram.new
|
|
77
|
+
h.push_event_time_ns(150)
|
|
78
|
+
h.push_event_time_us(5)
|
|
79
|
+
h.push_event_time_ms(10)
|
|
80
|
+
|
|
81
|
+
h.event_count # => 3
|
|
82
|
+
h.value_at_p99 # => approximated duration in nanoseconds
|
|
83
|
+
P99::IMPLEMENTATION # => "ruby" (or "c" when a native backend is present)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Force the pure-Ruby backend (for debugging or CI):
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
P99_PURE_RUBY=1 ruby -e "require 'p99'; puts P99::IMPLEMENTATION"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
## Examples
|
|
94
|
+
|
|
95
|
+
See [**EXAMPLES.md**](./EXAMPLES.md) for the full list. The primary
|
|
96
|
+
demonstration is [**build_histogram**](./examples/build_histogram.md):
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
ruby examples/build_histogram.rb
|
|
100
|
+
P99_TRIES=1000 ruby examples/build_histogram.rb
|
|
101
|
+
```
|
|
54
102
|
|
|
55
103
|
|
|
56
104
|
## Project Information
|
data/SECURITY.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# p99.Ruby - Security <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Table of Contents <!-- omit in toc -->
|
|
5
|
+
|
|
6
|
+
- [Reporting a vulnerability](#reporting-a-vulnerability)
|
|
7
|
+
- [Supported versions](#supported-versions)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## Reporting a vulnerability
|
|
11
|
+
|
|
12
|
+
Please report security issues privately via GitHub Security Advisories on https://github.com/synesissoftware/p99.Ruby/security, or by opening an issue if an advisory cannot be filed. Do not attach exploit proofs of concept against third-party systems.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## Supported versions
|
|
16
|
+
|
|
17
|
+
| Version | Supported |
|
|
18
|
+
| ------- | --------- |
|
|
19
|
+
| 0.0.x | ✅ |
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
<!-- ########################### end of file ########################### -->
|
data/TODO.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# p99.Ruby - TODO <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Functional improvements
|
|
5
|
+
|
|
6
|
+
* [ ] C extension backend (vendored **p99**) with pure-Ruby fallback;
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## Performance improvements
|
|
10
|
+
|
|
11
|
+
* \<none>
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## Packaging improvements
|
|
15
|
+
|
|
16
|
+
* [ ] Optional precompiled platform gems for the C extension;
|
|
17
|
+
* [x] Rename gemspec so the filename stem matches `spec.name` (`p99.gemspec` → **p99-ruby.gemspec**);
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
<!-- ########################### end of file ########################### -->
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# p99.Ruby Histogram <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
`P99::Histogram` is a fixed-size histogram for recording event durations and
|
|
4
|
+
estimating high percentiles such as p50, p90, p99, and p99.9. The current
|
|
5
|
+
release uses a pure-Ruby backend and stores durations in nanoseconds.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## Table of Contents <!-- omit in toc -->
|
|
9
|
+
|
|
10
|
+
- [Loading](#loading)
|
|
11
|
+
- [Recording durations](#recording-durations)
|
|
12
|
+
- [Reading statistics](#reading-statistics)
|
|
13
|
+
- [Reading percentiles](#reading-percentiles)
|
|
14
|
+
- [Overflow handling](#overflow-handling)
|
|
15
|
+
- [Backend selection](#backend-selection)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## Loading
|
|
19
|
+
|
|
20
|
+
Load the public entry point:
|
|
21
|
+
|
|
22
|
+
```Ruby
|
|
23
|
+
require 'p99'
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This loads `P99::Histogram` and selects the available implementation. The
|
|
27
|
+
active backend is available through `P99::IMPLEMENTATION`.
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## Recording durations
|
|
31
|
+
|
|
32
|
+
Create an empty histogram and record durations in the supported units:
|
|
33
|
+
|
|
34
|
+
```Ruby
|
|
35
|
+
histogram = P99::Histogram.new
|
|
36
|
+
|
|
37
|
+
histogram.push_event_time_ns(150)
|
|
38
|
+
histogram.push_event_time_us(5)
|
|
39
|
+
histogram.push_event_time_ms(10)
|
|
40
|
+
histogram.push_event_time_s(1)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
All recorded durations are converted to nanoseconds. Each `push_event_time_*`
|
|
44
|
+
method returns `true` when the duration is accepted and `false` when it cannot
|
|
45
|
+
be recorded.
|
|
46
|
+
Pass an integer in the selected unit; fractional values are truncated during
|
|
47
|
+
conversion.
|
|
48
|
+
|
|
49
|
+
Use `clear` to reset the histogram:
|
|
50
|
+
|
|
51
|
+
```Ruby
|
|
52
|
+
histogram.clear
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
## Reading statistics
|
|
57
|
+
|
|
58
|
+
The histogram exposes the number of recorded events and aggregate duration
|
|
59
|
+
statistics:
|
|
60
|
+
|
|
61
|
+
```Ruby
|
|
62
|
+
histogram.event_count
|
|
63
|
+
histogram.event_time_total
|
|
64
|
+
histogram.event_time_total_raw
|
|
65
|
+
histogram.min_event_time
|
|
66
|
+
histogram.max_event_time
|
|
67
|
+
histogram.has_overflowed?
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The duration values are expressed in nanoseconds. The raw total is useful when
|
|
71
|
+
the normal total has entered the overflow state.
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
## Reading percentiles
|
|
75
|
+
|
|
76
|
+
Use the named methods for common percentiles:
|
|
77
|
+
|
|
78
|
+
```Ruby
|
|
79
|
+
histogram.value_at_p50
|
|
80
|
+
histogram.value_at_p90
|
|
81
|
+
histogram.value_at_p99
|
|
82
|
+
histogram.value_at_p99_9
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
For other percentile values, use `value_at_percentile` or query several
|
|
86
|
+
percentiles at once with `values_at_percentiles`. `fixed_percentiles` provides
|
|
87
|
+
the library's standard percentile set.
|
|
88
|
+
|
|
89
|
+
The result is an approximation in nanoseconds. The implementation uses 64
|
|
90
|
+
logarithmic power-of-two buckets and linearly interpolates within the selected
|
|
91
|
+
bucket, so results should be treated as estimates rather than exact samples.
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
## Overflow handling
|
|
95
|
+
|
|
96
|
+
The histogram tracks whether the running event-time total has overflowed.
|
|
97
|
+
Once an addition cannot be represented safely, subsequent duration pushes are
|
|
98
|
+
rejected and `has_overflowed?` reports `true`.
|
|
99
|
+
|
|
100
|
+
Call `clear` to return the histogram to its initial empty state.
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
## Backend selection
|
|
104
|
+
|
|
105
|
+
The loader prefers a native backend when one is available. Set
|
|
106
|
+
`P99_PURE_RUBY` to force the pure-Ruby implementation:
|
|
107
|
+
|
|
108
|
+
```Shell
|
|
109
|
+
P99_PURE_RUBY=1 ruby -e "require 'p99'; puts P99::IMPLEMENTATION"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The current release reports `"ruby"` through `P99::IMPLEMENTATION`. A
|
|
113
|
+
compatible C-extension backend is planned for a future release.
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
<!-- ########################### end of file ########################### -->
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# p99.Ruby Guides <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
Task-oriented guidance for using **p99.Ruby**.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Table of Contents <!-- omit in toc -->
|
|
7
|
+
|
|
8
|
+
- [Guides](#guides)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Guides
|
|
12
|
+
|
|
13
|
+
* [Recording and reading percentiles](./recording-and-reading-percentiles.md)
|
|
14
|
+
explains time units, common and custom percentile queries, approximation,
|
|
15
|
+
and empty or overflowing histograms;
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
<!-- ########################### end of file ########################### -->
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# p99.Ruby - Recording and Reading Percentiles <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
This guide shows how to record event durations with `P99::Histogram` and
|
|
4
|
+
interpret its percentile results.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## Table of Contents <!-- omit in toc -->
|
|
8
|
+
|
|
9
|
+
- [Create a histogram](#create-a-histogram)
|
|
10
|
+
- [Record event durations](#record-event-durations)
|
|
11
|
+
- [Choose a time unit](#choose-a-time-unit)
|
|
12
|
+
- [Read common percentiles](#read-common-percentiles)
|
|
13
|
+
- [Read custom percentiles](#read-custom-percentiles)
|
|
14
|
+
- [Interpret approximate values](#interpret-approximate-values)
|
|
15
|
+
- [Handle empty and overflowing histograms](#handle-empty-and-overflowing-histograms)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## Create a histogram
|
|
19
|
+
|
|
20
|
+
Require the library and create an empty histogram:
|
|
21
|
+
|
|
22
|
+
```Ruby
|
|
23
|
+
require 'p99'
|
|
24
|
+
|
|
25
|
+
histogram = P99::Histogram.new
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The histogram has a fixed 64-bucket storage model, so its memory use does not
|
|
29
|
+
grow with the number of recorded events.
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
## Record event durations
|
|
33
|
+
|
|
34
|
+
Record each completed operation as an event. Select the method whose suffix
|
|
35
|
+
matches the unit of the duration:
|
|
36
|
+
|
|
37
|
+
```Ruby
|
|
38
|
+
histogram.push_event_time_ns(database_time_ns)
|
|
39
|
+
histogram.push_event_time_us(cache_time_us)
|
|
40
|
+
histogram.push_event_time_ms(request_time_ms)
|
|
41
|
+
histogram.push_event_time_s(batch_time_s)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Each method converts its argument to nanoseconds. A successful push returns
|
|
45
|
+
`true`; an invalid duration or a duration rejected after overflow returns
|
|
46
|
+
`false`.
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
## Choose a time unit
|
|
50
|
+
|
|
51
|
+
Use the unit that matches the value already produced by the measuring code:
|
|
52
|
+
|
|
53
|
+
* Use nanoseconds for APIs that already report high-resolution monotonic time;
|
|
54
|
+
* Use microseconds or milliseconds when those are the native measurement units;
|
|
55
|
+
* Use seconds for coarse-grained operations or externally supplied durations;
|
|
56
|
+
|
|
57
|
+
The stored and returned values are always nanoseconds, regardless of the input
|
|
58
|
+
method used.
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
## Read common percentiles
|
|
62
|
+
|
|
63
|
+
Read the percentile that matches the question being asked:
|
|
64
|
+
|
|
65
|
+
```Ruby
|
|
66
|
+
p50 = histogram.value_at_p50
|
|
67
|
+
p90 = histogram.value_at_p90
|
|
68
|
+
p99 = histogram.value_at_p99
|
|
69
|
+
p999 = histogram.value_at_p99_9
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
For example, p99 is useful when the slowest one percent of observations
|
|
73
|
+
matters. A percentile result is expressed in nanoseconds.
|
|
74
|
+
|
|
75
|
+
The fixed set can be read as a hash:
|
|
76
|
+
|
|
77
|
+
```Ruby
|
|
78
|
+
histogram.fixed_percentiles
|
|
79
|
+
# => { "p50" => ..., "p75" => ..., "p90" => ..., "p99" => ... }
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
## Read custom percentiles
|
|
84
|
+
|
|
85
|
+
Use `value_at_percentile` for one custom level:
|
|
86
|
+
|
|
87
|
+
```Ruby
|
|
88
|
+
histogram.value_at_percentile(99.5)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Use `values_at_percentiles` when several levels are needed:
|
|
92
|
+
|
|
93
|
+
```Ruby
|
|
94
|
+
histogram.values_at_percentiles([ 50.0, 90.0, 99.0, 99.9 ])
|
|
95
|
+
# => [ [50.0, ...], [90.0, ...], [99.0, ...], [99.9, ...] ]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Percentiles are expressed as values from 0.0 to 100.0. Values outside that
|
|
99
|
+
range are clamped to the nearest endpoint.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
## Interpret approximate values
|
|
103
|
+
|
|
104
|
+
`P99::Histogram` uses 64 logarithmic power-of-two buckets and linearly
|
|
105
|
+
interpolates within the bucket containing the requested rank. Results are
|
|
106
|
+
therefore estimates, not exact values from a retained sample set.
|
|
107
|
+
|
|
108
|
+
Use the histogram for stable operational summaries and comparisons. If exact
|
|
109
|
+
sample retrieval or arbitrary quantile algorithms are required, use a data
|
|
110
|
+
structure designed to retain or sort the individual observations.
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
## Handle empty and overflowing histograms
|
|
114
|
+
|
|
115
|
+
Percentile and minimum/maximum queries return `nil` for an empty histogram:
|
|
116
|
+
|
|
117
|
+
```Ruby
|
|
118
|
+
histogram.value_at_p99 # => nil
|
|
119
|
+
histogram.min_event_time # => nil
|
|
120
|
+
histogram.max_event_time # => nil
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`event_time_total` returns `nil` after the running total overflows. Use
|
|
124
|
+
`event_time_total_raw` to inspect the accumulated value and
|
|
125
|
+
`has_overflowed?` to check the overflow state. Rejected pushes return `false`.
|
|
126
|
+
|
|
127
|
+
Call `clear` to reset the histogram and begin a new measurement interval:
|
|
128
|
+
|
|
129
|
+
```Ruby
|
|
130
|
+
histogram.clear
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
<!-- ########################### end of file ########################### -->
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# p99.Ruby Generated API Reference <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
The generated API reference is produced by RDoc from the Ruby source
|
|
4
|
+
documentation comments. It complements the authored Histogram documentation:
|
|
5
|
+
|
|
6
|
+
* [`docs/components/histogram.md`](../components/histogram.md) explains the
|
|
7
|
+
component's loading, recording, statistics, percentile, and backend APIs;
|
|
8
|
+
* generated `doc/` explains the complete public Ruby API;
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Generate the reference
|
|
12
|
+
|
|
13
|
+
From the project directory, run:
|
|
14
|
+
|
|
15
|
+
```Shell
|
|
16
|
+
./generate_rdoc.sh
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The script removes previous generated output and writes the new reference to
|
|
20
|
+
`doc/` by default. Use `--pwd` to operate in the caller's current directory,
|
|
21
|
+
or set `SIS_RDOC_DOC_DIR` to choose another generated-document directory.
|
|
22
|
+
Generated files are build output and should not be edited by hand.
|
|
23
|
+
|
|
24
|
+
To check that every documentable API entity has RDoc documentation, run:
|
|
25
|
+
|
|
26
|
+
```Shell
|
|
27
|
+
./generate_rdoc.sh --coverage-report
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
## Reading the reference
|
|
32
|
+
|
|
33
|
+
Use the generated namespace and method pages for exact signatures and
|
|
34
|
+
source-level API details. Start with the authored component documentation when
|
|
35
|
+
deciding how to use `P99::Histogram`, then use RDoc to inspect the complete
|
|
36
|
+
method surface.
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
<!-- ########################### end of file ########################### -->
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# p99.Ruby Example - **build_histogram**
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
Example illustrating use of `P99::Histogram` to record event durations
|
|
6
|
+
generated by `sleep` delays under a simple PRNG, then print a histogram
|
|
7
|
+
summary and percentile values.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## Source
|
|
11
|
+
|
|
12
|
+
See [build_histogram.rb](./build_histogram.rb).
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## Execution
|
|
16
|
+
|
|
17
|
+
The number of iterations can be configured via the `P99_TRIES` environment
|
|
18
|
+
variable:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Run with the default of 100 tries
|
|
22
|
+
ruby examples/build_histogram.rb
|
|
23
|
+
|
|
24
|
+
# Run with 1000 tries
|
|
25
|
+
P99_TRIES=1000 ruby examples/build_histogram.rb
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## Representative output
|
|
30
|
+
|
|
31
|
+
The timing values vary by machine and scheduler. A short run produces output
|
|
32
|
+
like:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
Running Histogram example with 3 tries...
|
|
36
|
+
(backend: ruby)
|
|
37
|
+
|
|
38
|
+
Histogram summary:
|
|
39
|
+
Histogram{
|
|
40
|
+
implementation: ruby
|
|
41
|
+
event_count: 3
|
|
42
|
+
event_time_total: 1713000
|
|
43
|
+
has_overflowed: false
|
|
44
|
+
min_event_time: 319000
|
|
45
|
+
max_event_time: 782000
|
|
46
|
+
buckets: {18: 1, 19: 2}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
Percentiles (approximated):
|
|
50
|
+
p50 (f64): 655360 ns
|
|
51
|
+
p50 (integer): 524287 ns
|
|
52
|
+
p75 (integer): 782000 ns
|
|
53
|
+
p99 (integer): 782000 ns
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
<!-- ########################### end of file ########################### -->
|