Skip to content

Commit

Permalink
Add support for selecting CPU(s)
Browse files Browse the repository at this point in the history
This will allow the user to select the CPU(s) for all the graphs in CPU
Utilization, Perf Stat and Interrupt tabs.
  • Loading branch information
janaknat committed Jul 1, 2024
1 parent a05d7ee commit a1f3590
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 15 deletions.
Binary file added src/html_files/configure.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
130 changes: 130 additions & 0 deletions src/html_files/configure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
class RunConfig {
run: string;
cpu_count: number;
cpu_list: Array<string>;
}

var run_config: Map<string, RunConfig> = new Map<string, RunConfig>();
var init_done = false;

function getCPUList(run) {
return run_config.get(run).cpu_list;
}

function formGlobalConfig() {
for (let i = 0; i < cpu_utilization_raw_data['runs'].length; i++) {
let this_run_data = cpu_utilization_raw_data['runs'][i];
let run_name = this_run_data['name'];
var config = new RunConfig();

/* Elemet 0 is aggregate. Don't use that. */
let key = this_run_data['keys'][1];
config.cpu_count = JSON.parse(this_run_data['key_values'][key]).length;
config.cpu_list = new Array<string>();
for (let i = 0; i < config.cpu_count; i++) {
config.cpu_list.push(i.toString());
}
run_config.set(run_name, config);
}
}

function isCPUListUnchanged(check_cpu_list, run) {
return check_cpu_list.sort().toString() === run_config.get(run).cpu_list.sort().toString();
}

function allSelect(elem: HTMLInputElement, run) {
let checkboxes = document.getElementsByName(`${run}-cpulist`);
for (let i = 0; i < checkboxes.length; i++) {
(checkboxes[i] as HTMLInputElement).checked = elem.checked;
toggleCheckbox(checkboxes[i] as HTMLInputElement, run, false);
}
}

function allCPUsCheck(run) {
let checkboxes = document.getElementsByName(`${run}-cpulist`);
let allToggled = true;
for (let i = 0; i < checkboxes.length; i++) {
if (!((checkboxes[i] as HTMLInputElement).checked)) {
allToggled = false;
break;
}
}
(document.getElementById(`${run}-CPUAll`) as HTMLInputElement).checked = allToggled;
}

function toggleCheckbox(elem: HTMLInputElement, run, check) {
let cpu_list = run_config.get(run).cpu_list;
if (elem.checked) {
if (cpu_list.indexOf(elem.value) == -1) {
cpu_list.push(elem.value);
}
} else {
let index = cpu_list.indexOf(elem.value);
if (index != -1) {
cpu_list.splice(index, 1);
}
}
if (check) {
allCPUsCheck(run);
}
}

function createCheckbox(run, id, label_str, name, value, toggle_func) {
let elem = document.createElement("input");
elem.setAttribute("type", "checkbox");
elem.id = id;
elem.name = name;
elem.value = value;
elem.addEventListener("click", function (ev: Event) {
toggle_func(this, run, true);
}, false);
let label = document.createElement("label");
label.htmlFor = id;
label.innerHTML = label_str;

let cpu_div = document.createElement("div");
cpu_div.appendChild(elem);
cpu_div.appendChild(label);
return cpu_div;
}

function createCPUConfigure(container_id, run) {
let config = run_config.get(run);

/* Add a Toggle All checkbox */
let all_cpu = createCheckbox(run, `${run}-CPUAll`, 'Toggle All', '', -1, allSelect);
addElemToNode(container_id, all_cpu);

let cpu_configure_list = document.createElement("div");
cpu_configure_list.id = `${run}-cpus-configure-list`;
cpu_configure_list.style.display = "grid";
addElemToNode(container_id, cpu_configure_list);
let max_cpus = config.cpu_count;
let max_columns = max_cpus / 16;
let cpus_per_column = Math.floor(max_cpus / max_columns);
for (let column = 0; column < max_columns; column++) {
let cpus_start = column * cpus_per_column;
let cpus_end = cpus_start + cpus_per_column;
if (cpus_end > max_cpus) {
cpus_end = max_cpus;
}
for (let i = cpus_start, row = 1; i < cpus_end; i++, row++) {
let cpu_div = createCheckbox(run, `${run}-CPU${i}`, `CPU ${i}`, `${run}-cpulist`, i, toggleCheckbox);
cpu_div.style.gridColumn = `${column + 1}`;
cpu_div.style.gridRow = `${row}`;
addElemToNode(`${run}-cpus-configure-list`, cpu_div);
}
}
document.getElementById(`${run}-CPUAll`).click();
}

function configure() {
if (init_done) {
return;
}
clear_and_create('configure');
runs_raw.forEach(function (value, index, arr) {
createCPUConfigure(`${value}-configure-per-data`, value);
});
init_done = true;
}
13 changes: 9 additions & 4 deletions src/html_files/cpu_utilization.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
let got_cpu_util_data = false;
let util_cpu_list: Map<string, Array<string>> = new Map<string, Array<string>>();

