mirror of
https://github.com/apache/impala.git
synced 2025-12-19 18:12:08 -05:00
For large JS scripts, code-analysis and linting rules were added to standardize changes for the webUI scripts in IMPALA-13473. This change corrects the scripts to align with these linting and code-analysis rules. Change-Id: I5c8851c3d2f4e95b7eebd61f379361818afca7ea Reviewed-on: http://gerrit.cloudera.org:8080/22950 Tested-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com> Reviewed-by: Riza Suminto <riza.suminto@cloudera.com>
336 lines
13 KiB
JavaScript
336 lines
13 KiB
JavaScript
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
import {profile, diagram_width, resizeVerticalAll, DIAGRAM_MIN_HEIGHT, MARGIN_CHART_END,
|
|
decimals} from "./global_members.js";
|
|
import {name_width, page_additional_height, setTimingDiagramDimensions}
|
|
from "./fragment_diagram.js";
|
|
import {ARRAY_VALUES_START_INDEX, aggregateProfileTimeseries, generateTimesamples,
|
|
clearTimeseriesValues, mapTimeseriesCounters, displayWarning, destroyChart}
|
|
from "./chart_commons.js";
|
|
import {getFragmentMetricsWrapperHeight} from "./fragment_metrics_diagram.js";
|
|
import "./global_dom.js";
|
|
|
|
export let exportedForTest;
|
|
|
|
// #host_utilization_diagram
|
|
export let host_utilization_visible = true;
|
|
export let host_utilization_chart = null;
|
|
export let utilization_metrics_parse_successful = false;
|
|
|
|
const cpu_utilization_counters = [
|
|
["HostCpuIoWaitPercentage", "avg io wait", 0],
|
|
["HostCpuSysPercentage", "avg sys", 0],
|
|
["HostCpuUserPercentage", "avg user", 0]
|
|
];
|
|
const read_write_metrics_counters = [
|
|
["HostDiskReadThroughput", "avg disk read", 0],
|
|
["HostDiskWriteThroughput", "avg disk write", 0],
|
|
["HostNetworkRx", "avg network rx", 0],
|
|
["HostNetworkTx", "avg network tx", 0]
|
|
];
|
|
const UTILIZATION_TIMEAXIS_NAME = "utilization timeticks";
|
|
const MIN_NUM_SAMPLES = 3;
|
|
const DIAGRAM_CONTROLS_HEIGHT = Math.max(28, window.innerHeight * 0.025);
|
|
|
|
let cpu_nodes_usage_aggregate;
|
|
let read_write_metrics_aggregate;
|
|
let sampled_utilization_timeseries;
|
|
let prev_utilization_num_samples = 0;
|
|
const max_samples_utilization = {
|
|
allocated : 64,
|
|
available : 0,
|
|
collected : 0,
|
|
period : null
|
|
};
|
|
let host_utilization_resize_factor = 0.2;
|
|
|
|
const host_utilization_close_btn = document.getElementById("host_utilization_close_btn");
|
|
const host_utilization_resize_bar = document.getElementById(
|
|
"host_utilization_resize_bar");
|
|
|
|
function initializeUtilizationChart() {
|
|
const axis_mappings = {};
|
|
for(let i = 0; i < cpu_utilization_counters.length; ++i) {
|
|
axis_mappings[cpu_utilization_counters[i][1]] = "y";
|
|
}
|
|
for(let i = 0; i < read_write_metrics_counters.length; ++i) {
|
|
axis_mappings[read_write_metrics_counters[i][1]] = "y2";
|
|
}
|
|
const cpu_utilization_counter_group = new Array(cpu_utilization_counters.length);
|
|
for (let i = 0; i < cpu_utilization_counters.length; i++) {
|
|
cpu_utilization_counter_group[i] = cpu_utilization_counters[i][1];
|
|
}
|
|
host_utilization_diagram.style = null;
|
|
host_utilization_chart = c3.generate({
|
|
bindto : "#host_utilization_diagram",
|
|
data : {
|
|
columns : [[UTILIZATION_TIMEAXIS_NAME, 0]],
|
|
axes : axis_mappings,
|
|
type : "area",
|
|
groups : [ cpu_utilization_counter_group ],
|
|
order : "asc",
|
|
x : UTILIZATION_TIMEAXIS_NAME
|
|
}, size : {
|
|
height : getUtilizationHeight(),
|
|
width : diagram_width
|
|
}, padding : {
|
|
left : name_width,
|
|
right : MARGIN_CHART_END
|
|
}, axis : {
|
|
x :
|
|
{
|
|
padding : {
|
|
left : 0,
|
|
right : 0
|
|
},
|
|
tick : {
|
|
format : x => x.toFixed(decimals)
|
|
}
|
|
},
|
|
y :
|
|
{
|
|
tick : {
|
|
format : y => y + "%"
|
|
}
|
|
},
|
|
y2 :
|
|
{
|
|
tick : {
|
|
format : y2 => `${getReadableSize(y2, 1)}/s`
|
|
},
|
|
show : true
|
|
}
|
|
}, legend : {
|
|
show : false
|
|
}, tooltip : {
|
|
format : {
|
|
value : (value, ratio, id, index) => {
|
|
if (cpu_utilization_counter_group.includes(id)) {
|
|
return value.toFixed(decimals) + "%";
|
|
} else {
|
|
return `${getReadableSize(value, decimals)}/s`;
|
|
}
|
|
},
|
|
title : (x, index) => x.toFixed(decimals) + "s"
|
|
}
|
|
}
|
|
});
|
|
host_utilization_chart.load({
|
|
unload : true
|
|
});
|
|
const CHART_WIDTH = diagram_width - MARGIN_CHART_END - name_width;
|
|
prev_utilization_num_samples = 0;
|
|
host_utilization_resize_bar.style.marginLeft = `${name_width + CHART_WIDTH / 4}px`;
|
|
host_utilization_resize_bar.style.width = `${CHART_WIDTH / 2}px`;
|
|
host_utilization_resize_bar.style.marginRight = `${CHART_WIDTH / 4}px`;
|
|
}
|
|
|
|
function dragResizeBar(mousemove_e) {
|
|
if (mousemove_e.target.classList[0] === "c3-event-rect") return;
|
|
const NEXT_HEIGHT = getUtilizationHeight() + (host_utilization_resize_bar.offsetTop -
|
|
mousemove_e.clientY);
|
|
if (NEXT_HEIGHT >= DIAGRAM_MIN_HEIGHT && window.innerHeight - NEXT_HEIGHT
|
|
- DIAGRAM_CONTROLS_HEIGHT >= page_additional_height
|
|
+ getFragmentMetricsWrapperHeight() + DIAGRAM_MIN_HEIGHT) {
|
|
host_utilization_resize_factor = NEXT_HEIGHT / window.innerHeight;
|
|
resizeVerticalAll();
|
|
}
|
|
}
|
|
|
|
function initializeUtilizationMetrics(parent_profile, counters_y1, counters_y2,
|
|
max_samples, timeaxis_name) {
|
|
console.assert(parent_profile.profile_name === "Per Node Profiles");
|
|
// user, sys, io and sampled timeticks
|
|
cpu_nodes_usage_aggregate = new Array(counters_y1.length);
|
|
max_samples.available = 0;
|
|
max_samples.period = 0;
|
|
for (let i = 0; i < counters_y1.length; ++i) {
|
|
cpu_nodes_usage_aggregate[i] = new Array(max_samples.allocated + 2)
|
|
.fill(null);
|
|
cpu_nodes_usage_aggregate[i][0] = counters_y1[i][1];
|
|
cpu_nodes_usage_aggregate[i][1] = 0;
|
|
}
|
|
read_write_metrics_aggregate = new Array(counters_y2.length);
|
|
for (let i = 0; i < counters_y2.length; ++i) {
|
|
read_write_metrics_aggregate[i] = new Array(max_samples.allocated + 2)
|
|
.fill(null);
|
|
read_write_metrics_aggregate[i][0] = counters_y2[i][1];
|
|
read_write_metrics_aggregate[i][1] = 0;
|
|
}
|
|
sampled_utilization_timeseries = new Array(max_samples.allocated + 2)
|
|
.fill(null);
|
|
sampled_utilization_timeseries[0] = timeaxis_name;
|
|
mapTimeseriesCounters(parent_profile.child_profiles[0].time_series_counters,
|
|
counters_y1);
|
|
mapTimeseriesCounters(parent_profile.child_profiles[0].time_series_counters,
|
|
counters_y2);
|
|
return {cpu_nodes_usage_aggregate, read_write_metrics_aggregate,
|
|
sampled_utilization_timeseries};
|
|
}
|
|
|
|
function getUtilizationHeight() {
|
|
return Math.max(DIAGRAM_MIN_HEIGHT, window.innerHeight *
|
|
host_utilization_resize_factor);
|
|
}
|
|
|
|
export function getUtilizationWrapperHeight() {
|
|
return (utilization_metrics_parse_successful && host_utilization_visible) *
|
|
(getUtilizationHeight() + DIAGRAM_CONTROLS_HEIGHT);
|
|
}
|
|
|
|
export function resetUtilizationHeight() {
|
|
host_utilization_resize_factor = 0.2;
|
|
}
|
|
|
|
export function toogleUtilizationVisibility() {
|
|
if (utilization_metrics_parse_successful && host_utilization_visible) {
|
|
host_utilization_wrapper.style.display = "inline-block";
|
|
} else {
|
|
host_utilization_wrapper.style.display = "none";
|
|
}
|
|
}
|
|
|
|
export async function resizeUtilizationChart() {
|
|
if (host_utilization_chart === null) return;
|
|
const CHART_WIDTH = diagram_width - MARGIN_CHART_END - name_width;
|
|
host_utilization_resize_bar.style.marginLeft = `${name_width + CHART_WIDTH / 4}px`;
|
|
host_utilization_resize_bar.style.width = `${CHART_WIDTH / 2}px`;
|
|
host_utilization_resize_bar.style.marginRight = `${CHART_WIDTH / 4}px`;
|
|
host_utilization_chart.resize({
|
|
height : getUtilizationHeight(),
|
|
width : diagram_width
|
|
});
|
|
}
|
|
|
|
export function collectUtilizationFromProfile() {
|
|
// do not collect metrics, in case host utilization is not visible
|
|
if (!host_utilization_visible) {
|
|
utilization_metrics_parse_successful = false;
|
|
return;
|
|
}
|
|
|
|
// try parsing the metrics from JSON, to seek case of errors in expected format
|
|
// and do not render the chart unless attributes are parsed accurately
|
|
try {
|
|
// initialize the collection arrays for subsequent collections
|
|
// arrays are overwritten without further re-allocation to reduce memory usage
|
|
const per_node_profiles = profile.child_profiles[2].child_profiles[0];
|
|
console.assert(per_node_profiles.profile_name === "Per Node Profiles");
|
|
if (host_utilization_chart === null) {
|
|
({cpu_nodes_usage_aggregate, read_write_metrics_aggregate,
|
|
sampled_utilization_timeseries} = initializeUtilizationMetrics(
|
|
per_node_profiles, cpu_utilization_counters, read_write_metrics_counters,
|
|
max_samples_utilization, UTILIZATION_TIMEAXIS_NAME));
|
|
initializeUtilizationChart();
|
|
}
|
|
const impala_server_profile = profile.child_profiles[1];
|
|
console.assert(impala_server_profile.profile_name === "ImpalaServer");
|
|
// Update the plot, only when number of samples in SummaryStatsCounter is updated
|
|
if (impala_server_profile.summary_stats_counters[0].num_of_samples ===
|
|
prev_utilization_num_samples) {
|
|
utilization_metrics_parse_successful = true;
|
|
return;
|
|
}
|
|
|
|
// For each node's profile seperately aggregate into two different units of metrics
|
|
aggregateProfileTimeseries(per_node_profiles, cpu_nodes_usage_aggregate,
|
|
cpu_utilization_counters, max_samples_utilization);
|
|
aggregateProfileTimeseries(per_node_profiles, read_write_metrics_aggregate,
|
|
read_write_metrics_counters, max_samples_utilization);
|
|
|
|
// display warnings in case less samples are available without plotting
|
|
if (max_samples_utilization.available < MIN_NUM_SAMPLES) {
|
|
const UTILIZATION_SAMPLES_MESSAGE = `Warning: Not enough samples for
|
|
CPU utilization plot. Please decrease the value of starting flag
|
|
variable <b><i>periodic_counter_update_period_ms </b></i> to
|
|
increase the granularity of CPU utilization plot.`;
|
|
host_utilization_chart = destroyChart(host_utilization_chart,
|
|
host_utilization_diagram);
|
|
displayWarning(host_utilization_diagram, UTILIZATION_SAMPLES_MESSAGE,
|
|
diagram_width, name_width, MARGIN_CHART_END);
|
|
utilization_metrics_parse_successful = true;
|
|
return;
|
|
}
|
|
// average the aggregated metrics
|
|
cpu_nodes_usage_aggregate.forEach(acc_usage => {
|
|
for (let i = ARRAY_VALUES_START_INDEX; i < max_samples_utilization.available
|
|
+ ARRAY_VALUES_START_INDEX; ++i) {
|
|
acc_usage[i] = acc_usage[i] / (100 * per_node_profiles.child_profiles.length);
|
|
}
|
|
});
|
|
read_write_metrics_aggregate.forEach(acc_usage => {
|
|
for (let i = ARRAY_VALUES_START_INDEX; i < max_samples_utilization.available
|
|
+ ARRAY_VALUES_START_INDEX; ++i) {
|
|
acc_usage[i] = acc_usage[i] / per_node_profiles.child_profiles.length;
|
|
}
|
|
});
|
|
// generate timestamps for utilization values and decide on last timestamp value
|
|
generateTimesamples(sampled_utilization_timeseries, max_samples_utilization, false);
|
|
|
|
// load the utilization values to the chart
|
|
host_utilization_chart.load({
|
|
columns : [...cpu_nodes_usage_aggregate, ...read_write_metrics_aggregate,
|
|
sampled_utilization_timeseries]
|
|
});
|
|
// clear utilization value and timestamp samples arrays
|
|
cpu_nodes_usage_aggregate.forEach(acc_usage => {
|
|
clearTimeseriesValues(acc_usage, max_samples_utilization);
|
|
});
|
|
read_write_metrics_aggregate.forEach(acc_usage => {
|
|
clearTimeseriesValues(acc_usage, max_samples_utilization);
|
|
});
|
|
prev_utilization_num_samples = profile.child_profiles[1].summary_stats_counters[0]
|
|
.num_of_samples;
|
|
utilization_metrics_parse_successful = true;
|
|
} catch (e) {
|
|
utilization_metrics_parse_successful = false;
|
|
host_utilization_chart = destroyChart(host_utilization_chart,
|
|
host_utilization_diagram);
|
|
console.log(e);
|
|
}
|
|
}
|
|
|
|
export function destroyUtilizationChart() {
|
|
host_utilization_chart = destroyChart(host_utilization_chart, host_utilization_diagram);
|
|
toogleUtilizationVisibility();
|
|
setTimingDiagramDimensions();
|
|
}
|
|
|
|
host_utilization_resize_bar.addEventListener("mousedown",
|
|
function dragResizeBarBegin(mousedown_e) {
|
|
host_utilization_resize_bar.removeEventListener("mousedown", dragResizeBarBegin);
|
|
document.body.addEventListener("mousemove", dragResizeBar);
|
|
document.body.addEventListener("mouseup", function dragResrizeBarEnd() {
|
|
document.body.removeEventListener("mouseup", dragResrizeBarEnd);
|
|
document.body.removeEventListener("mousemove", dragResizeBar);
|
|
host_utilization_resize_bar.addEventListener("mousedown", dragResizeBarBegin);
|
|
});
|
|
});
|
|
|
|
host_utilization_close_btn.addEventListener("click", e => {
|
|
host_utilization_visible = false;
|
|
destroyUtilizationChart();
|
|
});
|
|
|
|
host_utilization_close_btn.style.height = `${DIAGRAM_CONTROLS_HEIGHT}px`;
|
|
host_utilization_close_btn.style.fontSize = `${DIAGRAM_CONTROLS_HEIGHT / 2}px`;
|
|
|
|
if (typeof process !== "undefined" && process.env.NODE_ENV === "test") {
|
|
exportedForTest = {initializeUtilizationMetrics};
|
|
}
|