Add shared reasource tag to allow coordination of usage
🧪 Test / test (push) Successful in 6m8s

This commit is contained in:
2026-05-09 15:22:27 +02:00
parent 9acc42b2e9
commit 278c122e8f
7 changed files with 509 additions and 5 deletions
+44
View File
@@ -46,6 +46,7 @@ static std::pair<std::string,std::string> parse_edge_name(const std::string& nam
static std::string to_json(const std::vector<NodeSnapshot>& nodes,
const std::vector<ChannelSnapshot>& channels,
const std::vector<ResourceSnapshot>& resources = {},
double elapsed_s = 0.0) {
std::ostringstream o;
o << std::fixed;
@@ -84,6 +85,18 @@ static std::string to_json(const std::vector<NodeSnapshot>& nodes,
<< ",\"bw_mbs\":" << c.bandwidth_mbs(elapsed_s)
<< "}";
}
o << "],\"resources\":[";
for (std::size_t i = 0; i < resources.size(); ++i) {
const auto& r = resources[i];
if (i) o << ',';
o << "{\"name\":\"" << escape_json(r.name) << "\""
<< ",\"acquisitions\":" << r.acquisitions
<< ",\"avg_wait_ms\":" << r.avg_wait_ms
<< ",\"peak_waiters\":" << r.peak_waiters
<< ",\"current_waiters\":" << r.current_waiters
<< ",\"held\":" << (r.held ? "true" : "false")
<< "}";
}
o << "]}";
return o.str();
}
@@ -112,12 +125,24 @@ static const char* HTML = R"html(<!DOCTYPE html>
border-radius: 4px; padding: 8px 12px; font-size: 11px; pointer-events: none;
display: none; white-space: pre; line-height: 1.6;
}
#resources {
position: absolute; bottom: 12px; right: 12px;
background: #16213e; border: 1px solid #0f3460; border-radius: 4px;
padding: 8px 12px; font-size: 10px; min-width: 220px;
display: none;
}
#resources h2 { margin: 0 0 6px; font-size: 11px; color: #e94560; }
.res-row { display: flex; justify-content: space-between; gap: 12px; margin-top: 3px; }
.res-name { color: #eee; }
.res-held-y { color: #e94560; }
.res-held-n { color: #4CAF50; }
</style>
</head>
<body>
<div id="header"><h1>KPN++ Web Debug</h1><span id="status">connecting...</span></div>
<svg id="graph"></svg>
<div id="tooltip"></div>
<div id="resources"><h2>Shared Resources</h2><div id="res-list"></div></div>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script>
const nodeRadius = 30;
@@ -200,6 +225,7 @@ function init(data) {
.text(d => `${d.ema_exec_ms.toFixed(1)}ms ${d.fps.toFixed(1)}fps`);
nodeSel = nodeG;
renderResources(data.resources);
// Tooltips
const tip = d3.select('#tooltip');
@@ -224,7 +250,25 @@ function init(data) {
}).on('mouseleave', () => tip.style('display','none'));
}
function renderResources(resources) {
const panel = document.getElementById('resources');
const list = document.getElementById('res-list');
if (!resources || resources.length === 0) { panel.style.display = 'none'; return; }
panel.style.display = 'block';
list.innerHTML = resources.map(r => {
const heldCls = r.held ? 'res-held-y' : 'res-held-n';
const heldTxt = r.held ? 'HELD' : 'free';
return `<div class="res-row">
<span class="res-name">${r.name}</span>
<span class="${heldCls}">${heldTxt}</span>
<span>wait ${r.avg_wait_ms.toFixed(1)}ms</span>
<span>waiters ${r.current_waiters}/${r.peak_waiters}</span>
</div>`;
}).join('');
}
function update(data) {
renderResources(data.resources);
// Update node stats in-place (preserve simulation x/y positions)
const byId = Object.fromEntries(data.nodes.map(n => [n.id, n]));
nodes.forEach(n => {