Skip to content

Commit

Permalink
Analytics: Add the front-end for analytics
Browse files Browse the repository at this point in the history
  • Loading branch information
janaknat committed Jan 22, 2025
1 parent dd767ed commit d00be0a
Show file tree
Hide file tree
Showing 7 changed files with 317 additions and 12 deletions.
68 changes: 68 additions & 0 deletions src/html_files/analytics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
class Rule {
name: string;
single_run_rule?: RuleCall;
all_run_rule?: RuleCall;
per_run_rule?: RuleCall;
}

interface RuleCall {
(opts: RuleOpts): Generator<Finding, void, any>;
}

class Rules {
data_type: string;
pretty_name: string;
rules: Array<Rule>;
}

class RuleOpts {
data_type: string;
runs: Array<string>;
key: string;
all_data: any;
base_run: string;
base_run_data: any;
this_run: any;
this_run_data: any;
other_run_data: Map<string, any>;
per_run_data: Array<any>;
}

enum Status {
Good = '✅',
NotGood = '❌',
}

class Analytics {
name: string;
analysis: Array<Finding>;
}

class Finding {
text: string;
status: Status;
recommendation: string;

constructor(text: string = '', status: Status = Status.NotGood, recommendation: string = '') {
this.text = text;
this.status = status;
this.recommendation = recommendation;
}

is_good() {
this.status = Status.Good;
}

is_not_good() {
this.status = Status.NotGood;
}
}

function is_unique(values_array) {
return new Set(values_array).size == 1;
}

let all_rules: Rules[] = [
system_info_rules,
cpu_utilization_rules,
];
44 changes: 44 additions & 0 deletions src/html_files/cpu_utilization.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,50 @@
let got_cpu_util_data = false;
let util_cpu_list: Map<string, CPUList> = new Map<string, CPUList>();