function getUtilizationType(run, elem, type, run_data) {
var cpu_type_datas = [];
Expand All @@ -9,18 +10,21 @@ function getUtilizationType(run, elem, type, run_data) {
data.forEach(function (value, index, arr) {
var x_time = [];
var y_data = [];
cpu = value.cpu;
cpu = value.cpu.toString();
type_data = value.data;
type_data.forEach(function (i_value, i_index, i_arr) {
x_time.push(i_value.time.TimeDiff);
y_data.push(i_value.value);
});
var cpu_type_data = {
var cpu_type_data: Partial<Plotly.PlotData> = {
name: `CPU ${cpu}`,
x: x_time,
y: y_data,
type: 'scatter',
};
}
if (util_cpu_list.get(run).indexOf(cpu) == -1) {
cpu_type_data.visible = 'legendonly';
}
cpu_type_datas.push(cpu_type_data);
});
var TESTER = elem;
Expand Down Expand Up @@ -134,12 +138,13 @@ function getCpuUtilization(elem, run, run_data) {
Plotly.newPlot(TESTER, data_list, layout, { frameMargins: 0 });
}
function cpuUtilization() {
if (got_cpu_util_data) {
if (got_cpu_util_data && allRunCPUListUnchanged(util_cpu_list)) {
return;
}
clear_and_create('cpuutilization');
for (let i = 0; i < cpu_utilization_raw_data['runs'].length; i++) {
let run_name = cpu_utilization_raw_data['runs'][i]['name'];
util_cpu_list.set(run_name, getCPUList(run_name).slice());
let elem_id = `${run_name}-cpuutilization-per-data`;
let this_run_data = cpu_utilization_raw_data['runs'][i];
getCpuUtilization(document.getElementById(elem_id), run_name, this_run_data['key_values']['aggregate']);
Expand Down
14 changes: 13 additions & 1 deletion src/html_files/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ body {

/* Style the buttons inside the tab */
.tab button {
display: block;
display: grid;
background-color: inherit;
color: black;
padding: 22px 16px;
Expand All @@ -51,6 +51,18 @@ body {
font-size: 17px;
}

.icon-text {
grid-column: 1;
}

.configure {
grid-column: 2;
background-image: url("images/configure.png");
background-repeat: no-repeat;
background-position-x: center;
background-position-y: center;
}

.all-runs {
grid-row: 1;
position: sticky;
Expand Down
10 changes: 9 additions & 1 deletion src/html_files/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
<html>
<head>
<link rel="stylesheet" href="index.css">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="icon" type="image/x-icon" href="images/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>APerf</title>
</head>
<body>
<div class="tab">
<div class="aperf">APerf</div>
<button class="tablinks" name="configure"><div class="icon-text">Configure</div><div class="configure"/></button>
<!--- Configure should be the first tab. Add any new tabs below this. -->
<button class="tablinks" name="system_info" id="default">SUT Config</button>
<button class="tablinks" name="cpu_utilization">CPU Utilization</button>
<button class="tablinks" name="flamegraphs">Flamegraphs</button>
Expand Down Expand Up @@ -98,6 +100,11 @@ <h3>Hide N/A and all-zero graphs:</h3>
<div id="aperfstat" class="tabcontent">
<div id="aperfstat-runs"></div>
</div>
<div id="configure" class="tabcontent">
<div id="configure-runs" class="extra">
<div id="cpus-configure"></div>
</div>
</div>
</div>
<script type="text/javascript" src="data/js/runs.js"></script>
<script type="text/javascript" src="data/js/system_info.js"></script>
Expand Down Expand Up @@ -130,6 +137,7 @@ <h3>Hide N/A and all-zero graphs:</h3>
<script type="text/javascript" src="js/perf_stat.js"></script>
<script type="text/javascript" src="js/netstat.js"></script>
<script type="text/javascript" src="js/aperf_run_stats.js"></script>
<script type="text/javascript" src="js/configure.js"></script>
<script type="text/javascript" src="index.js"></script>
</body>
</html>
3 changes: 3 additions & 0 deletions src/html_files/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ DataTypes.set('top_functions', {name: 'topfunctions', hideClass: '', trueId: '',
DataTypes.set('processes', {name: 'processes', hideClass: '', trueId: '', callback: processes});
DataTypes.set('perfstat', {name: 'perfstat', hideClass: '', trueId: '', callback: perfStat});
DataTypes.set('aperfstat', {name: 'aperfstat', hideClass: '', trueId: '', callback: aperfStat});
DataTypes.set('configure', {name: 'configure', hideClass: '', trueId: '', callback: configure});

function openData(evt: Event, elem: HTMLButtonElement) {
var tabName: string = elem.name;
Expand Down Expand Up @@ -118,5 +119,7 @@ function create_runs_header() {
// Set Runs header
create_runs_header();

formGlobalConfig();

// Show landing page
document.getElementById("default").click();
9 changes: 7 additions & 2 deletions src/html_files/interrupts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
let got_interrupt_data = false;
let interrupt_cpu_list: Map<string, Array<string>> = new Map<string, Array<string>>();

function getLine(run, elem, key, run_data) {
var data = JSON.parse(run_data);
Expand All @@ -15,12 +16,15 @@ function getLine(run, elem, key, run_data) {
}
})
})
var interrupt_cpu_data = {
var interrupt_cpu_data: Partial<Plotly.PlotData> = {
name: `CPU ${cpu}`,
x: x_time,
y: y_data,
type: 'scatter',
};
if (interrupt_cpu_list.get(run).indexOf(cpu.toString()) == -1) {
interrupt_cpu_data.visible = 'legendonly';
}
interrupt_type_datas.push(interrupt_cpu_data);
}
var title;
Expand Down Expand Up @@ -56,12 +60,13 @@ function getLines(run, container_id, keys, run_data) {
}

function interrupts() {
if (got_interrupt_data) {
if (got_interrupt_data && allRunCPUListUnchanged(interrupt_cpu_list)) {
return;
}
clear_and_create('interrupts');
for (let i = 0; i < interrupts_raw_data['runs'].length; i++) {
let run_name = interrupts_raw_data['runs'][i]['name'];
interrupt_cpu_list.set(run_name, getCPUList(run_name).slice());
let elem_id = `${run_name}-interrupts-per-data`;
let this_run_data = interrupts_raw_data['runs'][i];
getLines(run_name, elem_id, this_run_data['keys'], this_run_data['key_values']);
Expand Down
18 changes: 14 additions & 4 deletions src/html_files/perf_stat.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
let got_perf_stat_data = false;
let perf_cpu_list: Map<string, Array<string>> = new Map<string, Array<string>>();

function getEvents(run, container_id, keys, run_data) {
if (keys.length == 0) {
Expand All @@ -13,7 +14,7 @@ function getEvents(run, container_id, keys, run_data) {
elem.id = `perfstat-${run}-${value}`;
elem.style.float = "none";
addElemToNode(container_id, elem);
emptyOrCallback(keys, false, getEvent, elem, value, run_data);
emptyOrCallback(keys, false, getEvent, elem, value, run_data, run);
}
}
}
Expand All @@ -32,7 +33,7 @@ function addData(perfstat_data, stat, timediff) {
}
})
}
function getEvent(elem, key, run_data) {
function getEvent(elem, key, run_data, run) {
var data = JSON.parse(run_data);
var perfstat_datas = [];
data.data[0].cpus.forEach(function (value, index, arr) {
Expand All @@ -51,6 +52,7 @@ function getEvent(elem, key, run_data) {
var end_datas = [];
perfstat_datas.forEach(function (value, index, arr) {
var cpu_string = "";
let cpu = value.cpu.toString();
if (value.cpu > -1) {
cpu_string = `CPU ${value.cpu}`;
}
Expand All @@ -63,7 +65,14 @@ function getEvent(elem, key, run_data) {
y: value.y_data,
type: 'scatter',
};
end_datas.push(perfstat_line);
if (cpu_string != 'Aggregate' && perf_cpu_list.get(run).indexOf(cpu) == -1) {
perfstat_line.visible = 'legendonly';
}
if (cpu_string == 'Aggregate') {
end_datas.unshift(perfstat_line);
} else {
end_datas.push(perfstat_line);
}
})
let limits = key_limits.get(key);
var layout = {
Expand All @@ -80,13 +89,14 @@ function getEvent(elem, key, run_data) {
}

function perfStat() {
if (got_perf_stat_data) {
if (got_perf_stat_data && allRunCPUListUnchanged(perf_cpu_list)) {
return;
}
clear_and_create('perfstat');
form_graph_limits(perf_stat_raw_data);
for (let i = 0; i < perf_stat_raw_data['runs'].length; i++) {
let run_name = perf_stat_raw_data['runs'][i]['name'];
perf_cpu_list.set(run_name, getCPUList(run_name).slice());
let elem_id = `${run_name}-perfstat-per-data`;
let this_run_data = perf_stat_raw_data['runs'][i];
getEvents(run_name, elem_id, this_run_data['keys'], this_run_data['key_values']);
Expand Down
14 changes: 12 additions & 2 deletions src/html_files/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function canHide(hide, keys, key) {
}
return false;
}
function emptyOrCallback(keys, hide, callback, elem, key, run_data) {
function emptyOrCallback(keys, hide, callback, elem, key, run_data, run="") {
if (canHide(hide, keys, key)) {
return;
}
Expand All @@ -80,7 +80,7 @@ function emptyOrCallback(keys, hide, callback, elem, key, run_data) {
}, 0);
} else {
setTimeout(() => {
callback(elem, key, run_data[key]);
callback(elem, key, run_data[key], run);
}, 0);
}
}
Expand Down Expand Up @@ -159,3 +159,13 @@ function split_keys(check_runs, check_common_keys) {
}
}
}

function allRunCPUListUnchanged(cpu_list) {
for (let i = 0; i < runs_raw.length; i++) {
let run_name = runs_raw[i];
if (!isCPUListUnchanged(cpu_list.get(run_name), run_name)) {
return false;
}
}
return true;
}
Loading

0 comments on commit a1f3590

Please sign in to comment.