desna-interval 0.0.1__tar.gz
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.
- desna_interval-0.0.1/CHANGELOG.md +29 -0
- desna_interval-0.0.1/CITATION.cff +35 -0
- desna_interval-0.0.1/LICENSE +21 -0
- desna_interval-0.0.1/PKG-INFO +175 -0
- desna_interval-0.0.1/README.md +139 -0
- desna_interval-0.0.1/README.ru.md +138 -0
- desna_interval-0.0.1/docs/en/api.md +69 -0
- desna_interval-0.0.1/docs/en/cli.md +49 -0
- desna_interval-0.0.1/docs/en/publishing.md +19 -0
- desna_interval-0.0.1/docs/en/quickstart.md +72 -0
- desna_interval-0.0.1/docs/en/theory.md +104 -0
- desna_interval-0.0.1/docs/ru/api.md +68 -0
- desna_interval-0.0.1/docs/ru/cli.md +49 -0
- desna_interval-0.0.1/docs/ru/publishing.md +19 -0
- desna_interval-0.0.1/docs/ru/quickstart.md +72 -0
- desna_interval-0.0.1/docs/ru/theory.md +101 -0
- desna_interval-0.0.1/examples/01_quickstart.py +24 -0
- desna_interval-0.0.1/examples/02_expected_cost.py +35 -0
- desna_interval-0.0.1/examples/03_replay_trace.py +42 -0
- desna_interval-0.0.1/examples/04_kalman_adapter.py +24 -0
- desna_interval-0.0.1/experiments/README.md +402 -0
- desna_interval-0.0.1/experiments/README.ru.md +395 -0
- desna_interval-0.0.1/experiments/_sim/__init__.py +19 -0
- desna_interval-0.0.1/experiments/_sim/bootstrap.py +50 -0
- desna_interval-0.0.1/experiments/_sim/cases.py +80 -0
- desna_interval-0.0.1/experiments/_sim/config.py +195 -0
- desna_interval-0.0.1/experiments/_sim/families.py +168 -0
- desna_interval-0.0.1/experiments/_sim/live.py +207 -0
- desna_interval-0.0.1/experiments/_sim/metrics.py +117 -0
- desna_interval-0.0.1/experiments/_sim/plotstyle.py +94 -0
- desna_interval-0.0.1/experiments/_sim/replay.py +230 -0
- desna_interval-0.0.1/experiments/_sim/strategies.py +143 -0
- desna_interval-0.0.1/experiments/_sim/synthetic.py +158 -0
- desna_interval-0.0.1/experiments/_sim/traces.py +81 -0
- desna_interval-0.0.1/experiments/build_traces.py +108 -0
- desna_interval-0.0.1/experiments/config.toml +197 -0
- desna_interval-0.0.1/experiments/day_report.py +709 -0
- desna_interval-0.0.1/experiments/day_run.py +857 -0
- desna_interval-0.0.1/experiments/day_schedule.py +313 -0
- desna_interval-0.0.1/experiments/e1_theory.py +200 -0
- desna_interval-0.0.1/experiments/e2_compare.py +134 -0
- desna_interval-0.0.1/experiments/e3_lag.py +131 -0
- desna_interval-0.0.1/experiments/e4_live.py +355 -0
- desna_interval-0.0.1/experiments/e5_sensitivity.py +119 -0
- desna_interval-0.0.1/experiments/guest_access.py +238 -0
- desna_interval-0.0.1/experiments/run_all.ps1 +29 -0
- desna_interval-0.0.1/experiments/run_all.sh +25 -0
- desna_interval-0.0.1/experiments/run_day.ps1 +32 -0
- desna_interval-0.0.1/experiments/run_day.sh +41 -0
- desna_interval-0.0.1/experiments/testbed/README.txt +4 -0
- desna_interval-0.0.1/experiments/testbed/burst_load.py +184 -0
- desna_interval-0.0.1/experiments/testbed/guest_recorder.py +191 -0
- desna_interval-0.0.1/experiments/testbed/make_vms.sh +118 -0
- desna_interval-0.0.1/pyproject.toml +252 -0
- desna_interval-0.0.1/pyproject.toml.orig +160 -0
- desna_interval-0.0.1/scripts/check_commit_msg.py +78 -0
- desna_interval-0.0.1/scripts/commit-msg +4 -0
- desna_interval-0.0.1/scripts/install_hooks.sh +7 -0
- desna_interval-0.0.1/src/desna_interval/__init__.py +77 -0
- desna_interval-0.0.1/src/desna_interval/cli.py +96 -0
- desna_interval-0.0.1/src/desna_interval/estimators.py +270 -0
- desna_interval-0.0.1/src/desna_interval/libvirt_loop.py +202 -0
- desna_interval-0.0.1/src/desna_interval/py.typed +0 -0
- desna_interval-0.0.1/src/desna_interval/replay.py +192 -0
- desna_interval-0.0.1/src/desna_interval/rule.py +166 -0
- desna_interval-0.0.1/src/desna_interval/scheduler.py +110 -0
- desna_interval-0.0.1/tests/data/synthetic_reference.json +258 -0
- desna_interval-0.0.1/tests/test_core.py +279 -0
- desna_interval-0.0.1/tests/test_day_schedule.py +230 -0
- desna_interval-0.0.1/tests/test_docs.py +41 -0
- desna_interval-0.0.1/tests/test_examples.py +22 -0
- desna_interval-0.0.1/tests/test_experiments.py +204 -0
- desna_interval-0.0.1/tests/test_guest_access.py +302 -0
- desna_interval-0.0.1/tests/test_replay_cli.py +123 -0
- desna_interval-0.0.1/tests/test_sim_reference.py +45 -0
- desna_interval-0.0.1/tests/test_two_days.py +396 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes of desna-interval are documented here. The project follows
|
|
4
|
+
[Semantic Versioning](https://semver.org). Russian summary: the same entries
|
|
5
|
+
apply; the documentation is in `docs/ru/`.
|
|
6
|
+
|
|
7
|
+
## 0.0.1 — 2026-11-11
|
|
8
|
+
|
|
9
|
+
First release: the monitoring-interval rule of article 1 (A. Ferubko, O. Kazakov, BGITU).
|
|
10
|
+
Renamed from `deficit-interval` (module `deficit_interval`) before publication.
|
|
11
|
+
|
|
12
|
+
* Rule `delta* = s/v + sqrt(2 eps/v)` with the age of the snapshot
|
|
13
|
+
(`interval_unclipped`, `next_interval`, `next_interval_aged`, `min_slack`).
|
|
14
|
+
* Expected-cost optimum `x^3/3 + s x^2/2 = c v^2 / rho` (`expected_cost_rate`,
|
|
15
|
+
`optimal_interval_expected`), claim 1.5.
|
|
16
|
+
* Bounds on the growth rate `v`: `history_quantile`, `pooled_quantile`,
|
|
17
|
+
`WindowQuantile`, `FixedRate`, the scalar Kalman filter `KalmanRate` and the
|
|
18
|
+
adapter `RateFilterAdapter` for any filter with `rate()`; `burst_rate`.
|
|
19
|
+
* Per-object or common schedule (`MonitorScheduler`) and the protocol
|
|
20
|
+
`IntervalScheduler` for other schedules.
|
|
21
|
+
* Offline replay of policies on a trace (`replay`, `FixedPolicy`, `BackoffPolicy`,
|
|
22
|
+
`DeficitRulePolicy`, `ExpectedCostPolicy`) and the command line `desna-interval`.
|
|
23
|
+
* Live loop for libvirt guests (`libvirt_loop.run`, with an optional `scheduler`)
|
|
24
|
+
with snapshot age and an optional adaptation of the statistics period; it imports
|
|
25
|
+
without libvirt.
|
|
26
|
+
* Experiments E1–E5 of article 1 in `experiments/` (optional group `experiments`):
|
|
27
|
+
scripts with `--smoke`, one configuration file, outputs as CSV and PDF/PNG,
|
|
28
|
+
a synthetic generator bit-identical with the prototype, held-out scenario D.
|
|
29
|
+
* Documentation in English and Russian, four examples, tests.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite it as below."
|
|
3
|
+
type: software
|
|
4
|
+
title: "desna-interval: monitoring interval from a tolerance on accumulated deficit"
|
|
5
|
+
abstract: >-
|
|
6
|
+
A Python library that chooses the polling interval of a virtual machine's
|
|
7
|
+
memory from a tolerance on the accumulated deficit: the rule
|
|
8
|
+
delta* = s/v + sqrt(2 eps/v), the correction for the age of a late snapshot,
|
|
9
|
+
the expected-cost optimum, the Jensen bound on the benefit of adaptation,
|
|
10
|
+
estimators of the growth rate (including a Kalman adapter), and a live loop
|
|
11
|
+
for KVM guests through libvirt.
|
|
12
|
+
version: 0.0.1
|
|
13
|
+
date-released: 2026-11-11
|
|
14
|
+
license: MIT
|
|
15
|
+
repository-code: "https://github.com/89605502155/desna-interval"
|
|
16
|
+
url: "https://github.com/89605502155/desna-interval"
|
|
17
|
+
keywords:
|
|
18
|
+
- memory ballooning
|
|
19
|
+
- monitoring interval
|
|
20
|
+
- accumulated deficit
|
|
21
|
+
- virtual machines
|
|
22
|
+
- KVM
|
|
23
|
+
- libvirt
|
|
24
|
+
- virtio-balloon
|
|
25
|
+
authors:
|
|
26
|
+
- family-names: Ferubko
|
|
27
|
+
given-names: Andrey
|
|
28
|
+
email: ferubko1999@yandex.ru
|
|
29
|
+
orcid: "https://orcid.org/0009-0006-5625-137X"
|
|
30
|
+
affiliation: "Bryansk State Engineering-Technological University (BGITU)"
|
|
31
|
+
- family-names: Kazakov
|
|
32
|
+
given-names: Oleg
|
|
33
|
+
email: kazakov@bgitu.ru
|
|
34
|
+
orcid: "https://orcid.org/0000-0001-9665-8138"
|
|
35
|
+
affiliation: "Bryansk State Engineering-Technological University (BGITU)"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andrey Ferubko, Oleg Kazakov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: desna-interval
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Monitoring interval from a tolerance on accumulated deficit: the rule delta* = s/v + sqrt(2 eps/v), aged snapshots, expected-cost optimum and a libvirt loop for KVM memory ballooning
|
|
5
|
+
Keywords: kvm,libvirt,virtio-balloon,memory-ballooning,monitoring-interval,adaptive-sampling,accumulated-deficit,virtual-machines,polling
|
|
6
|
+
Author: Andrey Ferubko, Oleg Kazakov
|
|
7
|
+
Author-email: Andrey Ferubko <ferubko1999@yandex.ru>, Oleg Kazakov <kazakov@bgitu.ru>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Intended Audience :: System Administrators
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
23
|
+
Classifier: Topic :: System :: Monitoring
|
|
24
|
+
Classifier: Topic :: System :: Operating System Kernels :: Linux
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Dist: numpy>=1.26
|
|
27
|
+
Requires-Dist: libvirt-python>=8.0 ; extra == 'libvirt'
|
|
28
|
+
Requires-Python: >=3.11
|
|
29
|
+
Project-URL: Homepage, https://github.com/89605502155/desna-interval
|
|
30
|
+
Project-URL: Documentation, https://github.com/89605502155/desna-interval/tree/main/docs
|
|
31
|
+
Project-URL: Repository, https://github.com/89605502155/desna-interval
|
|
32
|
+
Project-URL: Issues, https://github.com/89605502155/desna-interval/issues
|
|
33
|
+
Project-URL: Changelog, https://github.com/89605502155/desna-interval/blob/main/CHANGELOG.md
|
|
34
|
+
Provides-Extra: libvirt
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# desna-interval
|
|
38
|
+
|
|
39
|
+
[](https://pypi.org/project/desna-interval/)
|
|
40
|
+
[](https://pypi.org/project/desna-interval/)
|
|
41
|
+
[](https://github.com/89605502155/desna-interval/blob/main/LICENSE)
|
|
42
|
+
|
|
43
|
+
**How often to poll a resource so that the deficit accumulated between two polls stays below a tolerance.**
|
|
44
|
+
|
|
45
|
+
desna-interval chooses the monitoring interval of a virtual machine from a
|
|
46
|
+
tolerance on its accumulated memory deficit. Built for memory ballooning of KVM
|
|
47
|
+
guests through libvirt; the rule is generic for any quantity whose growth rate
|
|
48
|
+
is bounded.
|
|
49
|
+
|
|
50
|
+
If demand grows no faster than `v` and the slack after a decision is `s`, the
|
|
51
|
+
deficit over a blind gap of length `Δ` is at most `(vΔ − s)⁺² / (2v)`. The
|
|
52
|
+
largest interval that keeps this below the tolerance `ε` is
|
|
53
|
+
|
|
54
|
+
Δ* = s/v + √(2ε/v)
|
|
55
|
+
|
|
56
|
+
With a snapshot that is `a` seconds old (virtio-balloon statistics arrive late),
|
|
57
|
+
the guarantee holds for `Δ* − a`.
|
|
58
|
+
|
|
59
|
+
Русская версия: [README.ru.md](https://github.com/89605502155/desna-interval/blob/main/README.ru.md).
|
|
60
|
+
Documentation: [English](https://github.com/89605502155/desna-interval/tree/main/docs/en) ·
|
|
61
|
+
[Русский](https://github.com/89605502155/desna-interval/tree/main/docs/ru) ·
|
|
62
|
+
[Changelog](https://github.com/89605502155/desna-interval/blob/main/CHANGELOG.md) ·
|
|
63
|
+
[Issues](https://github.com/89605502155/desna-interval/issues)
|
|
64
|
+
|
|
65
|
+
The library accompanies article 1 of the series by Andrey Ferubko, Bryansk State
|
|
66
|
+
Engineering-Technological University (BGITU). Theory:
|
|
67
|
+
[docs/en/theory.md](https://github.com/89605502155/desna-interval/blob/main/docs/en/theory.md).
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
pip install desna-interval # core: numpy only
|
|
73
|
+
pip install "desna-interval[libvirt]" # live loop on a KVM host
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Requires Python 3.11 or newer.
|
|
77
|
+
|
|
78
|
+
## Quick start
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from desna_interval import MonitorScheduler, WindowQuantile, next_interval_aged
|
|
82
|
+
|
|
83
|
+
next_interval_aged(s=256, v=128, eps=128, age=0.0) # -> 3.414 s, fresh snapshot
|
|
84
|
+
next_interval_aged(s=256, v=128, eps=128, age=1.0) # -> 2.414 s, snapshot 1 s old
|
|
85
|
+
|
|
86
|
+
sched = MonitorScheduler(["vm1", "vm2"], eps=128, estimator_factory=WindowQuantile)
|
|
87
|
+
sched.observe(now=0.0, demand={"vm1": 1000, "vm2": 3000}, slack={"vm1": 256, "vm2": 64})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Command line:
|
|
91
|
+
|
|
92
|
+
desna-interval interval --slack 256 --rate 128 --eps 128 --age 1
|
|
93
|
+
desna-interval optimal --slack 0 --rate 128 --rho 0.01 --cost 64
|
|
94
|
+
desna-interval replay trace.csv --eps 64 --slack 256
|
|
95
|
+
|
|
96
|
+
## How it differs from existing packages
|
|
97
|
+
|
|
98
|
+
Packages on PyPI that poll or sample adaptively, such as `python-adaptive`,
|
|
99
|
+
choose sample points to reduce the error of a function or a metric. Retry
|
|
100
|
+
packages such as `backoff` and `tenacity` implement back-off for failed calls,
|
|
101
|
+
and scheduling packages such as `APScheduler` only run jobs at given times.
|
|
102
|
+
None of them maps a tolerance on a resource deficit to a polling interval.
|
|
103
|
+
|
|
104
|
+
| Feature | desna-interval | generic adaptive sampling / polling packages |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| Interval from a tolerance on accumulated deficit, `Δ* = s/v + √(2ε/v)` | yes | no, they target metric or function error |
|
|
107
|
+
| Correction for the age of a late snapshot | yes | no |
|
|
108
|
+
| Expected-cost optimum for a known burst rate and poll price | yes | no |
|
|
109
|
+
| Bound on the growth rate from history, pooled over similar guests, or from a Kalman filter | yes | no |
|
|
110
|
+
| Live loop for libvirt guests (`memoryStats`, balloon targets) | yes | no |
|
|
111
|
+
| Replay of policies on a trace with the deficit as the metric | yes | no |
|
|
112
|
+
|
|
113
|
+
The rule is only as good as the bound `v`: see the theory document for when
|
|
114
|
+
it holds and when it does not.
|
|
115
|
+
|
|
116
|
+
## When it helps and when it does not
|
|
117
|
+
|
|
118
|
+
The rule bounds the deficit of each blind gap. The gain over a constant interval
|
|
119
|
+
depends on the workload:
|
|
120
|
+
|
|
121
|
+
- For identical machines with memoryless bursts no adaptive schedule beats a
|
|
122
|
+
constant interval with the same poll budget (claim 1.4, Jensen). The library does not
|
|
123
|
+
pretend otherwise.
|
|
124
|
+
- The gain comes from differences between machines, and the rule states a bound on
|
|
125
|
+
the deficit of each gap, which generic back-off does not.
|
|
126
|
+
- The guarantee is only as good as the bound on `v`. Use a long-history quantile
|
|
127
|
+
or a pooled bound for similar machines.
|
|
128
|
+
|
|
129
|
+
The comparison of the strategies (synthetic traces now, testbed traces for the
|
|
130
|
+
article) is the experiment E2 in [experiments/README.md](experiments/README.md).
|
|
131
|
+
Synthetic results show behaviour only.
|
|
132
|
+
|
|
133
|
+
## Authors
|
|
134
|
+
|
|
135
|
+
- Andrey Ferubko (Андрей Ферубко), ORCID [0009-0006-5625-137X](https://orcid.org/0009-0006-5625-137X)
|
|
136
|
+
- Oleg Kazakov (Олег Дмитриевич Казаков), ORCID [0000-0001-9665-8138](https://orcid.org/0000-0001-9665-8138)
|
|
137
|
+
|
|
138
|
+
Bryansk State Engineering-Technological University (BGITU).
|
|
139
|
+
|
|
140
|
+
## Modules
|
|
141
|
+
|
|
142
|
+
| Module | Contents |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `rule` | `blind_deficit_bound`, `interval_unclipped`, `next_interval`, `next_interval_aged`, `min_slack`, `expected_cost_rate`, `optimal_interval_expected` |
|
|
145
|
+
| `estimators` | bounds on `v`: `history_quantile`, `pooled_quantile`, `WindowQuantile`, `FixedRate`, `KalmanRate`, `RateFilterAdapter`; `burst_rate` |
|
|
146
|
+
| `scheduler` | `MonitorScheduler`, one interval per object or a common one; the `IntervalScheduler` protocol for other schedules |
|
|
147
|
+
| `replay` | `replay` and the policies `FixedPolicy`, `BackoffPolicy`, `DeficitRulePolicy`, `ExpectedCostPolicy` |
|
|
148
|
+
| `libvirt_loop` | `run` (optional `scheduler`), `read_state`, `reserve_controller`: the live loop |
|
|
149
|
+
|
|
150
|
+
## Development
|
|
151
|
+
|
|
152
|
+
```sh
|
|
153
|
+
uv sync
|
|
154
|
+
uv run ruff check . && uv run ruff format --check .
|
|
155
|
+
uv run mypy
|
|
156
|
+
uv run pytest
|
|
157
|
+
bash scripts/install_hooks.sh # once per clone: commit message limits
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The experiments of article 1 need the optional group `experiments` (matplotlib):
|
|
161
|
+
`uv sync --group experiments`. Their smoke modes run in `pytest`; the full runs are
|
|
162
|
+
described in [experiments/README.md](experiments/README.md).
|
|
163
|
+
|
|
164
|
+
Commit messages in this repository have a subject of at most 8 characters and
|
|
165
|
+
no body. The `commit-msg` hook installed by `scripts/install_hooks.sh` enforces it
|
|
166
|
+
(`scripts/check_commit_msg.py`). There is no CI and no automatic publishing.
|
|
167
|
+
|
|
168
|
+
## Citation
|
|
169
|
+
|
|
170
|
+
See [CITATION.cff](https://github.com/89605502155/desna-interval/blob/main/CITATION.cff)
|
|
171
|
+
or the "Cite this repository" button on GitHub.
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
MIT. Copyright (c) 2026 Andrey Ferubko, Oleg Kazakov. See [LICENSE](https://github.com/89605502155/desna-interval/blob/main/LICENSE).
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# desna-interval
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/desna-interval/)
|
|
4
|
+
[](https://pypi.org/project/desna-interval/)
|
|
5
|
+
[](https://github.com/89605502155/desna-interval/blob/main/LICENSE)
|
|
6
|
+
|
|
7
|
+
**How often to poll a resource so that the deficit accumulated between two polls stays below a tolerance.**
|
|
8
|
+
|
|
9
|
+
desna-interval chooses the monitoring interval of a virtual machine from a
|
|
10
|
+
tolerance on its accumulated memory deficit. Built for memory ballooning of KVM
|
|
11
|
+
guests through libvirt; the rule is generic for any quantity whose growth rate
|
|
12
|
+
is bounded.
|
|
13
|
+
|
|
14
|
+
If demand grows no faster than `v` and the slack after a decision is `s`, the
|
|
15
|
+
deficit over a blind gap of length `Δ` is at most `(vΔ − s)⁺² / (2v)`. The
|
|
16
|
+
largest interval that keeps this below the tolerance `ε` is
|
|
17
|
+
|
|
18
|
+
Δ* = s/v + √(2ε/v)
|
|
19
|
+
|
|
20
|
+
With a snapshot that is `a` seconds old (virtio-balloon statistics arrive late),
|
|
21
|
+
the guarantee holds for `Δ* − a`.
|
|
22
|
+
|
|
23
|
+
Русская версия: [README.ru.md](https://github.com/89605502155/desna-interval/blob/main/README.ru.md).
|
|
24
|
+
Documentation: [English](https://github.com/89605502155/desna-interval/tree/main/docs/en) ·
|
|
25
|
+
[Русский](https://github.com/89605502155/desna-interval/tree/main/docs/ru) ·
|
|
26
|
+
[Changelog](https://github.com/89605502155/desna-interval/blob/main/CHANGELOG.md) ·
|
|
27
|
+
[Issues](https://github.com/89605502155/desna-interval/issues)
|
|
28
|
+
|
|
29
|
+
The library accompanies article 1 of the series by Andrey Ferubko, Bryansk State
|
|
30
|
+
Engineering-Technological University (BGITU). Theory:
|
|
31
|
+
[docs/en/theory.md](https://github.com/89605502155/desna-interval/blob/main/docs/en/theory.md).
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
pip install desna-interval # core: numpy only
|
|
37
|
+
pip install "desna-interval[libvirt]" # live loop on a KVM host
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Requires Python 3.11 or newer.
|
|
41
|
+
|
|
42
|
+
## Quick start
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from desna_interval import MonitorScheduler, WindowQuantile, next_interval_aged
|
|
46
|
+
|
|
47
|
+
next_interval_aged(s=256, v=128, eps=128, age=0.0) # -> 3.414 s, fresh snapshot
|
|
48
|
+
next_interval_aged(s=256, v=128, eps=128, age=1.0) # -> 2.414 s, snapshot 1 s old
|
|
49
|
+
|
|
50
|
+
sched = MonitorScheduler(["vm1", "vm2"], eps=128, estimator_factory=WindowQuantile)
|
|
51
|
+
sched.observe(now=0.0, demand={"vm1": 1000, "vm2": 3000}, slack={"vm1": 256, "vm2": 64})
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Command line:
|
|
55
|
+
|
|
56
|
+
desna-interval interval --slack 256 --rate 128 --eps 128 --age 1
|
|
57
|
+
desna-interval optimal --slack 0 --rate 128 --rho 0.01 --cost 64
|
|
58
|
+
desna-interval replay trace.csv --eps 64 --slack 256
|
|
59
|
+
|
|
60
|
+
## How it differs from existing packages
|
|
61
|
+
|
|
62
|
+
Packages on PyPI that poll or sample adaptively, such as `python-adaptive`,
|
|
63
|
+
choose sample points to reduce the error of a function or a metric. Retry
|
|
64
|
+
packages such as `backoff` and `tenacity` implement back-off for failed calls,
|
|
65
|
+
and scheduling packages such as `APScheduler` only run jobs at given times.
|
|
66
|
+
None of them maps a tolerance on a resource deficit to a polling interval.
|
|
67
|
+
|
|
68
|
+
| Feature | desna-interval | generic adaptive sampling / polling packages |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| Interval from a tolerance on accumulated deficit, `Δ* = s/v + √(2ε/v)` | yes | no, they target metric or function error |
|
|
71
|
+
| Correction for the age of a late snapshot | yes | no |
|
|
72
|
+
| Expected-cost optimum for a known burst rate and poll price | yes | no |
|
|
73
|
+
| Bound on the growth rate from history, pooled over similar guests, or from a Kalman filter | yes | no |
|
|
74
|
+
| Live loop for libvirt guests (`memoryStats`, balloon targets) | yes | no |
|
|
75
|
+
| Replay of policies on a trace with the deficit as the metric | yes | no |
|
|
76
|
+
|
|
77
|
+
The rule is only as good as the bound `v`: see the theory document for when
|
|
78
|
+
it holds and when it does not.
|
|
79
|
+
|
|
80
|
+
## When it helps and when it does not
|
|
81
|
+
|
|
82
|
+
The rule bounds the deficit of each blind gap. The gain over a constant interval
|
|
83
|
+
depends on the workload:
|
|
84
|
+
|
|
85
|
+
- For identical machines with memoryless bursts no adaptive schedule beats a
|
|
86
|
+
constant interval with the same poll budget (claim 1.4, Jensen). The library does not
|
|
87
|
+
pretend otherwise.
|
|
88
|
+
- The gain comes from differences between machines, and the rule states a bound on
|
|
89
|
+
the deficit of each gap, which generic back-off does not.
|
|
90
|
+
- The guarantee is only as good as the bound on `v`. Use a long-history quantile
|
|
91
|
+
or a pooled bound for similar machines.
|
|
92
|
+
|
|
93
|
+
The comparison of the strategies (synthetic traces now, testbed traces for the
|
|
94
|
+
article) is the experiment E2 in [experiments/README.md](experiments/README.md).
|
|
95
|
+
Synthetic results show behaviour only.
|
|
96
|
+
|
|
97
|
+
## Authors
|
|
98
|
+
|
|
99
|
+
- Andrey Ferubko (Андрей Ферубко), ORCID [0009-0006-5625-137X](https://orcid.org/0009-0006-5625-137X)
|
|
100
|
+
- Oleg Kazakov (Олег Дмитриевич Казаков), ORCID [0000-0001-9665-8138](https://orcid.org/0000-0001-9665-8138)
|
|
101
|
+
|
|
102
|
+
Bryansk State Engineering-Technological University (BGITU).
|
|
103
|
+
|
|
104
|
+
## Modules
|
|
105
|
+
|
|
106
|
+
| Module | Contents |
|
|
107
|
+
|---|---|
|
|
108
|
+
| `rule` | `blind_deficit_bound`, `interval_unclipped`, `next_interval`, `next_interval_aged`, `min_slack`, `expected_cost_rate`, `optimal_interval_expected` |
|
|
109
|
+
| `estimators` | bounds on `v`: `history_quantile`, `pooled_quantile`, `WindowQuantile`, `FixedRate`, `KalmanRate`, `RateFilterAdapter`; `burst_rate` |
|
|
110
|
+
| `scheduler` | `MonitorScheduler`, one interval per object or a common one; the `IntervalScheduler` protocol for other schedules |
|
|
111
|
+
| `replay` | `replay` and the policies `FixedPolicy`, `BackoffPolicy`, `DeficitRulePolicy`, `ExpectedCostPolicy` |
|
|
112
|
+
| `libvirt_loop` | `run` (optional `scheduler`), `read_state`, `reserve_controller`: the live loop |
|
|
113
|
+
|
|
114
|
+
## Development
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
uv sync
|
|
118
|
+
uv run ruff check . && uv run ruff format --check .
|
|
119
|
+
uv run mypy
|
|
120
|
+
uv run pytest
|
|
121
|
+
bash scripts/install_hooks.sh # once per clone: commit message limits
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The experiments of article 1 need the optional group `experiments` (matplotlib):
|
|
125
|
+
`uv sync --group experiments`. Their smoke modes run in `pytest`; the full runs are
|
|
126
|
+
described in [experiments/README.md](experiments/README.md).
|
|
127
|
+
|
|
128
|
+
Commit messages in this repository have a subject of at most 8 characters and
|
|
129
|
+
no body. The `commit-msg` hook installed by `scripts/install_hooks.sh` enforces it
|
|
130
|
+
(`scripts/check_commit_msg.py`). There is no CI and no automatic publishing.
|
|
131
|
+
|
|
132
|
+
## Citation
|
|
133
|
+
|
|
134
|
+
See [CITATION.cff](https://github.com/89605502155/desna-interval/blob/main/CITATION.cff)
|
|
135
|
+
or the "Cite this repository" button on GitHub.
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT. Copyright (c) 2026 Andrey Ferubko, Oleg Kazakov. See [LICENSE](https://github.com/89605502155/desna-interval/blob/main/LICENSE).
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# desna-interval
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/desna-interval/)
|
|
4
|
+
[](https://pypi.org/project/desna-interval/)
|
|
5
|
+
[](https://github.com/89605502155/desna-interval/blob/main/LICENSE)
|
|
6
|
+
|
|
7
|
+
**Как часто опрашивать ресурс, чтобы накопленный между опросами дефицит оставался ниже допуска.**
|
|
8
|
+
|
|
9
|
+
desna-interval выбирает интервал мониторинга виртуальной машины по допуску на
|
|
10
|
+
накопленный дефицит памяти. Создан для баллонирования памяти ВМ KVM через libvirt;
|
|
11
|
+
правило общее для любой величины с ограниченной скоростью роста.
|
|
12
|
+
|
|
13
|
+
Если потребность растёт не быстрее `v`, а запас после решения равен `s`, то дефицит
|
|
14
|
+
за слепой промежуток длины `Δ` не превышает `(vΔ − s)⁺² / (2v)`. Наибольший интервал,
|
|
15
|
+
при котором дефицит остаётся ниже допуска `ε`, равен
|
|
16
|
+
|
|
17
|
+
Δ* = s/v + √(2ε/v)
|
|
18
|
+
|
|
19
|
+
Если снимок статистики старше на `a` секунд (статистика virtio-balloon приходит с
|
|
20
|
+
опозданием), гарантия сохраняется для интервала `Δ* − a`.
|
|
21
|
+
|
|
22
|
+
English version: [README.md](https://github.com/89605502155/desna-interval/blob/main/README.md).
|
|
23
|
+
Документация: [English](https://github.com/89605502155/desna-interval/tree/main/docs/en) ·
|
|
24
|
+
[Русский](https://github.com/89605502155/desna-interval/tree/main/docs/ru) ·
|
|
25
|
+
[Журнал изменений](https://github.com/89605502155/desna-interval/blob/main/CHANGELOG.md) ·
|
|
26
|
+
[Задачи](https://github.com/89605502155/desna-interval/issues)
|
|
27
|
+
|
|
28
|
+
Библиотека сопровождает статью 1 серии А. Ферубко, Брянский государственный
|
|
29
|
+
инженерно-технологический университет (БГИТУ). Теория:
|
|
30
|
+
[docs/ru/theory.md](https://github.com/89605502155/desna-interval/blob/main/docs/ru/theory.md).
|
|
31
|
+
|
|
32
|
+
## Установка
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
pip install desna-interval # ядро: только numpy
|
|
36
|
+
pip install "desna-interval[libvirt]" # живой цикл на хосте KVM
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Нужен Python 3.11 или новее.
|
|
40
|
+
|
|
41
|
+
## Быстрый старт
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from desna_interval import MonitorScheduler, WindowQuantile, next_interval_aged
|
|
45
|
+
|
|
46
|
+
next_interval_aged(s=256, v=128, eps=128, age=0.0) # -> 3.414 с, свежий снимок
|
|
47
|
+
next_interval_aged(s=256, v=128, eps=128, age=1.0) # -> 2.414 с, снимок старше на 1 с
|
|
48
|
+
|
|
49
|
+
sched = MonitorScheduler(["vm1", "vm2"], eps=128, estimator_factory=WindowQuantile)
|
|
50
|
+
sched.observe(now=0.0, demand={"vm1": 1000, "vm2": 3000}, slack={"vm1": 256, "vm2": 64})
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Командная строка:
|
|
54
|
+
|
|
55
|
+
desna-interval interval --slack 256 --rate 128 --eps 128 --age 1
|
|
56
|
+
desna-interval optimal --slack 0 --rate 128 --rho 0.01 --cost 64
|
|
57
|
+
desna-interval replay trace.csv --eps 64 --slack 256
|
|
58
|
+
|
|
59
|
+
## Отличия от существующих пакетов
|
|
60
|
+
|
|
61
|
+
Пакеты на PyPI, которые адаптивно опрашивают или выбирают точки выборки, например
|
|
62
|
+
`python-adaptive`, подбирают точки так, чтобы уменьшить ошибку функции или метрики.
|
|
63
|
+
Пакеты повторных попыток (`backoff`, `tenacity`) реализуют откат для неудачных
|
|
64
|
+
вызовов, а пакеты расписаний (`APScheduler`) лишь запускают задачи в заданное время.
|
|
65
|
+
Ни один из них не переводит допуск на дефицит ресурса в интервал опроса.
|
|
66
|
+
|
|
67
|
+
| Возможность | desna-interval | общие пакеты адаптивной выборки и опроса |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| Интервал из допуска на накопленный дефицит, `Δ* = s/v + √(2ε/v)` | да | нет, они целятся в ошибку метрики или функции |
|
|
70
|
+
| Поправка на возраст запаздывающего снимка | да | нет |
|
|
71
|
+
| Оптимум ожидаемых затрат при известной интенсивности всплесков и цене опроса | да | нет |
|
|
72
|
+
| Граница скорости роста по истории, по группе однотипных ВМ или фильтром Калмана | да | нет |
|
|
73
|
+
| Живой цикл для ВМ libvirt (`memoryStats`, цели баллона) | да | нет |
|
|
74
|
+
| Проигрывание политик на трассе с дефицитом как метрикой | да | нет |
|
|
75
|
+
|
|
76
|
+
Правило работает настолько, насколько верна граница `v`: когда оно верно и когда нет,
|
|
77
|
+
описано в теории.
|
|
78
|
+
|
|
79
|
+
## Когда это помогает и когда нет
|
|
80
|
+
|
|
81
|
+
Правило ограничивает дефицит каждого слепого промежутка. Выигрыш перед постоянным
|
|
82
|
+
интервалом зависит от нагрузки:
|
|
83
|
+
|
|
84
|
+
- Для одинаковых машин со всплесками без памяти никакой адаптивный график не лучше
|
|
85
|
+
постоянного интервала при том же бюджете опросов (утверждение 1.4, Йенсен). Библиотека
|
|
86
|
+
этого не скрывает.
|
|
87
|
+
- Выигрыш даёт различие между машинами, а правило задаёт границу дефицита каждого
|
|
88
|
+
промежутка, чего нет у общего отката.
|
|
89
|
+
- Гарантия не лучше границы `v`. Для однотипных машин берите квантиль по длинной
|
|
90
|
+
истории или общую оценку.
|
|
91
|
+
|
|
92
|
+
Сравнение стратегий (сейчас на синтетике, для статьи — на трассах стенда) — это
|
|
93
|
+
эксперимент E2 в [experiments/README.ru.md](experiments/README.ru.md). Синтетические
|
|
94
|
+
результаты показывают поведение, а не измерения.
|
|
95
|
+
|
|
96
|
+
## Авторы
|
|
97
|
+
|
|
98
|
+
- Андрей Ферубко (Andrey Ferubko), ORCID [0009-0006-5625-137X](https://orcid.org/0009-0006-5625-137X)
|
|
99
|
+
- Олег Дмитриевич Казаков (Oleg Kazakov), ORCID [0000-0001-9665-8138](https://orcid.org/0000-0001-9665-8138)
|
|
100
|
+
|
|
101
|
+
Брянский государственный инженерно-технологический университет (БГИТУ).
|
|
102
|
+
|
|
103
|
+
## Модули
|
|
104
|
+
|
|
105
|
+
| Модуль | Содержимое |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `rule` | `blind_deficit_bound`, `interval_unclipped`, `next_interval`, `next_interval_aged`, `min_slack`, `expected_cost_rate`, `optimal_interval_expected` |
|
|
108
|
+
| `estimators` | границы `v`: `history_quantile`, `pooled_quantile`, `WindowQuantile`, `FixedRate`, `KalmanRate`, `RateFilterAdapter`; `burst_rate` |
|
|
109
|
+
| `scheduler` | `MonitorScheduler`: интервал у каждой ВМ или общий; протокол `IntervalScheduler` для других расписаний |
|
|
110
|
+
| `replay` | `replay` и политики `FixedPolicy`, `BackoffPolicy`, `DeficitRulePolicy`, `ExpectedCostPolicy` |
|
|
111
|
+
| `libvirt_loop` | `run` (необязательный `scheduler`), `read_state`, `reserve_controller`: живой цикл |
|
|
112
|
+
|
|
113
|
+
## Разработка
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
uv sync
|
|
117
|
+
uv run ruff check . && uv run ruff format --check .
|
|
118
|
+
uv run mypy
|
|
119
|
+
uv run pytest
|
|
120
|
+
bash scripts/install_hooks.sh # один раз в клоне: ограничения сообщений коммитов
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Эксперименты статьи 1 требуют необязательную группу `experiments` (matplotlib):
|
|
124
|
+
`uv sync --group experiments`. Их режимы `--smoke` выполняются в `pytest`; полные
|
|
125
|
+
прогоны описаны в [experiments/README.ru.md](experiments/README.ru.md).
|
|
126
|
+
|
|
127
|
+
Сообщения коммитов в этом репозитории: тема не длиннее 8 символов, тела нет.
|
|
128
|
+
Хук `commit-msg`, который ставит `scripts/install_hooks.sh`, проверяет это правило
|
|
129
|
+
(`scripts/check_commit_msg.py`). CI и автоматической публикации нет.
|
|
130
|
+
|
|
131
|
+
## Цитирование
|
|
132
|
+
|
|
133
|
+
См. [CITATION.cff](https://github.com/89605502155/desna-interval/blob/main/CITATION.cff)
|
|
134
|
+
или кнопку «Cite this repository» на GitHub.
|
|
135
|
+
|
|
136
|
+
## Лицензия
|
|
137
|
+
|
|
138
|
+
MIT. Copyright (c) 2026 Andrey Ferubko, Oleg Kazakov. См. [LICENSE](https://github.com/89605502155/desna-interval/blob/main/LICENSE).
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# API
|
|
2
|
+
|
|
3
|
+
All names are re-exported from the package `desna_interval`. Units: memory in
|
|
4
|
+
MiB, time in seconds, rate in MiB/s, deficit in MiB·s.
|
|
5
|
+
|
|
6
|
+
## Rule (`desna_interval.rule`)
|
|
7
|
+
|
|
8
|
+
| Function | Meaning |
|
|
9
|
+
|---|---|
|
|
10
|
+
| `blind_deficit_bound(s, v, delta)` | Upper bound on the deficit over a blind gap, claim 1.1 |
|
|
11
|
+
| `interval_unclipped(s, v, eps)` | `s/v + sqrt(2 eps/v)`, claim 1.2; needs `v > 0` |
|
|
12
|
+
| `next_interval(s, v, eps, dmin=1, dmax=10)` | The interval clipped to `[dmin, dmax]` |
|
|
13
|
+
| `next_interval_aged(s, v, eps, age=0, dmin=1, dmax=10)` | Same, minus the snapshot age, claim 1.3 |
|
|
14
|
+
| `min_slack(delta, v, eps)` | Smallest slack that admits interval `delta` |
|
|
15
|
+
| `burst_deficit_integral(delta, s, v)` | `G(delta)` of claim 1.4 |
|
|
16
|
+
| `expected_cost_rate(delta, s, v, rho, c)` | `(rho G(delta) + c) / delta` |
|
|
17
|
+
| `optimal_interval_expected(s, v, rho, c, dmin, dmax)` | Minimiser of the expected cost, claim 1.5 |
|
|
18
|
+
|
|
19
|
+
## Estimators (`desna_interval.estimators`)
|
|
20
|
+
|
|
21
|
+
An online estimator has `update(t, d)` and `upper() -> float`. A filter
|
|
22
|
+
(`RateFilter`) has `update(t, d)` and `rate() -> (rate, variance)`.
|
|
23
|
+
|
|
24
|
+
| Name | Meaning |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `WindowQuantile(window=300, q=1, v_floor=2)` | Quantile of growth over the last `window` seconds |
|
|
27
|
+
| `FixedRate(v)` | Constant bound, e.g. from `history_quantile` |
|
|
28
|
+
| `KalmanRate(q=1, r=25)` | Scalar Kalman filter of level and growth rate |
|
|
29
|
+
| `RateFilterAdapter(filt, z=2.33, v_floor=2)` | `rate + z·sqrt(variance)` of any `RateFilter` |
|
|
30
|
+
| `growth_rates(t, d, step=1)` | Non-negative growth rates on a regular grid |
|
|
31
|
+
| `history_quantile(t, d, q=0.99, step=1, v_floor=2)` | Robust bound from one history |
|
|
32
|
+
| `pooled_quantile(series, q, step, v_floor)` | Common bound over `(t, d)` pairs |
|
|
33
|
+
| `per_series_quantiles(t, rows, ...)` | `history_quantile` for each row |
|
|
34
|
+
| `burst_rate(t, d, step, rise, window, min_gap)` | Rate of burst onsets `rho`, 1/s |
|
|
35
|
+
|
|
36
|
+
## Scheduler (`desna_interval.scheduler`)
|
|
37
|
+
|
|
38
|
+
`MonitorScheduler(vms, eps, estimator_factory, dmin=1, dmax=10, mode="per_vm")`.
|
|
39
|
+
|
|
40
|
+
- `due(now)`: the objects to poll now.
|
|
41
|
+
- `next_wakeup()`: time of the next poll.
|
|
42
|
+
- `observe(now, demand, slack, age=None)`: updates the estimators of the polled
|
|
43
|
+
objects and returns their intervals. With `mode="global"` all intervals equal
|
|
44
|
+
the smallest one.
|
|
45
|
+
|
|
46
|
+
## Replay (`desna_interval.replay`)
|
|
47
|
+
|
|
48
|
+
`replay(t, d, policy, slack) -> ReplayResult`. A policy has
|
|
49
|
+
`next_interval(t, d) -> float`. The result has `polls`, `duration`, `deficit`,
|
|
50
|
+
`gap_deficits`, `intervals`, `mean_interval` and `violation_share(eps)`.
|
|
51
|
+
|
|
52
|
+
Policies: `FixedPolicy(delta)`, `BackoffPolicy(dmin, dmax, factor, threshold)`,
|
|
53
|
+
`DeficitRulePolicy(eps, slack, estimator, dmin, dmax)`,
|
|
54
|
+
`ExpectedCostPolicy(slack, v, rho, c, dmin, dmax)`.
|
|
55
|
+
|
|
56
|
+
## Live loop (`desna_interval.libvirt_loop`)
|
|
57
|
+
|
|
58
|
+
Requires `libvirt-python`; the module imports without it, so tests use fake
|
|
59
|
+
domains.
|
|
60
|
+
|
|
61
|
+
- `read_state(dom, reserve_mib, balloon_in_total=False, wall=time.time)`
|
|
62
|
+
returns `(allocation MiB, demand MiB, snapshot age s)`.
|
|
63
|
+
- `reserve_controller(s_target=256, deadband=64)`: example controller.
|
|
64
|
+
- `run(domains, controller, eps, reserve_mib, duration_s, log_path, ...)`
|
|
65
|
+
polls the domains on the schedule, applies targets when `apply=True`, writes a
|
|
66
|
+
CSV log and returns the number of polls. `adapt_stats_period=True` sets each
|
|
67
|
+
guest's statistics period to the whole part of its interval. The optional
|
|
68
|
+
`scheduler` replaces `MonitorScheduler` with any object that implements
|
|
69
|
+
`IntervalScheduler` (`due`, `next_wakeup`, `observe`), for example a heuristic.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Command line
|
|
2
|
+
|
|
3
|
+
The program is `desna-interval`. Every subcommand prints one line or a table.
|
|
4
|
+
|
|
5
|
+
desna-interval --version
|
|
6
|
+
|
|
7
|
+
## `interval`
|
|
8
|
+
|
|
9
|
+
Interval `delta* = s/v + sqrt(2 eps/v)` minus the snapshot age, clipped.
|
|
10
|
+
|
|
11
|
+
desna-interval interval --slack 256 --rate 128 --eps 128 --age 1
|
|
12
|
+
# 2.414
|
|
13
|
+
|
|
14
|
+
| Option | Meaning | Default |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| `--slack` | slack `s`, MiB | required |
|
|
17
|
+
| `--rate` | growth bound `v`, MiB/s | required |
|
|
18
|
+
| `--eps` | tolerance, MiB·s | required |
|
|
19
|
+
| `--age` | snapshot age, s | 0 |
|
|
20
|
+
| `--dmin`, `--dmax` | clipping bounds, s | 1, 10 |
|
|
21
|
+
|
|
22
|
+
## `min-slack`
|
|
23
|
+
|
|
24
|
+
Smallest slack that admits an interval.
|
|
25
|
+
|
|
26
|
+
desna-interval min-slack --delta 5 --rate 128 --eps 128
|
|
27
|
+
# 458.980664
|
|
28
|
+
|
|
29
|
+
## `optimal`
|
|
30
|
+
|
|
31
|
+
Interval that minimises the expected cost.
|
|
32
|
+
|
|
33
|
+
desna-interval optimal --slack 0 --rate 128 --rho 0.01 --cost 64
|
|
34
|
+
# 5.3133
|
|
35
|
+
|
|
36
|
+
Options: `--slack`, `--rate`, `--rho` (burst onsets per second), `--cost` (price
|
|
37
|
+
of one poll in MiB·s), `--dmin`, `--dmax`.
|
|
38
|
+
|
|
39
|
+
## `replay`
|
|
40
|
+
|
|
41
|
+
Compares policies on a CSV trace with the header `t,d` (time in s, demand in MiB).
|
|
42
|
+
|
|
43
|
+
desna-interval replay trace.csv --eps 64 --slack 256
|
|
44
|
+
|
|
45
|
+
Prints the bound `v` (0.99 quantile of the history), the burst rate `rho` and one
|
|
46
|
+
line per policy: `policy,polls,mean_interval_s,deficit_mib_s,violation_share`.
|
|
47
|
+
Options: `--eps`, `--slack`, `--fixed` (list of fixed intervals, s).
|
|
48
|
+
|
|
49
|
+
Exit status is 0 on success.
|