Skip to content

Commit bba8dd0

Browse files
committed
with new data
1 parent 97d5a2c commit bba8dd0

File tree

3 files changed

+169
-60
lines changed

3 files changed

+169
-60
lines changed

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<!-- <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>-->
1313
<script src="src/lib/bootstrap.bundle.js"></script>
1414
<script type="text/javascript" src="src/DataTables/datatables.min.js"></script>
15+
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/11.11.2/math.min.js"></script>
1516
</head>
1617
<body>
1718
<div class="cover" style="padding:12.5%">

src/js/main.js

Lines changed: 167 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ const JOB = 'jobs_info';
44
const JOBNAME = 'job_name';
55
const USER = 'user_name';
66
let mode = 'historical'; // 'realTime' or 'historical'
7-
const timeFormat = d3.timeFormat('%Y-%m-%dT%H:%M:%S-05:00');
7+
const timeFormat = d3.timeFormat('%Y-%m-%dT%H:%M:%S-06:00');
8+
let sampleMinTime = null;
9+
let sampleMaxTime = null;
810
// layout
911
let Layout = {
1012
data: {},
@@ -114,26 +116,24 @@ function renderModeMenu() {
114116
// Handle time range changes
115117
d3.select('#realTimeRange')
116118
.on('change', function () {
117-
const selected = +this.value;
118-
const intervalSelect = d3.select('#realTimeInterval');
119-
const intervalBox = d3.select('#intervalContainer');
120-
const startEndBox = d3.select('#startEndContainer');
121-
const processBtn = d3.select('#processBtn');
122-
123-
if (selected === -1) {
124-
intervalBox.style('display', 'none');
125-
startEndBox.style('display', null); // show time inputs
126-
processBtn.style('display', null); // show Process button
127-
} else if (selected === -3) {
128-
intervalBox.style('display', 'none');
129-
startEndBox.style('display', 'none');
130-
processBtn.style('display', 'none');
131-
loadSampleData()
132-
}
133-
else {
134-
intervalBox.style('display', null); // show interval
135-
startEndBox.style('display', 'none'); // hide time inputs
136-
processBtn.style('display', 'none'); // hide button
119+
const selected = +this.value;
120+
const intervalSelect = d3.select('#realTimeInterval');
121+
const intervalBox = d3.select('#intervalContainer');
122+
const startEndBox = d3.select('#startEndContainer');
123+
const processBtn = d3.select('#processBtn');
124+
if (selected === -1) {
125+
intervalBox.style('display', 'none');
126+
startEndBox.style('display', null);
127+
processBtn.style('display', null);
128+
} else if (selected === -3) {
129+
intervalBox.style('display', 'none');
130+
startEndBox.style('display', null);
131+
processBtn.style('display', null);
132+
loadSampleData()
133+
} else {
134+
intervalBox.style('display', null); // show interval
135+
startEndBox.style('display', 'none'); // hide time inputs
136+
processBtn.style('display', 'none'); // hide button
137137

138138
// Update interval options
139139
const intervalOptions = INTERVALS[selected] || [];
@@ -458,6 +458,7 @@ async function fetchDataAndProcess(Params, isRealTime = true) {
458458
cpu_power: Array(len).fill().map(() => []),
459459
// gpu_mem: Array(len).fill().map(() => []),
460460
// gpu_usage: Array(len).fill().map(() => []),
461+
memory_usage: Array(len).fill().map(() => []),
461462
temperature: Array(len).fill().map(() => []),
462463
cpu_usage: Array(len).fill().map(() => []),
463464
dram_usage: Array(len).fill().map(() => []),
@@ -466,14 +467,14 @@ async function fetchDataAndProcess(Params, isRealTime = true) {
466467
jobName: []
467468
};
468469
}
469-
470470
nodes_info[node].cpus[idx] = entry.cores ?? [];
471471
nodes_info[node].job_id[idx] = entry.jobs ?? [];
472472
nodes_info[node].system_power[idx] = entry.system_power_consumption ?? [];
473473
// nodes_info[node].gpu_power[idx] = (entry.gpu_power_consumption ?? []).map(v => v / 1000);
474474
nodes_info[node].cpu_power[idx] = entry.cpu_power_consumption ?? [];
475475
// nodes_info[node].gpu_mem[idx] = entry.gpu_memory_usage ?? [];
476476
// nodes_info[node].gpu_usage[idx] = entry.gpu_usage ?? [];
477+
nodes_info[node].memory_usage[idx] = entry.memory_usage ?? [];
477478
nodes_info[node].temperature[idx] = entry.temperature ?? [];
478479
nodes_info[node].cpu_usage[idx] = entry.cpu_usage ?? [];
479480
nodes_info[node].dram_usage[idx] = entry.dram_usage ?? [];
@@ -605,19 +606,90 @@ function startRealTimePolling(isRealTime = true) {
605606
realTimeIntervalId = setInterval(fetchAndUpdate, intervalMs);
606607
}
607608

609+
// async function loadHistoricalAcrossRanges() {
610+
// const start = document.getElementById('startTime')?.value;
611+
// const end = document.getElementById('endTime')?.value;
612+
// if (!start || !end) {
613+
// console.warn('Start or End time is missing.');
614+
// return;
615+
// }
616+
617+
// const data = await fetchAllNodeRanges(start, end);
618+
// request = new Simulation(Promise.resolve(data)); // you might need to adapt Simulation constructor
619+
// initdraw();
620+
// initTimeElement();
621+
// }
622+
608623
async function loadHistoricalAcrossRanges() {
609624
const start = document.getElementById('startTime')?.value;
610625
const end = document.getElementById('endTime')?.value;
626+
611627
if (!start || !end) {
612628
console.warn('Start or End time is missing.');
613629
return;
614630
}
615631

616-
const data = await fetchAllNodeRanges(start, end);
617-
request = new Simulation(Promise.resolve(data)); // you might need to adapt Simulation constructor
618-
initdraw();
619-
initTimeElement();
632+
if (document.getElementById('realTimeRange').value == -3) {
633+
const data = await fetchDataAndProcess({}, false);
634+
635+
// Convert to timestamps (milliseconds)
636+
const startDate = new Date(start).getTime() * 1e6; // Convert to milliseconds
637+
const endDate = new Date(end).getTime() * 1e6; // Convert to milliseconds
638+
639+
console.log('Start date:', startDate, 'End date:', endDate);
640+
console.log('Data timestamps:', data.time_stamp);
641+
// Ensure time_stamp is in milliseconds
642+
data.time_stamp = data.time_stamp.map(d => d instanceof Date ? d.getTime() : d);
643+
console.log('Data timestamps:', data.time_stamp);
644+
645+
const validIndexes = data.time_stamp
646+
.map((t, i) => ({ t, i }))
647+
.filter(({ t }) => t >= startDate && t <= endDate)
648+
.map(({ i }) => i);
649+
650+
const filteredTimestamps = validIndexes.map(i => data.time_stamp[i]);
651+
652+
const filteredNodesInfo = {};
653+
for (const [node, metrics] of Object.entries(data.nodes_info)) {
654+
const filteredMetrics = {};
655+
for (const [key, arr] of Object.entries(metrics)) {
656+
filteredMetrics[key] = Array.isArray(arr)
657+
? validIndexes.map(i => arr[i])
658+
: arr;
659+
}
660+
filteredNodesInfo[node] = filteredMetrics;
661+
}
662+
663+
const filteredData = {
664+
...data,
665+
time_stamp: filteredTimestamps,
666+
nodes_info: filteredNodesInfo,
667+
};
668+
669+
request = new Simulation(Promise.resolve(filteredData));
670+
671+
d3.select('#chartContainer').selectAll("*").remove();
672+
updateProcess({
673+
percentage: 5,
674+
text: 'Load UI...'
675+
})
676+
initMenu();
677+
updateProcess({
678+
percentage: 15,
679+
text: 'Preprocess data...'
680+
});
681+
initdraw();
682+
initTimeElement();
683+
}
684+
else {
685+
// Regular fetch mode
686+
const data = await fetchAllNodeRanges(start, end);
687+
request = new Simulation(Promise.resolve(data));
688+
initdraw();
689+
initTimeElement();
690+
}
620691
}
692+
621693
function loadHistoricalData() {
622694
if (realTimeIntervalId) clearInterval(realTimeIntervalId);
623695

@@ -635,24 +707,59 @@ function loadHistoricalData() {
635707
initTimeElement();
636708
}
637709

638-
function loadSampleData() {
710+
async function loadSampleData() {
639711
if (realTimeIntervalId) clearInterval(realTimeIntervalId);
640-
request = new Simulation(fetchDataAndProcess({}, false));
641-
initdraw();
712+
const data = await fetchDataAndProcess({}, false);
713+
714+
// Store min/max times from sample data
715+
const timestamps = data.time_stamp.map(ts => new Date(ts / 1e6)); // Convert from ns to ms
716+
const toUTCMinus6 = ts => new Date(ts - 6 * 60 * 60 * 1000);
717+
718+
sampleMinTime = toUTCMinus6(Math.min(...timestamps));
719+
sampleMaxTime = toUTCMinus6(Math.max(...timestamps));
720+
721+
722+
723+
if (sampleMinTime && sampleMaxTime) {
724+
const startInput = d3.select('#startTime').node();
725+
const endInput = d3.select('#endTime').node();
726+
727+
// Format: YYYY-MM-DDTHH:mm
728+
const toInputValue = d => d.toISOString().slice(0, 16);
729+
730+
const minStr = toInputValue(sampleMinTime);
731+
const maxStr = toInputValue(sampleMaxTime);
732+
733+
// 👇 Limit the allowed selectable range
734+
startInput.min = endInput.min = minStr;
735+
startInput.max = endInput.max = maxStr;
736+
737+
// Optional: set default values
738+
startInput.value = minStr;
739+
endInput.value = maxStr;
740+
}
741+
request = new Simulation(Promise.resolve(data));
742+
743+
updateProcess({
744+
percentage: 5,
745+
text: 'Load UI...'
746+
})
747+
initMenu();
748+
updateProcess({
749+
percentage: 15,
750+
text: 'Preprocess data...'
751+
});
752+
initdraw();
642753
initTimeElement();
643-
}
644-
d3.selectAll('#navMode li a').on('click', function () {
645-
const mode = d3.select(this.parentNode).classed('realtime') ? 'realTime' : 'historical';
646-
renderModeMenu(mode);
647-
setTimeout(() => {
648-
if (mode === 'realTime') {
649-
startRealTimePolling();
650-
} else {
651-
// loadHistoricalData();
652-
loadSampleData();
653754
}
654-
}, 100);
655-
});
755+
d3.selectAll('#navMode li a').on('click', function () {
756+
const mode = d3.select(this.parentNode).classed('realtime') ? 'realTime' : 'historical';
757+
renderModeMenu(mode);
758+
setTimeout(() => {
759+
loadSampleData();
760+
761+
}, 100);
762+
});
656763

657764
$(document).ready(function () {
658765
try {
@@ -669,7 +776,7 @@ $(document).ready(function () {
669776
// "gpu_mem", "gpu_usage", "cpu_usage", "dram_usage",
670777
// ];
671778
serviceListattr = [
672-
"system_power","cpu_power", "dram_power", "temperature", "cpu_usage", "dram_usage",
779+
"system_power","cpu_power", "temperature", "cpu_usage", "memory_usage",
673780
];
674781

675782
serviceLists = serviceListattr.map((key, index) => ({
@@ -682,7 +789,7 @@ $(document).ready(function () {
682789
enable: true,
683790
idroot: index,
684791
angle: 0,
685-
range: index == 3 ? [0, 100] : [0, 3000],
792+
range: [0, 3000],
686793
}]
687794
}));
688795
serviceFullList = [];
@@ -809,35 +916,35 @@ function updateServiceRanges(data) {
809916

810917
// Initialize min/max for each metric
811918
for (const metric of metrics) {
812-
rangeMap[metric] = { min: Infinity, max: -Infinity };
919+
rangeMap[metric] = { min: Infinity, max: -Infinity, sum: 0, count: 0 };
813920
}
814-
815921
// Loop through nodes and update min/max values
816922
for (const node in data.nodes_info) {
817923
const info = data.nodes_info[node];
818924
metrics.forEach(metric => {
819-
const values = (info[metric] || []).flat(); // Flatten 2D array if needed
820-
for (const v of values) {
821-
if (v != null && !isNaN(v)) {
822-
rangeMap[metric].min = Math.min(rangeMap[metric].min, v);
823-
rangeMap[metric].max = Math.max(rangeMap[metric].max, v);
824-
}
825-
}
925+
const values = (info[metric] || []).flat();
926+
rangeMap[metric].min = Math.min(rangeMap[metric].min, Math.min(...values));
927+
rangeMap[metric].max = Math.max(rangeMap[metric].max, Math.max(...values));
928+
rangeMap[metric].sum += values.reduce((a, b) => a + b, 0);
929+
rangeMap[metric].count += values.length;
826930
});
827931
}
828932

829-
// Update serviceLists.sub.range
830-
for (const service of serviceLists) {
831-
const metric = service.text;
832-
const r = rangeMap[metric];
833-
if (r.min !== Infinity && r.max !== -Infinity) {
834-
service.sub[0].range = [Math.floor(r.min), Math.ceil(r.max)];
835-
}
933+
for (const service of serviceLists) {
934+
const metric = service.idroot != null ? serviceListattr[service.idroot] : service.text;
935+
const r = rangeMap[metric];
936+
if (r && r.min !== Infinity && r.max !== -Infinity) {
937+
service.sub[0].range = [Math.floor(r.min), Math.ceil(r.max)];
938+
service.sub[0].defaultThreshold = rangeMap[metric].count > 0
939+
? Math.floor(rangeMap[metric].sum / rangeMap[metric].count)
940+
: 0;
836941
}
942+
}
837943

838944
console.log("Updated ranges:", serviceLists.map(s => ({
839945
metric: s.text,
840-
range: s.sub[0].range
946+
range: s.sub[0].range,
947+
defaultThreshold: s.sub[0].defaultThreshold
841948
})));
842949
}
843950

src/js/simulation.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class Simulation {
1313
onDataChange=[];
1414
onUpdateTime=[];
1515
onStartQuery=()=>{};
16+
1617
constructor(url) {
1718
this.updateData.bind(this)(url);
1819
}

0 commit comments

Comments
 (0)