Add a MultiRingBuffer type, and use it to cleanly emit stacked charts for the tree system.

This commit is contained in:
Herbert Wolverson 2023-03-06 21:44:04 +00:00
parent 664d29e783
commit 39f605e195
2 changed files with 81 additions and 70 deletions

View File

@ -3,9 +3,9 @@ function metaverse_color_ramp(n) {
return "#32b08c"; return "#32b08c";
} else if (n <= 20) { } else if (n <= 20) {
return "#ffb94a"; return "#ffb94a";
} else if (n <=50) { } else if (n <= 50) {
return "#f95f53"; return "#f95f53";
} else if (n <=70) { } else if (n <= 70) {
return "#bf3d5e"; return "#bf3d5e";
} else { } else {
return "#dc4e58"; return "#dc4e58";
@ -49,9 +49,9 @@ function deleteAllCookies() {
function cssrules() { function cssrules() {
var rules = {}; var rules = {};
for (var i=0; i<document.styleSheets.length; ++i) { for (var i = 0; i < document.styleSheets.length; ++i) {
var cssRules = document.styleSheets[i].cssRules; var cssRules = document.styleSheets[i].cssRules;
for (var j=0; j<cssRules.length; ++j) for (var j = 0; j < cssRules.length; ++j)
rules[cssRules[j].selectorText] = cssRules[j]; rules[cssRules[j].selectorText] = cssRules[j];
} }
return rules; return rules;
@ -80,7 +80,7 @@ function updateHostCounts() {
$("#currentLogin").html(html); $("#currentLogin").html(html);
}); });
$("#startTest").on('click', () => { $("#startTest").on('click', () => {
$.get("/api/run_btest", () => {}); $.get("/api/run_btest", () => { });
}); });
} }
@ -88,9 +88,9 @@ function colorReloadButton() {
$("body").append(reloadModal); $("body").append(reloadModal);
$("#btnReload").on('click', () => { $("#btnReload").on('click', () => {
$.get("/api/reload_libreqos", (result) => { $.get("/api/reload_libreqos", (result) => {
const myModal = new bootstrap.Modal(document.getElementById('reloadModal'), {focus: true}); const myModal = new bootstrap.Modal(document.getElementById('reloadModal'), { focus: true });
$("#reloadLibreResult").text(result); $("#reloadLibreResult").text(result);
myModal.show(); myModal.show();
}); });
}); });
$.get("/api/reload_required", (req) => { $.get("/api/reload_required", (req) => {
@ -150,7 +150,7 @@ function redactText(text) {
if (!isRedacted()) return text; if (!isRedacted()) return text;
let redacted = ""; let redacted = "";
let sum = 0; let sum = 0;
for(let i = 0; i < text.length; i++){ for (let i = 0; i < text.length; i++) {
let code = text.charCodeAt(i); let code = text.charCodeAt(i);
sum += code; sum += code;
} }
@ -160,13 +160,13 @@ function redactText(text) {
function scaleNumber(n) { function scaleNumber(n) {
if (n > 1000000000000) { if (n > 1000000000000) {
return (n/1000000000000).toFixed(2) + "T"; return (n / 1000000000000).toFixed(2) + "T";
} else if (n > 1000000000) { } else if (n > 1000000000) {
return (n/1000000000).toFixed(2) + "G"; return (n / 1000000000).toFixed(2) + "G";
} else if (n > 1000000) { } else if (n > 1000000) {
return (n/1000000).toFixed(2) + "M"; return (n / 1000000).toFixed(2) + "M";
} else if (n > 1000) { } else if (n > 1000) {
return (n/1000).toFixed(2) + "K"; return (n / 1000).toFixed(2) + "K";
} }
return n; return n;
} }
@ -190,17 +190,75 @@ const reloadModal = `
</div> </div>
</div>`; </div>`;
function yValsRingSort(y, head, capacity) {
let result = [];
for (let i=0; i<head; ++i)
result.push(y[i]);
for (let i=head; i<capacity; ++i) {
result.push(y[i])
}
return result;
}
// MultiRingBuffer provides an interface for storing multiple ring-buffers
// of performance data, with a view to them ending up on the same graph.
class MultiRingBuffer {
constructor(capacity) {
this.capacity = capacity;
this.data = {};
}
push(id, download, upload) {
if (!this.data.hasOwnProperty(id)) {
this.data[id] = new RingBuffer(this.capacity);
}
this.data[id].push(download, upload);
}
plotStackedBars(target_div, rootName) {
let graphData = [];
for (const [k, v] of Object.entries(this.data)) {
if (k != rootName) {
let total = v.download.reduce((a, b) => a + b) +
v.upload.reduce((a, b) => a + b);
if (total > 0) {
let dn = { x: v.x_axis, y: yValsRingSort(v.download, v.head, v.capacity), name: k + "_DL", type: 'scatter', stackgroup: 'dn' };
let up = { x: v.x_axis, y: yValsRingSort(v.upload, v.head, v.capacity), name: k + "_UL", type: 'scatter', stackgroup: 'up' };
graphData.push(dn);
graphData.push(up);
}
}
}
/*let v = buffers[rootName];
let dn = { x: v.x_axis, y: v.download, name: "DL", type: 'scatter', fill: null };
let up = { x: v.x_axis, y: v.upload, name: "UL", type: 'scatter', fill: null };
graphData.push(dn);
graphData.push(up);*/
let graph = document.getElementById(target_div);
Plotly.newPlot(
graph,
graphData,
{
margin: { l: 0, r: 0, b: 0, t: 0, pad: 4 },
yaxis: { automargin: true },
xaxis: { automargin: true, title: "Time since now (seconds)" },
showlegend: false,
},
{ responsive: true, displayModeBar: false });
}
}
class RingBuffer { class RingBuffer {
constructor(capacity) { constructor(capacity) {
this.capacity = capacity; this.capacity = capacity;
this.head = capacity-1; this.head = capacity - 1;
this.download = []; this.download = [];
this.upload = []; this.upload = [];
this.x_axis = []; this.x_axis = [];
for (var i=0; i<capacity; ++i) { for (var i = 0; i < capacity; ++i) {
this.download.push(0.0); this.download.push(0.0);
this.upload.push(0.0); this.upload.push(0.0);
this.x_axis.push(i); this.x_axis.push(0-i);
} }
} }
@ -224,14 +282,14 @@ class RttHistogram {
constructor() { constructor() {
this.entries = [] this.entries = []
this.x = []; this.x = [];
for (let i=0; i<20; ++i) { for (let i = 0; i < 20; ++i) {
this.entries.push(i); this.entries.push(i);
this.x.push(i * 10); this.x.push(i * 10);
} }
} }
clear() { clear() {
for (let i=0; i<20; ++i) { for (let i = 0; i < 20; ++i) {
this.entries[i] = 0; this.entries[i] = 0;
} }
} }

View File

@ -115,7 +115,7 @@
<script> <script>
let node = 0; let node = 0;
let buffers = {}; let buffers = new MultiRingBuffer(300);
let rtt_histo = new RttHistogram(); let rtt_histo = new RttHistogram();
function bgColor(traffic, limit) { function bgColor(traffic, limit) {
@ -147,15 +147,8 @@
tbl += "<td style='background-color: " + dnbg + "'>" + scaleNumber(data[i].traffic[0] * 8) + "</td>"; tbl += "<td style='background-color: " + dnbg + "'>" + scaleNumber(data[i].traffic[0] * 8) + "</td>";
tbl += "<td style='background-color: " + upbg + "'>" + scaleNumber(data[i].traffic[1] * 8) + "</td>"; tbl += "<td style='background-color: " + upbg + "'>" + scaleNumber(data[i].traffic[1] * 8) + "</td>";
let nodeName = data[i].name; buffers.push(nodeName, data[i].traffic[0] * 8, data[i].traffic[1] * 8);
if (!buffers.hasOwnProperty(nodeName)) { }
buffers[nodeName] = new RingBuffer(300);
}
buffers[nodeName].push(
data[i].traffic[0] * 8,
data[i].traffic[1] * 8
);
}
tbl += "</table>"; tbl += "</table>";
$("#clientList").html(tbl); $("#clientList").html(tbl);
}); });
@ -178,13 +171,7 @@
getClients(rootName); getClients(rootName);
// Throughput graph // Throughput graph
if (!buffers.hasOwnProperty(rootName)) { buffers.push(rootName, data[0][1].current_throughput[0] * 8, data[0][1].current_throughput[1] * 8);
buffers[rootName] = new RingBuffer(300);
}
buffers[rootName].push(
data[0][1].current_throughput[0] * 8,
data[0][1].current_throughput[1] * 8
);
// Build the table & update node buffers // Build the table & update node buffers
let tbl = "<table class='table'>"; let tbl = "<table class='table'>";
@ -192,13 +179,7 @@
for (let i = 1; i < data.length; ++i) { for (let i = 1; i < data.length; ++i) {
let nodeName = data[i][1].name; let nodeName = data[i][1].name;
if (!buffers.hasOwnProperty(nodeName)) { buffers.push(nodeName, data[i][1].current_throughput[0] * 8,data[i][1].current_throughput[1] * 8);
buffers[nodeName] = new RingBuffer(300);
}
buffers[nodeName].push(
data[i][1].current_throughput[0] * 8,
data[i][1].current_throughput[1] * 8
);
tbl += "<tr>"; tbl += "<tr>";
tbl += "<td style='width: 20%' class='redact'><a href='/tree?parent=" + encodeURI(data[i][0]) + "'>" + redactText(nodeName) + "</a></td>"; tbl += "<td style='width: 20%' class='redact'><a href='/tree?parent=" + encodeURI(data[i][0]) + "'>" + redactText(nodeName) + "</a></td>";
@ -232,35 +213,7 @@
$("#treeList").html(tbl); $("#treeList").html(tbl);
// Build the stacked chart // Build the stacked chart
let graphData = []; buffers.plotStackedBars("tpGraph", rootName);
for (const [k, v] of Object.entries(buffers)) {
if (k != rootName) {
let total = v.download.reduce((a, b) => a + b) +
v.upload.reduce((a, b) => a + b);
if (total > 0) {
let dn = { x: v.x_axis, y: v.download, name: k + "_DL", type: 'scatter', stackgroup: 'dn' };
let up = { x: v.x_axis, y: v.upload, name: k + "_UL", type: 'scatter', stackgroup: 'up' };
graphData.push(dn);
graphData.push(up);
}
}
}
/*let v = buffers[rootName];
let dn = { x: v.x_axis, y: v.download, name: "DL", type: 'scatter', fill: null };
let up = { x: v.x_axis, y: v.upload, name: "UL", type: 'scatter', fill: null };
graphData.push(dn);
graphData.push(up);*/
let graph = document.getElementById("tpGraph");
Plotly.newPlot(
graph,
graphData,
{
margin: { l: 0, r: 0, b: 0, t: 0, pad: 4 },
yaxis: { automargin: true },
xaxis: { automargin: true, title: "Time since now (seconds)" },
showlegend: false,
},
{ responsive: true, displayModeBar: false });
// Build the RTT histo // Build the RTT histo
rtt_histo.plot("rttHistogram"); rtt_histo.plot("rttHistogram");