let cpu_utilization_rules = {
data_type: "cpu_utilization",
pretty_name: "CPU Utilization",
rules: [
{
name: "User",
single_run_rule: function* (opts): Generator<Finding, void, any> {
let system_util = get_data_key(opts.data_type, "System");
let total_util: number = opts.base_run_data + system_util.get(opts.base_run);
if (total_util < 50) {
yield new Finding(
`Average CPU Utilization for '${opts.base_run}' is less than 50%.`,
Status.NotGood,
);
}
},
per_run_rule: function* (opts): Generator<Finding, void, any> {
let system_util = get_data_key(opts.data_type, "System");
let init_total_util: number = opts.base_run_data + system_util.get(opts.base_run);
let run_total_util: number = opts.this_run_data + system_util.get(opts.this_run);
let cpu_diff = Math.ceil(Math.abs(run_total_util - init_total_util));
yield new Finding(
`Average CPU Utilization difference between '${opts.base_run}' and '${opts.this_run}' is ${cpu_diff}%.`,
cpu_diff > 10 ? Status.NotGood : Status.Good,
);
},
},
{
name: "Idle",
single_run_rule: function* (opts): Generator<Finding, void, any> {
if (opts.base_run_data > 50) {
yield new Finding(`Average Idle time for '${opts.base_run}' is greater than 50%.`, Status.NotGood);
}
},
per_run_rule: function* (opts): Generator<Finding, void, any> {
let idle_diff = Math.ceil(Math.abs(opts.this_run_data - opts.base_run_data));
yield new Finding(
`Average Idle time difference between '${opts.base_run}' and '${opts.this_run}' is ${idle_diff}%.`,
idle_diff > 10 ? Status.NotGood : Status.Good,
)
},
}
]
}
function getUtilizationType(run, elem, type, run_data) {
var cpu_type_datas = [];
var type_data;
Expand Down
4 changes: 1 addition & 3 deletions src/html_files/flamegraphs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,9 @@ function getFlamegraphInfo(run, container_id) {
addElemToNode(container_id, div);
}

function flamegraphs(set: boolean|string) {
function flamegraphs(set) {
if (set == got_flamegraphs_data) {
return;
} else if (typeof(set) == "boolean") {
set = "flamegraphs";
}
got_flamegraphs_data = set;
clear_and_create('flamegraphs');
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 @@ -11,7 +11,7 @@
<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="system_info" id="default">Report</button>
<button class="tablinks" name="cpu_utilization">CPU Utilization</button>
<button class="tablinks" name="flamegraphs">Flamegraphs</button>
<button class="tablinks" name="top_functions">Top Functions</button>
Expand All @@ -30,6 +30,12 @@
<div class="content">
<div id="header" class="all-runs"></div>
<div id="system_info" class="tabcontent extra">
<div class="extra">
<input type="radio" class="systeminfo-select" name="landingChoice" id="findings" checked>Findings</button>
<input type="radio" class="systeminfo-select" name="landingChoice" id="sutconfig">System Info</button>
<h3 id="landing-text"></h3>
</div>
<div id="findings-data"></div>
<div id="systeminfo-runs"></div>
</div>
<div id="cpu_utilization" class="tabcontent">
Expand Down Expand Up @@ -131,6 +137,7 @@ <h3>Hide N/A and all-zero graphs:</h3>
<script type="text/javascript" src="data/js/aperf_run_stats.js"></script>
<script type="text/javascript" src="data/js/aperf_runlog.js"></script>
<script type="text/javascript" src="data/js/java_profile.js"></script>
<script type="text/javascript" src="data/js/analytics.js"></script>
<script type="text/javascript" src="js/utils.js"></script>
<script type="text/javascript" src="js/plotly.js" charset="utf-8"></script>
<script type="text/javascript" src="js/system_info.js"></script>
Expand All @@ -149,6 +156,7 @@ <h3>Hide N/A and all-zero graphs:</h3>
<script type="text/javascript" src="js/aperf_run_stats.js"></script>
<script type="text/javascript" src="js/aperf_runlog.js"></script>
<script type="text/javascript" src="js/configure.js"></script>
<script type="text/javascript" src="js/analytics.js"></script>
<script type="text/javascript" src="index.js"></script>
</body>
</html>
8 changes: 6 additions & 2 deletions src/html_files/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ DataTypes.set('meminfo', {name: 'meminfo', hideClass: 'meminfoHide', trueId: 'me
DataTypes.set('netstat', {name: 'netstat', hideClass: 'netstatHide', trueId: 'netstat_hide_yes', callback: netStat});
DataTypes.set('interrupts', {name: 'interrupts', hideClass: '', trueId: '', callback: interrupts});
DataTypes.set('cpu_utilization', {name: 'cpuutilization', hideClass: '', trueId: '', callback: cpuUtilization});
DataTypes.set('system_info', {name: 'systeminfo', hideClass: '', trueId: '', callback: systemInfo});
DataTypes.set('system_info', {name: 'systeminfo', hideClass: 'landingChoice', trueId: '', callback: systemInfo});
DataTypes.set('flamegraphs', {name: 'flamegraphs', hideClass: 'flamegraphsSelection', trueId: '', callback: flamegraphs});
DataTypes.set('top_functions', {name: 'topfunctions', hideClass: '', trueId: '', callback: topFunctions});
DataTypes.set('processes', {name: 'processes', hideClass: '', trueId: '', callback: processes});
Expand Down Expand Up @@ -44,7 +44,11 @@ function display_tab(name) {
if (datatype.hideClass != "") {
let queryInput = `input[name="${datatype.hideClass}"]:checked`;
let checkedId = document.querySelector(queryInput).id;
datatype.callback(checkedId == datatype.trueId);
if (datatype.trueId != "") {
datatype.callback(checkedId == datatype.trueId);
} else {
datatype.callback(checkedId);
}
} else {
datatype.callback();
}
Expand Down
167 changes: 161 additions & 6 deletions src/html_files/system_info.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,49 @@
let got_system_info_data = false;
let got_system_info_data = "none";
let system_info_rules = {
data_type: "system_info",
pretty_name: "System Info",
rules: [
{
name: "System Name",
all_run_rule: function* (ruleOpts: RuleOpts): Generator<Finding, void, any> {
let os_version = get_data_key(ruleOpts.data_type, "OS Version").values();
if (is_unique(ruleOpts.per_run_data) && is_unique(os_version)) {
yield new Finding("Same OS across runs.", Status.Good);
} else {
yield new Finding("Different OS and/or version across runs.");
}
},
},
{
name: "Total CPUs",
all_run_rule: function* (ruleOpts: RuleOpts) : Generator<Finding, void, any>{
if (is_unique(ruleOpts.per_run_data)) {
yield new Finding("Total CPUs are the same across runs.", Status.Good);
} else {
yield new Finding("Total CPUs are not the same across runs.");
}
},
},
{
name: "Kernel Version",
all_run_rule: function* (ruleOpts: RuleOpts) : Generator<Finding, void, any>{
let versions = ruleOpts.per_run_data;
for (let i = 0; i < versions.length; i++) {
if (versions[i].split(".").length > 2) {
versions[i] = versions[i].split(".").slice(0, 2).join(".");
} else if (versions[i].split("-").length > 1) {
versions[i] = versions[i].split("-")[0];
}
}
if (is_unique(versions)) {
yield new Finding("Kernel versions (major, minor) are the same across all runs.", Status.Good);
} else {
yield new Finding("Kernel versions (major, minor) are not the same across all runs.");
}
},
}
]
}

function getSystemInfo(run, container_id, run_data) {
var data = JSON.parse(run_data);
Expand All @@ -19,11 +64,101 @@ function getSystemInfo(run, container_id, run_data) {
})
}

function systemInfo() {
if (got_system_info_data) {
return;
function formRuleOpts(data_type, rule) {
let per_run_data = get_data_key(data_type, rule.name);
let base_run_data = per_run_data.get(runs_raw[0]);
let other_run_data = new Map(per_run_data);
other_run_data.delete(runs_raw[0]);
let ruleOpts: RuleOpts = {
data_type: data_type,
runs: runs_raw,
key: rule.name,
all_data: raw_analytics,
this_run: undefined,
this_run_data: undefined,
base_run: runs_raw[0],
base_run_data: base_run_data,
other_run_data: other_run_data,
per_run_data: [...per_run_data.values()],
}
clear_and_create('systeminfo');
return ruleOpts;
}
function analytics() {
let all_analytics = [];
for (var i = 0; i < all_rules.length; i++) {
let rules_group = all_rules[i];
let data_type = rules_group.data_type;
let analytics = {
name: rules_group.pretty_name,
analysis: [],
}
for (var j = 0; j < rules_group.rules.length; j++) {
let rule = rules_group.rules[j];
let opts = formRuleOpts(data_type, rule);
if (runs_raw.length > 1) {
for (const [key, value] of opts.other_run_data) {
opts.this_run = key;
opts.this_run_data = value;
let gen = rule.per_run_rule?.(opts);
if (gen) {
let result = gen.next();
while (!result.done) {
analytics.analysis = analytics.analysis.concat(result.value);
result = gen.next();
}
}
}
let gen = rule.all_run_rule?.(opts);
if (gen) {
let result = gen.next();
while (!result.done) {
analytics.analysis = analytics.analysis.concat(result.value);
result = gen.next();
}
}
}
for (var k = 0; k < runs_raw.length; k++) {
let run = runs_raw[k];
let per_run_data = get_data_key(data_type, rule.name);
let run_data = per_run_data.get(run);
opts.base_run = run;
opts.base_run_data = run_data;
let gen = rule.single_run_rule?.(opts);
if (gen) {
let result = gen.next();
while (!result.done) {
analytics.analysis = analytics.analysis.concat(result.value);
result = gen.next();
}
}
}
}
all_analytics.push(analytics);
}
var table = document.createElement('table');
table.style.border = 'none';
table.id = 'analytics-table';
addElemToNode("findings-data", table);
for (let j = 0; j < all_analytics.length; j++) {
let analytics = all_analytics[j];
for (let k = 0; k < analytics.analysis.length; k++) {
const row = table.insertRow();
if (k == 0) {
const key = row.insertCell();
key.textContent = `${analytics.name}`;
} else {
const key = row.insertCell();
key.textContent = '';
}
const tick = row.insertCell();
tick.textContent = `${analytics.analysis[k].status}`;
const data = row.insertCell();
data.textContent = `${analytics.analysis[k].text}`;
}
}
}

function sutconfig() {
for (let i = 0; i < system_info_raw_data['runs'].length; i++) {
let run_name = system_info_raw_data['runs'][i]['name'];
let elem_id = `${run_name}-systeminfo-per-data`;
Expand All @@ -32,5 +167,25 @@ function systemInfo() {
getSystemInfo(run_name, elem_id, this_run_data['key_values']['values']);
}, 0);
}
got_system_info_data = true;
}

function systemInfo(set) {
if (set == got_system_info_data) {
return;
}
clear_and_create('systeminfo');
clearElements("findings-data");
got_system_info_data = set;
switch (set) {
case 'findings':
document.getElementById('landing-text').innerHTML = 'Findings';
analytics();
break;
case 'sutconfig':
document.getElementById('landing-text').innerHTML = 'System Info';
sutconfig();
break;
default:
return;
}
}
Loading

0 comments on commit d00be0a

Please sign in to comment.