aboutsummaryrefslogtreecommitdiffstats
path: root/src/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/api')
-rw-r--r--src/api/dashboard/dashboard.html65
1 files changed, 44 insertions, 21 deletions
diff --git a/src/api/dashboard/dashboard.html b/src/api/dashboard/dashboard.html
index 0ae99f4..ee22b3e 100644
--- a/src/api/dashboard/dashboard.html
+++ b/src/api/dashboard/dashboard.html
@@ -79,9 +79,16 @@
margin-left: 1em; cursor: pointer; }
section h2 label.choice input { vertical-align: -2px; margin: 0 3px 0 0; }
section.collapsed h2 label.choice { display: none; }
- /* The console's rates, after its filter. */
- section h2 .rates { font-size: 12px; text-transform: none; letter-spacing: 0;
+ /* The console's rates, at the right of its title: messages and bytes per second, a
+ row each, small enough for both to fit the title's line, centred on it. Columns as
+ wide as their widest content will be, so the numbers stay put as they change. */
+ section h2 .rates { float: right; display: grid;
+ grid-template-columns: repeat(3, minmax(5ch, auto)) minmax(5.5ch, auto);
+ column-gap: 5px; height: 18px; align-content: center;
+ font-size: 9px; line-height: 9px; text-transform: none; letter-spacing: 0;
margin-left: 1em; font-variant-numeric: tabular-nums; }
+ section h2 .rates span { text-align: right; }
+ section h2 .rates span.unit { text-align: left; }
section.collapsed h2 .rates { display: none; }
/* The right column dragged off to the side: the map takes the width. */
@media (min-width: 901px) {
@@ -262,7 +269,7 @@
<div id="column-hint" class="note">Drag the space left of these boxes to the right to
hide the column.</div>
<section id="console-box">
- <h2>Console <label class="choice" title="Only the messages with the node or over the link in focus (clicked on the map or in the peers); all while nothing is"><input type="checkbox" id="console-filter">filter selected</label><span id="console-rates" class="rates" title="Messages per second sent and received, as load averages are: over the last 1, 5 and 15 minutes (exponentially weighted), since the page was opened; with the filter, those with the node or over the link in focus">msg/s –</span></h2>
+ <h2>Console <label class="choice" title="Only the messages with the node or over the link in focus (clicked on the map or in the peers); all while nothing is"><input type="checkbox" id="console-filter">filter selected</label><span id="console-rates" class="rates" title="Messages and bytes per second sent and received, as load averages are: over the last 1, 5 and 15 minutes (exponentially weighted), since the page was opened; with the filter, those with the node or over the link in focus"></span></h2>
<div class="scroll" id="console-scroll"><div id="console" class="console"></div>
<div id="console-none" class="note" hidden>No information available</div></div>
</section>
@@ -1809,35 +1816,41 @@ function trafficArrived() {
if (flows.length > 0 && flowFrame === null) flowFrame = requestAnimationFrame(drawFlows);
}
-// --- The console's rates: messages per second sent and received, per peer and in all,
-// averaged as load averages are, over 1, 5 and 15 minutes (each sample weighs in by
-// how long ago it was, `e^(-age/window)`), from the counts each update brings. The
-// first sample is taken as it is, so they needn't climb from 0 first. ---
+// --- The console's rates: messages and bytes per second sent and received, per peer
+// and in all, averaged as load averages are, over 1, 5 and 15 minutes (each sample
+// weighs in by how long ago it was, `e^(-age/window)`), from the counts each update
+// brings. The first sample is taken as it is, so they needn't climb from 0 first. ---
const RATE_WINDOWS_S = [60, 300, 900];
-// By peer, and in all (`null`): the averages; and when the counts were last taken.
+// By peer, and in all (`null`): the averages (`messages`, `bytes`: per window); and when
+// the counts were last taken.
const rates = new Map();
let ratesAt = null;
function measureRates(current) {
const now = performance.now();
if (lastTraffic !== null && ratesAt !== null && now > ratesAt) {
const secs = (now - ratesAt) / 1000;
- const total = (counts, way) => Object.values(counts[way])
- .reduce((sum, count) => sum + count.messages, 0);
- let all = 0;
- const sample = (key, rate) => {
+ // Of `what` (`messages`, `bytes`), sent and received, by how much each grew.
+ const grown = (counts, before, what) => ["sent", "received"].reduce((sum, way) => {
+ const total = of => Object.values(of[way]).reduce((sum, count) => sum + count[what], 0);
+ return sum + Math.max(0, total(counts) - total(before));
+ }, 0);
+ const average = (known, rate) => known ? known.map((average, i) =>
+ rate + (average - rate) * Math.exp(-secs / RATE_WINDOWS_S[i])) : RATE_WINDOWS_S.map(() => rate);
+ const sample = (key, messages, bytes) => {
const known = rates.get(key);
- rates.set(key, known ? known.map((average, i) =>
- rate + (average - rate) * Math.exp(-secs / RATE_WINDOWS_S[i])) : RATE_WINDOWS_S.map(() => rate));
+ rates.set(key, { messages: average(known && known.messages, messages / secs),
+ bytes: average(known && known.bytes, bytes / secs) });
};
+ let messagesInAll = 0, bytesInAll = 0;
for (const [id, counts] of current) {
const before = lastTraffic.get(id);
if (!before) continue;
- const grown = Math.max(0, total(counts, "sent") - total(before, "sent")) +
- Math.max(0, total(counts, "received") - total(before, "received"));
- sample(id, grown / secs);
- all += grown;
+ const messages = grown(counts, before, "messages"), bytes = grown(counts, before, "bytes");
+ sample(id, messages, bytes);
+ messagesInAll += messages;
+ bytesInAll += bytes;
}
- sample(null, all / secs);
+ sample(null, messagesInAll, bytesInAll);
// Peers gone from the list: their averages too.
for (const key of [...rates.keys()]) if (key !== null && !current.has(key)) rates.delete(key);
}
@@ -1851,8 +1864,18 @@ function showRates() {
const peer = filtering ? peerOf(focused) : null;
const shown = filtering && peer === null ? undefined : rates.get(peer);
const format = rate => rate < 100 ? rate.toFixed(2) : String(Math.round(rate));
- text(document.getElementById("console-rates"),
- "msg/s " + (shown ? shown.map(format).join(" ") : "–"));
+ // Bytes in the unit the largest of the three needs, all three alike.
+ const largest = shown ? Math.max(...shown.bytes) : 0;
+ const [unit, per] = largest < 1024 ? ["B/s", 1] : largest < 1048576 ? ["KiB/s", 1024]
+ : ["MiB/s", 1048576];
+ const row = (values, unit) => [...(values ? values.map(format) : ["–", "", ""]), unit];
+ const cells = [...row(shown && shown.messages, "msg/s"),
+ ...row(shown && shown.bytes.map(bytes => bytes / per), unit)];
+ const box = document.getElementById("console-rates");
+ if (box.childElementCount !== cells.length) {
+ box.replaceChildren(...cells.map((_, i) => el("span", { class: i % 4 === 3 ? "unit" : "" })));
+ }
+ cells.forEach((cell, i) => text(box.children[i], cell));
}
// --- Console: the messages this node exchanged with its peers, one by one, as the