98 lines
3.9 KiB
JavaScript
98 lines
3.9 KiB
JavaScript
import { applyTableStyles, makeSortable } from '../ui/table.js';
|
|
import { createTimeRangeSelector, filterHistoryByTimeRange } from '../ui/timerange.js';
|
|
export function showNodeAnalytics(element, stats) {
|
|
const { container: rangeSelector, select: timeSelect } = createTimeRangeSelector();
|
|
function updateContent() {
|
|
// Filter history by time range
|
|
const history = filterHistoryByTimeRange(stats.history || [], timeSelect.value);
|
|
// Calculate node averages from filtered history
|
|
const nodeAverages = {};
|
|
history.forEach(run => {
|
|
const nodes = Object.values(run.nodes);
|
|
nodes.forEach(node => {
|
|
const nodeType = node.nodeType;
|
|
if (!nodeAverages[nodeType]) {
|
|
nodeAverages[nodeType] = {
|
|
total_time: 0,
|
|
vram_usage: 0,
|
|
ram_usage: 0,
|
|
count: 0,
|
|
cache_hits: 0
|
|
};
|
|
}
|
|
const stats = nodeAverages[nodeType];
|
|
stats.count++;
|
|
stats.total_time = (stats.total_time * (stats.count - 1) + (node.endTime - node.startTime)) / stats.count;
|
|
stats.vram_usage = (stats.vram_usage * (stats.count - 1) + (node.vramAfter - node.vramBefore)) / stats.count;
|
|
stats.ram_usage = (stats.ram_usage * (stats.count - 1) + (node.ramAfter - node.ramBefore)) / stats.count;
|
|
if (node.cacheHit)
|
|
stats.cache_hits++;
|
|
});
|
|
});
|
|
// Convert to array for sorting
|
|
const nodeStats = Object.entries(nodeAverages).map(([nodeType, stats]) => ({
|
|
nodeType,
|
|
...stats
|
|
}));
|
|
// Sort by execution time by default
|
|
nodeStats.sort((a, b) => b.total_time - a.total_time);
|
|
const contentDiv = element.querySelector('.node-analytics-content');
|
|
if (!contentDiv)
|
|
return;
|
|
const html = [`
|
|
<div style="margin: 8px 0;">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Node Type</th>
|
|
<th class="sort-numeric">Avg Time (s)</th>
|
|
<th class="sort-numeric">Avg VRAM (GB)</th>
|
|
<th class="sort-numeric">Runs</th>
|
|
<th class="sort-numeric">Cache Hit %</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
`];
|
|
nodeStats.forEach(node => {
|
|
const avgTime = (node.total_time / 1000).toFixed(3);
|
|
const avgVram = (node.vram_usage / 1e9).toFixed(2);
|
|
const cacheHitRate = ((node.cache_hits / node.count) * 100).toFixed(1);
|
|
html.push(`
|
|
<tr>
|
|
<td>${node.nodeType}</td>
|
|
<td>${avgTime}s</td>
|
|
<td>${avgVram}GB</td>
|
|
<td>${node.count}</td>
|
|
<td>${cacheHitRate}%</td>
|
|
</tr>
|
|
`);
|
|
});
|
|
html.push(`
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
`);
|
|
contentDiv.innerHTML = html.join('');
|
|
const table = contentDiv.querySelector('table');
|
|
if (table) {
|
|
applyTableStyles(table);
|
|
makeSortable(table);
|
|
}
|
|
}
|
|
// Set up the main container
|
|
element.innerHTML = `
|
|
<div style="padding: 8px;">
|
|
<h3>Node Performance Analytics</h3>
|
|
<div class="node-analytics-content"></div>
|
|
</div>
|
|
`;
|
|
// Insert range selector after heading
|
|
const heading = element.querySelector('h3');
|
|
if (heading)
|
|
heading.after(rangeSelector);
|
|
// Update when time range changes
|
|
timeSelect.addEventListener('change', updateContent);
|
|
// Initial content update
|
|
updateContent();
|
|
}
|