limits 4.7.1__tar.gz → 4.7.3__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.
- {limits-4.7.1 → limits-4.7.3}/HISTORY.rst +22 -0
- {limits-4.7.1 → limits-4.7.3}/PKG-INFO +1 -1
- {limits-4.7.1 → limits-4.7.3}/doc/source/conf.py +10 -1
- limits-4.7.3/doc/source/ext/_static/benchmark-chart.css +97 -0
- limits-4.7.3/doc/source/ext/_static/js/benchmark-chart.js +343 -0
- {limits-4.7.1 → limits-4.7.3}/doc/source/ext/_static/js/benchmark-details.js +22 -6
- {limits-4.7.1 → limits-4.7.3}/doc/source/ext/_static/js/benchmark-loader.js +4 -5
- limits-4.7.3/doc/source/ext/_templates/git_info.js +2 -0
- {limits-4.7.1 → limits-4.7.3}/doc/source/ext/bench_chart.py +26 -12
- limits-4.7.3/doc/source/performance.rst +126 -0
- {limits-4.7.1 → limits-4.7.3}/limits/_version.py +3 -3
- {limits-4.7.1 → limits-4.7.3}/limits/aio/storage/memcached.py +4 -1
- {limits-4.7.1 → limits-4.7.3}/limits.egg-info/PKG-INFO +1 -1
- {limits-4.7.1 → limits-4.7.3}/requirements/docs.txt +3 -3
- limits-4.7.1/doc/source/ext/_static/benchmark-chart.css +0 -10
- limits-4.7.1/doc/source/ext/_static/js/benchmark-chart.js +0 -194
- limits-4.7.1/doc/source/ext/_templates/git_info.js +0 -2
- limits-4.7.1/doc/source/performance.rst +0 -221
- {limits-4.7.1 → limits-4.7.3}/CLASSIFIERS +0 -0
- {limits-4.7.1 → limits-4.7.3}/CONTRIBUTIONS.rst +0 -0
- {limits-4.7.1 → limits-4.7.3}/LICENSE.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/MANIFEST.in +0 -0
- {limits-4.7.1 → limits-4.7.3}/README.rst +0 -0
- {limits-4.7.1 → limits-4.7.3}/doc/Makefile +0 -0
- {limits-4.7.1 → limits-4.7.3}/doc/source/_static/custom.css +0 -0
- {limits-4.7.1 → limits-4.7.3}/doc/source/api.rst +0 -0
- {limits-4.7.1 → limits-4.7.3}/doc/source/async.rst +0 -0
- {limits-4.7.1 → limits-4.7.3}/doc/source/changelog.rst +0 -0
- {limits-4.7.1 → limits-4.7.3}/doc/source/custom-storage.rst +0 -0
- {limits-4.7.1 → limits-4.7.3}/doc/source/index.rst +0 -0
- {limits-4.7.1 → limits-4.7.3}/doc/source/installation.rst +0 -0
- {limits-4.7.1 → limits-4.7.3}/doc/source/quickstart.rst +0 -0
- {limits-4.7.1 → limits-4.7.3}/doc/source/storage.rst +0 -0
- {limits-4.7.1 → limits-4.7.3}/doc/source/strategies.rst +0 -0
- {limits-4.7.1 → limits-4.7.3}/doc/source/theme_config.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/__init__.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/aio/__init__.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/aio/storage/__init__.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/aio/storage/base.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/aio/storage/etcd.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/aio/storage/memory.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/aio/storage/mongodb.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/aio/storage/redis/__init__.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/aio/storage/redis/bridge.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/aio/storage/redis/coredis.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/aio/storage/redis/redispy.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/aio/storage/redis/valkey.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/aio/strategies.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/errors.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/limits.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/py.typed +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/resources/redis/lua_scripts/acquire_moving_window.lua +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/resources/redis/lua_scripts/acquire_sliding_window.lua +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/resources/redis/lua_scripts/clear_keys.lua +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/resources/redis/lua_scripts/incr_expire.lua +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/resources/redis/lua_scripts/moving_window.lua +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/resources/redis/lua_scripts/sliding_window.lua +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/storage/__init__.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/storage/base.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/storage/etcd.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/storage/memcached.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/storage/memory.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/storage/mongodb.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/storage/redis.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/storage/redis_cluster.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/storage/redis_sentinel.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/storage/registry.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/strategies.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/typing.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/util.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits/version.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits.egg-info/SOURCES.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits.egg-info/dependency_links.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits.egg-info/not-zip-safe +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits.egg-info/requires.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/limits.egg-info/top_level.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/pyproject.toml +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/ci.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/dev.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/main.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/storage/async-etcd.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/storage/async-memcached.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/storage/async-mongodb.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/storage/async-redis.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/storage/async-valkey.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/storage/etcd.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/storage/memcached.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/storage/mongodb.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/storage/redis.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/storage/rediscluster.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/storage/valkey.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/requirements/test.txt +0 -0
- {limits-4.7.1 → limits-4.7.3}/setup.cfg +0 -0
- {limits-4.7.1 → limits-4.7.3}/setup.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/tests/test_limit_granularities.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/tests/test_limits.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/tests/test_ratelimit_parser.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/tests/test_storage.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/tests/test_strategy.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/tests/test_utils.py +0 -0
- {limits-4.7.1 → limits-4.7.3}/versioneer.py +0 -0
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
Changelog
|
|
4
4
|
=========
|
|
5
5
|
|
|
6
|
+
v4.7.3
|
|
7
|
+
------
|
|
8
|
+
Release Date: 2025-04-12
|
|
9
|
+
|
|
10
|
+
* Documentation
|
|
11
|
+
|
|
12
|
+
* Expand benchmark results to included preseeded limits
|
|
13
|
+
|
|
14
|
+
* Bug Fix
|
|
15
|
+
|
|
16
|
+
* Handle clearing missing key with memcache + async
|
|
17
|
+
|
|
18
|
+
v4.7.2
|
|
19
|
+
------
|
|
20
|
+
Release Date: 2025-04-09
|
|
21
|
+
|
|
22
|
+
* Documentation
|
|
23
|
+
|
|
24
|
+
* Improve presentation of benchmark docs
|
|
25
|
+
|
|
6
26
|
v4.7.1
|
|
7
27
|
------
|
|
8
28
|
Release Date: 2025-04-08
|
|
@@ -863,6 +883,8 @@ Release Date: 2015-01-08
|
|
|
863
883
|
|
|
864
884
|
|
|
865
885
|
|
|
886
|
+
|
|
887
|
+
|
|
866
888
|
|
|
867
889
|
|
|
868
890
|
|
|
@@ -39,7 +39,15 @@ else:
|
|
|
39
39
|
"branch": git_info.get("branch", ""),
|
|
40
40
|
"sha": git_info.get("long", None)
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
benchmark_param_mapping = {
|
|
43
|
+
"percentage_full": {
|
|
44
|
+
"display": "Percentage Seeded",
|
|
45
|
+
"info": "Percentage of rate limit already filled before the benchmark is run",
|
|
46
|
+
},
|
|
47
|
+
"async": {"display": "Asyncio", "info": "Using asyncio storage implementation"},
|
|
48
|
+
"storage_type": {"display": "Storage", "info": "Storage Backend"},
|
|
49
|
+
"strategy": {"display": "Strategy", "info": "Rate Limiting Strategy"},
|
|
50
|
+
}
|
|
43
51
|
html_static_path = ["_static"]
|
|
44
52
|
|
|
45
53
|
html_css_files = [
|
|
@@ -73,6 +81,7 @@ extensions = [
|
|
|
73
81
|
"sphinxext.opengraph",
|
|
74
82
|
"sphinxcontrib.programoutput",
|
|
75
83
|
"sphinx_copybutton",
|
|
84
|
+
"sphinx_design",
|
|
76
85
|
"sphinx_inline_tabs",
|
|
77
86
|
"sphinx_paramlinks",
|
|
78
87
|
"bench_chart",
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
.plot-container {
|
|
2
|
+
filter: invert(100%);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
body[data-theme="light"] .plot-container {
|
|
6
|
+
filter: invert(0);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.benchmark-chart {
|
|
10
|
+
width: 100%;
|
|
11
|
+
}
|
|
12
|
+
.benchmark-details {
|
|
13
|
+
.benchmark-details-section {
|
|
14
|
+
thead > tr {
|
|
15
|
+
color: var(--color-purple);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
.benchmark-chart-error,
|
|
20
|
+
.benchmark-details-error {
|
|
21
|
+
color: var(--color-red);
|
|
22
|
+
font-size: smaller;
|
|
23
|
+
padding: 2em;
|
|
24
|
+
text-align: center;
|
|
25
|
+
height: 5em;
|
|
26
|
+
}
|
|
27
|
+
.benchmark-chart-loading {
|
|
28
|
+
display: flex;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
align-items: center;
|
|
31
|
+
font-size: 1.2rem;
|
|
32
|
+
font-weight: bold;
|
|
33
|
+
color: var(--color-purple);
|
|
34
|
+
letter-spacing: 1px;
|
|
35
|
+
height: 200px;
|
|
36
|
+
animation: benchmark-chart-loading-animation;
|
|
37
|
+
animation-iteration-count: 10;
|
|
38
|
+
animation-duration: 2s;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@keyframes benchmark-chart-loading-animation {
|
|
42
|
+
0% {
|
|
43
|
+
opacity: 0;
|
|
44
|
+
}
|
|
45
|
+
25% {
|
|
46
|
+
opacity: 0.25;
|
|
47
|
+
}
|
|
48
|
+
50% {
|
|
49
|
+
opacity: 0.5;
|
|
50
|
+
}
|
|
51
|
+
90% {
|
|
52
|
+
opacity: 0.9;
|
|
53
|
+
}
|
|
54
|
+
100% {
|
|
55
|
+
opacity: 1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
.benchmark-filters {
|
|
59
|
+
padding-top: 1em;
|
|
60
|
+
padding-bottom: 1em;
|
|
61
|
+
display: flex;
|
|
62
|
+
justify-content: flex-end;
|
|
63
|
+
}
|
|
64
|
+
.benchmark-filter-dropdowns {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: flex-end;
|
|
67
|
+
justify-content: flex-end;
|
|
68
|
+
margin-top: 2em;
|
|
69
|
+
flex-direction: row;
|
|
70
|
+
@media only screen and (max-width: 800px) {
|
|
71
|
+
flex-basis: min-content;
|
|
72
|
+
}
|
|
73
|
+
@media only screen and (max-width: 400px) {
|
|
74
|
+
flex-basis: max-content;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.benchmark-filter {
|
|
80
|
+
display: flex;
|
|
81
|
+
flex-direction: row;
|
|
82
|
+
gap: 0.25em;
|
|
83
|
+
padding: 0.25em;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.benchmark-filter label {
|
|
87
|
+
font-size: small;
|
|
88
|
+
font-weight: bold;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.benchmark-filter select {
|
|
92
|
+
font-size: small;
|
|
93
|
+
border: 1px solid;
|
|
94
|
+
border-radius: 0.4em;
|
|
95
|
+
}
|
|
96
|
+
.benchmark-filter input[type="checkbox"] {
|
|
97
|
+
}
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import { render, html } from "https://unpkg.com/uhtml@3.2.1?module";
|
|
2
|
+
import { fetchBenchmarkData } from "./benchmark-loader.js";
|
|
3
|
+
const KNOWN_PARAMS = [
|
|
4
|
+
"storage_type",
|
|
5
|
+
"limit",
|
|
6
|
+
"strategy",
|
|
7
|
+
"async",
|
|
8
|
+
"percentage_full",
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
function getBenchmarkData(result, query) {
|
|
12
|
+
let benchmarks = result.benchmarks;
|
|
13
|
+
return benchmarks.filter(function (benchmark) {
|
|
14
|
+
let okay = true;
|
|
15
|
+
if (query) {
|
|
16
|
+
Object.entries(query).forEach((entry) => {
|
|
17
|
+
let key = entry[0];
|
|
18
|
+
let value = entry[1];
|
|
19
|
+
if (
|
|
20
|
+
key != "group" &&
|
|
21
|
+
!(value === "") && // i.e. any.
|
|
22
|
+
benchmark.params[key] != null &&
|
|
23
|
+
benchmark.params[key] != value
|
|
24
|
+
) {
|
|
25
|
+
okay = false;
|
|
26
|
+
} else if (key == "group" && value != benchmark.group) {
|
|
27
|
+
okay = false;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return okay;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function formatParam(key, str) {
|
|
36
|
+
if (key === "limit") {
|
|
37
|
+
var m = str.match(/(\d+(?:\.\d+)?)\s+per\s+1\s+(\w+)/i);
|
|
38
|
+
if (!m) return str;
|
|
39
|
+
var n = parseFloat(m[1]),
|
|
40
|
+
u = m[2].toLowerCase(),
|
|
41
|
+
num =
|
|
42
|
+
n >= 1000
|
|
43
|
+
? (n / 1000) % 1 === 0
|
|
44
|
+
? n / 1000 + "K"
|
|
45
|
+
: (n / 1000).toFixed(1) + "K"
|
|
46
|
+
: n.toString(),
|
|
47
|
+
umap = {
|
|
48
|
+
second: "s",
|
|
49
|
+
seconds: "s",
|
|
50
|
+
minute: "min",
|
|
51
|
+
minutes: "mins",
|
|
52
|
+
hour: "hr",
|
|
53
|
+
hours: "hr",
|
|
54
|
+
day: "day",
|
|
55
|
+
days: "day",
|
|
56
|
+
};
|
|
57
|
+
return num + "/" + (umap[u] || u);
|
|
58
|
+
} else if (key === "percentage_full") {
|
|
59
|
+
return `${str}% Seeded`;
|
|
60
|
+
}
|
|
61
|
+
return str;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function nameTransform(benchmark, stripParams, query) {
|
|
65
|
+
let name = benchmark.name;
|
|
66
|
+
let params = benchmark.params;
|
|
67
|
+
name = name
|
|
68
|
+
.replace(/\[.*?\]/, "")
|
|
69
|
+
.replace("_async", "")
|
|
70
|
+
.replaceAll("_", "-");
|
|
71
|
+
name = name.replace(benchmark.group, "");
|
|
72
|
+
let queryParam = Object.entries(query).map((entry) => entry[0]);
|
|
73
|
+
let additional = getRemainingGroups(benchmark, query);
|
|
74
|
+
Object.entries(additional).forEach((param) => {
|
|
75
|
+
let value = formatParam(param[0], param[1]);
|
|
76
|
+
if (name) {
|
|
77
|
+
name += ` - ${value}`;
|
|
78
|
+
} else {
|
|
79
|
+
name = `${value}`;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
return name;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function getRemainingGroups(benchmark, query) {
|
|
86
|
+
let queryParam = Object.entries(query).map((entry) => entry[0]);
|
|
87
|
+
let additional = {};
|
|
88
|
+
Object.entries(benchmark.params).forEach((param) => {
|
|
89
|
+
const key = param[0];
|
|
90
|
+
const value = param[1];
|
|
91
|
+
if (
|
|
92
|
+
(!queryParam.includes(key) || query?.[key] === "") &&
|
|
93
|
+
KNOWN_PARAMS.includes(key)
|
|
94
|
+
) {
|
|
95
|
+
additional[key] = value;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
return additional;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getColorForStorage(storageType) {
|
|
102
|
+
const storageColorMap = {
|
|
103
|
+
memory: window
|
|
104
|
+
.getComputedStyle(document.body)
|
|
105
|
+
.getPropertyValue("--color-purple"),
|
|
106
|
+
mongodb: window
|
|
107
|
+
.getComputedStyle(document.body)
|
|
108
|
+
.getPropertyValue("--color-yellow"),
|
|
109
|
+
memcached: window
|
|
110
|
+
.getComputedStyle(document.body)
|
|
111
|
+
.getPropertyValue("--color-aqua"),
|
|
112
|
+
redis: window
|
|
113
|
+
.getComputedStyle(document.body)
|
|
114
|
+
.getPropertyValue("--color-red"),
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// Fallback color if an unknown storageType appears
|
|
118
|
+
return storageColorMap[storageType] || "#7f7f7f"; // gray
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function sortBenchmarksByParams(benchmarks, sortKeys) {
|
|
122
|
+
return benchmarks.sort(function (a, b) {
|
|
123
|
+
for (const key of sortKeys) {
|
|
124
|
+
let valA = (a.params?.[key] || "").toLowerCase();
|
|
125
|
+
let valB = (b.params?.[key] || "").toLowerCase();
|
|
126
|
+
if (key === "limit") {
|
|
127
|
+
valA = parseInt(valA.split(" ")[0], 10);
|
|
128
|
+
valB = parseInt(valB.split(" ")[0], 10);
|
|
129
|
+
}
|
|
130
|
+
if (valA < valB) return -1;
|
|
131
|
+
if (valA > valB) return 1;
|
|
132
|
+
}
|
|
133
|
+
return a.name.localeCompare(b.name);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
let dispatched = new Set();
|
|
138
|
+
|
|
139
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
140
|
+
const charts = document.querySelectorAll(".benchmark-chart");
|
|
141
|
+
charts.forEach((chart) => {
|
|
142
|
+
const source = chart.dataset.source;
|
|
143
|
+
const filters = JSON.parse(chart.dataset.filters);
|
|
144
|
+
const query = JSON.parse(chart.dataset.query);
|
|
145
|
+
const paramMapping = JSON.parse(chart.dataset.paramMapping);
|
|
146
|
+
const chartId = chart.dataset.chartId;
|
|
147
|
+
let sortBy = JSON.parse(
|
|
148
|
+
chart.dataset.sortBy || '["storage_type", "limit"]',
|
|
149
|
+
);
|
|
150
|
+
render(
|
|
151
|
+
chart,
|
|
152
|
+
html`
|
|
153
|
+
<div class="benchmark-chart-loading">
|
|
154
|
+
<span>Loading</span>
|
|
155
|
+
</div>
|
|
156
|
+
`,
|
|
157
|
+
);
|
|
158
|
+
if (!dispatched.has(source)) {
|
|
159
|
+
fetchBenchmarkData(`${source}.json`)
|
|
160
|
+
.then((result) => {
|
|
161
|
+
window.Benchmarks[source] = result;
|
|
162
|
+
let event = new Event(`${source}-loaded`);
|
|
163
|
+
window.dispatchEvent(event);
|
|
164
|
+
})
|
|
165
|
+
.catch((error) => {
|
|
166
|
+
let event = new Event(`${source}-failed`);
|
|
167
|
+
window.dispatchEvent(event);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
dispatched.add(source);
|
|
171
|
+
window.addEventListener(`${chart.dataset.source}-failed`, function () {
|
|
172
|
+
chart.querySelector(".benchmark-chart-loading")?.remove();
|
|
173
|
+
render(
|
|
174
|
+
chart,
|
|
175
|
+
html`
|
|
176
|
+
<div class="benchmark-chart-error">Benchmark data not available.</div>
|
|
177
|
+
`,
|
|
178
|
+
);
|
|
179
|
+
});
|
|
180
|
+
window.addEventListener(`${chart.dataset.source}-loaded`, function () {
|
|
181
|
+
chart.innerHTML = "";
|
|
182
|
+
chart.querySelector(".benchmark-chart-loading")?.remove();
|
|
183
|
+
const results = Benchmarks[chart.dataset.source];
|
|
184
|
+
const allBenchmarks = getBenchmarkData(results, query);
|
|
185
|
+
const currentFilters = Object.fromEntries(
|
|
186
|
+
Object.entries(filters).map(([key, value]) => {
|
|
187
|
+
return typeof value.default === "boolean"
|
|
188
|
+
? [key, value.default]
|
|
189
|
+
: [key, value.default != null ? value.default.toString() : ""];
|
|
190
|
+
}),
|
|
191
|
+
);
|
|
192
|
+
const queryFilter = { ...query, ...currentFilters };
|
|
193
|
+
const dropdownTarget = document.createElement("div");
|
|
194
|
+
dropdownTarget.classList.add("benchmark-filters");
|
|
195
|
+
const chartTarget = document.createElement("div");
|
|
196
|
+
chart.append(chartTarget);
|
|
197
|
+
chart.append(dropdownTarget);
|
|
198
|
+
function renderDropdowns() {
|
|
199
|
+
const dropdowns = Object.entries(filters).map(([key]) => {
|
|
200
|
+
const fullName = `${chartId}-${key}`;
|
|
201
|
+
const uniqueValues = [
|
|
202
|
+
...new Set(allBenchmarks.map((b) => b.params?.[key])),
|
|
203
|
+
].sort();
|
|
204
|
+
const isBoolean =
|
|
205
|
+
uniqueValues.length === 2 &&
|
|
206
|
+
uniqueValues.includes(true) &&
|
|
207
|
+
uniqueValues.includes(false);
|
|
208
|
+
if (isBoolean) {
|
|
209
|
+
return html`
|
|
210
|
+
<div class="benchmark-filter" title=${paramMapping[key]?.info}>
|
|
211
|
+
<input
|
|
212
|
+
type="checkbox"
|
|
213
|
+
id=${fullName}
|
|
214
|
+
?checked=${currentFilters[key] === true}
|
|
215
|
+
onchange=${(e) => {
|
|
216
|
+
currentFilters[key] = e.target.checked;
|
|
217
|
+
renderChartWithFilters(currentFilters);
|
|
218
|
+
}}
|
|
219
|
+
/>
|
|
220
|
+
<label for=${fullName}>
|
|
221
|
+
${paramMapping[key]?.display || key}
|
|
222
|
+
</label>
|
|
223
|
+
</div>
|
|
224
|
+
`;
|
|
225
|
+
} else {
|
|
226
|
+
return html`
|
|
227
|
+
<div class="benchmark-filter" title=${paramMapping[key]?.info}>
|
|
228
|
+
<label for=${fullName}>
|
|
229
|
+
${paramMapping[key]?.display || key}
|
|
230
|
+
<select
|
|
231
|
+
id=${fullName}
|
|
232
|
+
onchange=${(e) => {
|
|
233
|
+
const value = e.target.value;
|
|
234
|
+
if (value) {
|
|
235
|
+
currentFilters[key] =
|
|
236
|
+
value === "false"
|
|
237
|
+
? false
|
|
238
|
+
: value === "true"
|
|
239
|
+
? true
|
|
240
|
+
: value;
|
|
241
|
+
} else {
|
|
242
|
+
currentFilters[key] = "";
|
|
243
|
+
}
|
|
244
|
+
renderChartWithFilters(currentFilters);
|
|
245
|
+
}}
|
|
246
|
+
>
|
|
247
|
+
<option value="" ?selected=${currentFilters[key] == ""}>
|
|
248
|
+
All
|
|
249
|
+
</option>
|
|
250
|
+
${uniqueValues.map(
|
|
251
|
+
(val) => html`
|
|
252
|
+
<option
|
|
253
|
+
value=${val}
|
|
254
|
+
?selected=${currentFilters[key] == val.toString()}
|
|
255
|
+
>
|
|
256
|
+
${val}
|
|
257
|
+
</option>
|
|
258
|
+
`,
|
|
259
|
+
)}
|
|
260
|
+
</select>
|
|
261
|
+
</label>
|
|
262
|
+
</div>
|
|
263
|
+
`;
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
render(
|
|
267
|
+
dropdownTarget,
|
|
268
|
+
html`<div class="benchmark-filter-dropdowns">${dropdowns}</div>`,
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
function legendKeyFunc(benchmark, key) {
|
|
272
|
+
return key === "group" ? benchmark.group : benchmark.params[key];
|
|
273
|
+
}
|
|
274
|
+
function renderChartWithFilters(currentFilters) {
|
|
275
|
+
const queryFilter = { ...query, ...currentFilters };
|
|
276
|
+
const data = sortBenchmarksByParams(
|
|
277
|
+
getBenchmarkData(results, queryFilter),
|
|
278
|
+
sortBy,
|
|
279
|
+
);
|
|
280
|
+
let legendGroupKey =
|
|
281
|
+
queryFilter?.storage_type == ""
|
|
282
|
+
? "storage_type"
|
|
283
|
+
: Object.entries(queryFilter).find((entry) => entry[1] === "")?.[0];
|
|
284
|
+
Plotly.newPlot(
|
|
285
|
+
chartTarget,
|
|
286
|
+
data.map((benchmark) => ({
|
|
287
|
+
type: "box",
|
|
288
|
+
name: nameTransform(benchmark, true, queryFilter),
|
|
289
|
+
y: benchmark.stats.data || [
|
|
290
|
+
benchmark.stats.min * 1e3,
|
|
291
|
+
benchmark.stats.q1 * 1e3,
|
|
292
|
+
benchmark.stats.median * 1e3,
|
|
293
|
+
benchmark.stats.q3 * 1e3,
|
|
294
|
+
benchmark.stats.max * 1e3,
|
|
295
|
+
],
|
|
296
|
+
boxmean: true,
|
|
297
|
+
boxpoints: false,
|
|
298
|
+
line: { width: 1 },
|
|
299
|
+
marker: {
|
|
300
|
+
color: getColorForStorage(benchmark.params.storage_type),
|
|
301
|
+
},
|
|
302
|
+
showlegend: true,
|
|
303
|
+
legendgroup: legendKeyFunc(benchmark, legendGroupKey),
|
|
304
|
+
legendgrouptitle: {
|
|
305
|
+
text: formatParam(
|
|
306
|
+
legendGroupKey,
|
|
307
|
+
legendKeyFunc(benchmark, legendGroupKey),
|
|
308
|
+
),
|
|
309
|
+
},
|
|
310
|
+
})),
|
|
311
|
+
{
|
|
312
|
+
yaxis: {
|
|
313
|
+
title: { text: "Time (ms)" },
|
|
314
|
+
exponentformat: "none",
|
|
315
|
+
ticksuffix: " ms",
|
|
316
|
+
tickformat: ",.2f",
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
responsive: true,
|
|
321
|
+
displaylogo: false,
|
|
322
|
+
},
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
renderDropdowns();
|
|
327
|
+
renderChartWithFilters(currentFilters);
|
|
328
|
+
let initial = true;
|
|
329
|
+
chartTarget.on("plotly_afterplot", function () {
|
|
330
|
+
const { hash } = window.location;
|
|
331
|
+
if (hash && initial) {
|
|
332
|
+
initial = false;
|
|
333
|
+
const target = document.querySelector(hash);
|
|
334
|
+
if (target) {
|
|
335
|
+
setTimeout(function () {
|
|
336
|
+
target.scrollIntoView({ behavior: "instant" });
|
|
337
|
+
}, 10);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
});
|
|
@@ -1,21 +1,37 @@
|
|
|
1
1
|
import { render, html } from "https://unpkg.com/uhtml@3.2.1?module";
|
|
2
|
+
import { fetchBenchmarkData } from "./benchmark-loader.js";
|
|
2
3
|
document.addEventListener("DOMContentLoaded", function () {
|
|
3
4
|
const details = document.querySelectorAll(".benchmark-details");
|
|
5
|
+
let dispatched = new Set();
|
|
4
6
|
details.forEach((detail) => {
|
|
5
7
|
let source = detail.dataset.source;
|
|
6
8
|
if (!dispatched.has(source)) {
|
|
7
|
-
fetchBenchmarkData(`${source}.json`)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
fetchBenchmarkData(`${source}.json`)
|
|
10
|
+
.then((result) => {
|
|
11
|
+
window.Benchmarks[source] = result;
|
|
12
|
+
let event = new Event(`${source}-loaded`);
|
|
13
|
+
window.dispatchEvent(event);
|
|
14
|
+
})
|
|
15
|
+
.catch((error) => {
|
|
16
|
+
let event = new Event(`${source}-failed`);
|
|
17
|
+
window.dispatchEvent(event);
|
|
18
|
+
});
|
|
12
19
|
}
|
|
13
20
|
dispatched.add(source);
|
|
21
|
+
window.addEventListener(`${detail.dataset.source}-failed`, function () {
|
|
22
|
+
render(
|
|
23
|
+
detail,
|
|
24
|
+
html`
|
|
25
|
+
<div class="benchmark-details-error">
|
|
26
|
+
Benchmark data not available.
|
|
27
|
+
</div>
|
|
28
|
+
`,
|
|
29
|
+
);
|
|
30
|
+
});
|
|
14
31
|
window.addEventListener(`${detail.dataset.source}-loaded`, function () {
|
|
15
32
|
const machine_info = window.Benchmarks[source].machine_info;
|
|
16
33
|
const commit_info = window.Benchmarks[source].commit_info;
|
|
17
34
|
const cpu = window.Benchmarks[source].machine_info.cpu;
|
|
18
|
-
console.log(machine_info);
|
|
19
35
|
render(
|
|
20
36
|
detail,
|
|
21
37
|
html`
|
|
@@ -7,16 +7,13 @@ window.Benchmarks = new Map();
|
|
|
7
7
|
|
|
8
8
|
function fetchBenchmarkData(filename) {
|
|
9
9
|
let attempts = 0;
|
|
10
|
-
|
|
11
10
|
function tryFetch() {
|
|
12
11
|
if (attempts >= BENCHMARK_PATHS.length) {
|
|
13
|
-
return Promise.reject("All fetch attempts failed.");
|
|
12
|
+
return Promise.reject(new Error("All fetch attempts failed."));
|
|
14
13
|
}
|
|
15
|
-
|
|
16
14
|
const base = BENCHMARK_PATHS[attempts++];
|
|
17
15
|
const url = base + filename;
|
|
18
|
-
|
|
19
|
-
// First send a HEAD request to quietly check existence
|
|
16
|
+
console.log(`Testing ${url}`);
|
|
20
17
|
return fetch(url, { method: "HEAD" })
|
|
21
18
|
.then((headRes) => {
|
|
22
19
|
if (!headRes.ok) throw new Error("HEAD check failed");
|
|
@@ -30,3 +27,5 @@ function fetchBenchmarkData(filename) {
|
|
|
30
27
|
|
|
31
28
|
return tryFetch();
|
|
32
29
|
}
|
|
30
|
+
|
|
31
|
+
export { fetchBenchmarkData };
|