This commit is contained in:
@@ -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 => {
|
||||
|
||||
Reference in New Issue
Block a user