Browse Source

ui support cpu usage

tags/v1.2.0-rc1
ph 4 years ago
parent
commit
1f7981db3b
8 changed files with 1157 additions and 22 deletions
  1. +24
    -0
      mindinsight/ui/src/locales/en-us.json
  2. +24
    -0
      mindinsight/ui/src/locales/zh-cn.json
  3. +654
    -0
      mindinsight/ui/src/mixins/cpu-utilization.vue
  4. +215
    -0
      mindinsight/ui/src/mixins/init-dot.vue
  5. +8
    -0
      mindinsight/ui/src/services/request-service.js
  6. +2
    -1
      mindinsight/ui/src/views/profiling-gpu/profiling.vue
  7. +228
    -20
      mindinsight/ui/src/views/profiling/data-process.vue
  8. +2
    -1
      mindinsight/ui/src/views/profiling/profiling.vue

+ 24
- 0
mindinsight/ui/src/locales/en-us.json View File

@@ -453,6 +453,30 @@
"unit": "ms/time",
"gpuunit": "us/time",
"chartTitle": "Average Time Consumption Ranking",
"userUtilization": "User Usage",
"sysUtilization": "System Usage",
"ioUtilization": "I/O Usage",
"idleUtilization": "Idle Usage",
"avgUserUtilization": "Average User Usage:",
"avgSysUtilization": "Average System Usage:",
"avgIOUtilization": "Average I/O Usage:",
"avgIdleUtilization": "Average Idle Usage:",
"avgWaitingProcess": "Average Number of Waiting Threads:",
"avgSwitchCount": "Average Number of Context Switches:",
"logicCores": "Number of Logical CPU Cores:",
"allOperators": "All Operators",
"currentOperator": "Current Operator",
"cpuStepInputTip": "Enter a positive integer ranging from 1 to {max}. The value of Start Step must be less than or equal to that of End Step.",
"startStep": "Start Step:",
"endStep": "End Step:",
"filterStep": "Filter",
"resetStep": "Reset",
"cpuUtilization": "CPU Usage",
"cpuStepTip": "The step value is a positive integer ranging from 1 to {max}.",
"structuralCpuUtil": "CPU Usage of the Entire System",
"processCpuUtil": "Process CPU Usage",
"operatorCpuUtil": "Operator CPU Usage",
"utilizationTitle": "Usage(%)",
"memory": {
"memoryDetailLink": "Memory Usage Information",
"overView": "Memory Allocation OverView",


+ 24
- 0
mindinsight/ui/src/locales/zh-cn.json View File

@@ -452,6 +452,30 @@
"unit": "ms/次",
"gpuunit": "us/次",
"chartTitle": "平均耗时排名",
"userUtilization": "用户利用率",
"sysUtilization": "系统利用率",
"ioUtilization": "IO利用率",
"idleUtilization": "空闲利用率",
"avgUserUtilization": "平均用户利用率:",
"avgSysUtilization": "平均系统利用率:",
"avgIOUtilization": "平均IO利用率:",
"avgIdleUtilization": "平均空闲利用率:",
"avgWaitingProcess": "平均等待线程数:",
"avgSwitchCount": "平均上下文切换次数:",
"logicCores": "CPU逻辑核数:",
"allOperators": "所有算子",
"currentOperator": "当前算子",
"cpuStepInputTip": "请输入step范围 (1~{max}的正整数,且起始step小于等于结束step)",
"startStep": "起始step:",
"endStep": "结束step:",
"filterStep": "筛选",
"resetStep": "重置",
"cpuUtilization": "CPU利用率",
"cpuStepTip": "Step的范围为1~{max}的正整数",
"structuralCpuUtil": "整机CPU利用率",
"processCpuUtil": "进程CPU利用率",
"operatorCpuUtil": "算子CPU利用率",
"utilizationTitle": "利用率(%)",
"memory": {
"memoryDetailLink": "内存使用情况",
"overView": "内存分配概览",


+ 654
- 0
mindinsight/ui/src/mixins/cpu-utilization.vue View File

@@ -0,0 +1,654 @@
<!--
Copyright 2021 Huawei Technologies Co., Ltd.All Rights Reserved.

Licensed 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.
-->
<script>
import echarts from 'echarts';
import {select, selectAll} from 'd3';
const d3 = {select, selectAll};
import 'd3-graphviz';
import RequestService from '@/services/request-service';
import initDot from '../mixins/init-dot';
export default {
data() {
return {
chartGrid: {
grid: {
left: 40,
top: 40,
right: 70,
bottom: 60,
},
}, // The grid setting of chart
chartDataZoom: {
dataZoom: [
{
start: 0,
end: 100,
bottom: 0,
},
{
start: 0,
end: 100,
type: 'inside',
bottom: 0,
},
],
}, // The data zoom setting of chart
deviceCpuChart: {
id: 'deviceCpuChart',
chartDom: null,
option: {
tooltip: {
trigger: 'axis',
formatter: null,
confine: true,
},
legend: {
right: 70,
top: 8,
data: [],
},
xAxis: {
name: '',
data: [],
},
yAxis: {
name: this.$t('profiling.utilizationTitle'),
type: 'value',
},
series: [],
},
logicCores: 0,
cpuAvgUser: 0,
cpuAvgSystem: 0,
cpuAvgIO: 0,
cpuAvgFree: 0,
cpuAvgProcess: 0,
cpuAvgSwitch: 0,
}, // The total data of device cpu info
processCpuChart: {
id: 'processCpuChart',
chartDom: null,
option: {
tooltip: {
trigger: 'axis',
formatter: null,
confine: true,
},
legend: {
right: 70,
top: 8,
data: [],
},
xAxis: {
name: '',
data: [],
},
yAxis: {
name: this.$t('profiling.utilizationTitle'),
type: 'value',
},
series: [],
},
cpuAvgUser: 0,
cpuAvgSystem: 0,
}, // The total data of process cpu info
operatorCpuChart: {
id: 'operatorCpuChart',
chartDom: null,
option: {
tooltip: {
trigger: 'axis',
formatter: null,
confine: true,
},
legend: {
right: 70,
top: 8,
data: [],
},
xAxis: {
name: '',
data: [],
},
yAxis: {
name: this.$t('profiling.utilizationTitle'),
type: 'value',
},
series: [],
},
opList: {},
cpuAvgTotalUser: 0,
cpuAvgTotalSystem: 0,
cpuAvgOpUser: 0,
cpuAvgOpSystem: 0,
processNumber: 0,
}, // The total data of operator cpu info
cpuInfo: {
initOver: false,
noData: true,
startStep: {
step: '',
showStep: '',
},
endStep: {
step: '',
showStep: '',
},
stepArray: [],
step: 0,
deviceId: null,
stepTip: this.$t('profiling.cpuStepTip'),
cpuStepInputTip: '',
cpuInfoStr: {
user_utilization: this.$t('profiling.userUtilization'),
sys_utilization: this.$t('profiling.sysUtilization'),
io_utilization: this.$t('profiling.ioUtilization'),
idle_utilization: this.$t('profiling.idleUtilization'),
},
samplingInterval: 0,
}, // The common data of page
strokeBeforeClick: undefined, // The stroke info of original dom
prevNode: undefined, // The previous clicked node
prevGraph: undefined, // The previous clicked graph
operatorCPUList: [], // The list of operator cpu info
selIndex: null, // The index of selected graph node, to get right operator cpu info
};
},
created() {
Object.assign(this.deviceCpuChart.option, this.chartGrid, this.chartDataZoom);
Object.assign(this.processCpuChart.option, this.chartGrid, this.chartDataZoom);
Object.assign(this.operatorCpuChart.option, this.chartGrid, this.chartDataZoom);
},
methods: {
/**
* The logic of query and render graph info of cpu
* @return {Promise}
*/
initCPUGraph() {
return new Promise((resolve) => {
const params = {
params: {
train_id: this.trainId,
profile: this.dir,
},
body: {
device_id: this.currentCard,
},
};
RequestService.queryOpQueue(params)
.then((res) => {
if (res.data && res.data.object) {
// Keep data order right
const newData = this.ensureDataOrder(res.data.object);
// Process data
const graphData = this.processGraphData(newData);
// Transform to dot
const dot = initDot.objectToDot(graphData);
// Render dot
this.initOperatorGraph(dot).then(() => {
const nodes = d3.selectAll('g.node');
// Add click event
this.addGraphEvent(nodes);
// Add cursor style
this.updateGraphStyle(nodes);
resolve(true);
});
}
});
});
},
/**
* The logic of make sure the index of data is same to id
* @param {Array} dataArr
* @return {Array}
*/
ensureDataOrder(dataArr) {
const newArr = [];
dataArr.forEach((data) => {
newArr[data[0]] = data;
this.operatorCPUList[data[0]] = `${data[1]}_${data[0]}`;
});
this.selIndex = newArr.findIndex((data) => {
return data.parent_id === null || newArr[data.parent_id] === undefined;
});
return newArr;
},
/**
* The logic of process operator data into 'initDot' format
* @param {Array} dataArr
* @return {Object}
*/
processGraphData(dataArr) {
const graphData = {
total: {
compound: 'true',
rankdir: 'LR',
id: 'operatorGraph',
bgcolor: 'transparent',
},
node: {
style: 'filled',
fontsize: '10px',
},
edge: {
fontsize: '6px',
style: 'filled',
fillcolor: '#e6ebf5',
color: '#e6ebf5',
},
nodes: [],
};
const nodeStyle = {
shape: 'Mrecord',
fillcolor: '#c6e2ff',
color: '#c6e2ff',
};
if (Array.isArray(dataArr)) {
dataArr.forEach((data) => {
const text = `${data[1]}_${data[0]}`;
const node = Object.assign({
name: text,
id: text,
label: text,
}, nodeStyle);
// If has the parent node
if (typeof data[6] === 'number') {
const next = data[6];
node.next = [
{
name: `${dataArr[next][1]}_${dataArr[next][0]}`,
},
];
}
graphData.nodes.push(node);
});
}
return graphData;
},
/**
* Init operator graph
* @param {String} dot
* @return {Object}
*/
initOperatorGraph(dot) {
return new Promise((resolve) => {
d3.select('#operator-graph')
.graphviz()
.height('100%')
.width('100%')
.fit(true)
.dot(dot)
.render(() => {
resolve(true);
});
});
},
/**
* Add operator graph Event
* @param {Array} nodes
*/
addGraphEvent(nodes) {
if (nodes) {
nodes.on(
'click',
(target, index, nodeslist) => {
this.clickEvent(nodeslist[index]);
},
false,
);
}
},
/**
* Update operator graph style
* @param {Array} nodes
*/
updateGraphStyle(nodes) {
nodes.attr('cursor', 'pointer');
},
/**
* The logic of operator graph click event
* @param {Object} node
*/
clickEvent(node) {
if (this.prevGraph) {
this.prevGraph.setAttribute('stroke', this.strokeBeforeClick);
}
if (this.prevNode === Node) {
return;
} else {
this.prevNode = node;
}
const children = node.children;
for (let i = 0; i < children.length; i++) {
if (children[i].nodeName === 'path') {
this.prevGraph = children[i];
this.strokeBeforeClick = children[i].getAttribute('stroke');
children[i].setAttribute('stroke', '#409eff');
}
}
const strArr = node.id.split('_');
this.selIndex = strArr[strArr.length - 1];
this.updateOperatorCpuChart(this.selIndex);
},

/**
* Query average rate info
* @param {Boolean} isFilter wherter filter step
* @param {Boolean} isInitGraph wherter init graph
*/
queryCpuInfo(isFilter, isInitGraph) {
this.cpuInfo.deviceId = this.currentCard;
const params = {
params: {
profile: this.dir,
train_id: this.trainId,
},
body: {
device_id: this.currentCard,
filter_condition: {},
},
};
if (isFilter) {
params.body.filter_condition.start_step = this.cpuInfo.startStep.step;
params.body.filter_condition.end_step = this.cpuInfo.endStep.step;
}
this.cpuInfo.initOver = false;
RequestService.getCpuUtilization(params).then(
(res) => {
this.cpuInfo.initOver = true;
if (res && res.data) {
this.cpuInfo.noData = !res.data.step_total_num;
this.cpuInfo.step = res.data.step_total_num;
this.cpuInfo.stepArray = res.data.step_info;
this.cpuInfo.stepTip = this.$t('profiling.cpuStepTip', {max: `${this.cpuInfo.step}`});
this.cpuInfo.cpuStepInputTip = this.$t('profiling.cpuStepInputTip', {max: `${this.cpuInfo.step}`});
this.samplingInterval = res.data.sampling_interval;
this.deviceCpuChart.logicCores = res.data.cpu_processor_num;
const deviceInfo = res.data.device_info;
const processInfo = res.data.process_info;
const opInfo = res.data.op_info;
if (deviceInfo && processInfo && opInfo && this.samplingInterval) {
this.initDeviceCpu(deviceInfo);
this.initProcessCpu(processInfo);
if (isInitGraph) {
this.$nextTick(() => {
this.initCPUGraph().then(() => {
this.initOperatorCpu(opInfo, true);
});
});
} else {
this.$nextTick(() => {
this.initOperatorCpu(opInfo, false);
});
}
} else {
this.clearCpuChart();
}
} else {
this.clearCpuChart();
this.cpuInfo.noData = true;
}
},
() => {
this.clearCpuChart();
this.cpuInfo.initOver = true;
this.cpuInfo.noData = true;
},
);
},
/**
* clear cpu chart and graph
*/
clearCpuChart() {
if (this.deviceCpuChart.chartDom) {
this.deviceCpuChart.chartDom.clear();
}
if (this.processCpuChart.chartDom) {
this.processCpuChart.chartDom.clear();
}
if (this.operatorCpuChart.chartDom) {
this.operatorCpuChart.chartDom.clear();
}
},
/**
* filter step to view cpu info
*/
viewStepFilter() {
if (
/^[0-9]*[1-9][0-9]*$/.test(this.cpuInfo.startStep.showStep) &&
/^[0-9]*[1-9][0-9]*$/.test(this.cpuInfo.endStep.showStep) &&
this.cpuInfo.startStep.showStep <= this.cpuInfo.endStep.showStep &&
this.cpuInfo.endStep.showStep <= this.cpuInfo.step
) {
this.cpuInfo.startStep.step = this.cpuInfo.startStep.showStep;
this.cpuInfo.endStep.step = this.cpuInfo.endStep.showStep;
this.queryCpuInfo(true, false);
} else if (this.cpuInfo.endStep.showStep === '' &&
/^[0-9]*[1-9][0-9]*$/.test(this.cpuInfo.startStep.showStep) &&
this.cpuInfo.startStep.showStep <= this.cpuInfo.step) {
this.cpuInfo.startStep.step = this.cpuInfo.startStep.showStep;
this.cpuInfo.endStep.step = this.cpuInfo.step;
this.cpuInfo.endStep.showStep = this.cpuInfo.step;
this.queryCpuInfo(true, false);
} else if (this.cpuInfo.startStep.showStep === '' &&
/^[0-9]*[1-9][0-9]*$/.test(this.cpuInfo.endStep.showStep) &&
this.cpuInfo.endStep.showStep <= this.cpuInfo.step) {
this.cpuInfo.startStep.step = 1;
this.cpuInfo.startStep.showStep = 1;
this.cpuInfo.endStep.step = this.cpuInfo.endStep.showStep;
this.queryCpuInfo(true, false);
} else if (this.cpuInfo.startStep.showStep === '' &&
this.cpuInfo.endStep.showStep === '') {
this.resetStepFilter();
} else {
this.cpuInfo.startStep.showStep = this.cpuInfo.startStep.step;
this.cpuInfo.endStep.showStep = this.cpuInfo.endStep.step;
this.$message.error(this.cpuInfo.cpuStepInputTip);
}
},
/**
* reset to view all cpu info
*/
resetStepFilter() {
this.cpuInfo.startStep.showStep = '';
this.cpuInfo.startStep.step = '';
this.cpuInfo.endStep.showStep = '';
this.cpuInfo.endStep.step = '';
this.queryCpuInfo(false, false);
},
/**
* format chart tip
* @param {Object} params
* @param {Array} stepArray
* @return {String}
*/
formateCpuChartTip(params, stepArray) {
const data = params;
let str = '';
if (data && data.length) {
const colorArray = [
'#c23531',
'#2f4554',
'#61a0a8',
'#d48265',
'#d48265',
];
const index = data[0].dataIndex;
str += `step: ${stepArray[index]}`;
data.forEach((item, index) => {
str += `<br><span class="cpu-chart-tip" style="background-color:${colorArray[index]};"></span>` +
`${item.seriesName}: ${item.data}`;
});
str += `</div>`;
}
return str;
},

/**
* Init device cpu chart
* @param {Object} deviceInfo
*/
initDeviceCpu(deviceInfo) {
const series = [];
const legend = [];
Object.keys(this.cpuInfo.cpuInfoStr).forEach((val) => {
const info = deviceInfo[val];
if (info && info.metrics) {
const item = {
type: 'line',
name: this.cpuInfo.cpuInfoStr[val],
data: info.metrics,
showSymbol: false,
};
series.push(item);
legend.push(item.name);
}
});
this.deviceCpuChart.cpuAvgUser = deviceInfo.user_utilization.avg_value;
this.deviceCpuChart.cpuAvgSystem = deviceInfo.sys_utilization.avg_value;
this.deviceCpuChart.cpuAvgIO = deviceInfo.io_utilization.avg_value;
this.deviceCpuChart.cpuAvgFree = deviceInfo.idle_utilization.avg_value;
this.deviceCpuChart.cpuAvgProcess = deviceInfo.runable_processes.avg_value;
this.deviceCpuChart.cpuAvgSwitch = deviceInfo.context_switch_count.avg_value;
this.deviceCpuChart.option.series = series;
this.deviceCpuChart.option.xAxis.name = `${this.$t('profiling.sampleInterval')}\n${
this.$t('symbols.leftbracket')}${this.samplingInterval}ms${this.$t('symbols.rightbracket')}`;
this.deviceCpuChart.option.xAxis.data = deviceInfo[Object.keys(deviceInfo)[0]].metrics.map(
(val, index) => index + 1,
);
this.deviceCpuChart.option.legend.data = legend;
this.deviceCpuChart.option.tooltip.formatter = (params) => {
return this.formateCpuChartTip(params, this.cpuInfo.stepArray);
};
this.$nextTick(() => {
if (this.$refs.deviceCpuChart) {
this.deviceCpuChart.chartDom = echarts.init(this.$refs.deviceCpuChart);
}
this.deviceCpuChart.chartDom.setOption(this.deviceCpuChart.option);
});
},
/**
* Init process cpu chart
* @param {Object} processInfo
*/
initProcessCpu(processInfo) {
const series = [];
const legend = [];
Object.keys(this.cpuInfo.cpuInfoStr).forEach((val) => {
const info = processInfo[val];
if (info && info.metrics) {
const item = {
type: 'line',
name: this.cpuInfo.cpuInfoStr[val],
data: info.metrics,
showSymbol: false,
};
series.push(item);
legend.push(item.name);
}
});
this.processCpuChart.cpuAvgUser = processInfo.user_utilization.avg_value;
this.processCpuChart.cpuAvgSystem = processInfo.sys_utilization.avg_value;
this.processCpuChart.option.series = series;
this.processCpuChart.option.xAxis.name = `${this.$t('profiling.sampleInterval')}\n${
this.$t('symbols.leftbracket')}${this.samplingInterval}ms${this.$t('symbols.rightbracket')}`;
this.processCpuChart.option.xAxis.data = processInfo[Object.keys(processInfo)[0]].metrics.map(
(val, index) => index + 1,
);
this.processCpuChart.option.legend.data = legend;
this.processCpuChart.option.tooltip.formatter = (params) => {
return this.formateCpuChartTip(params, this.cpuInfo.stepArray);
};
this.$nextTick(() => {
if (this.$refs.processCpuChart) {
this.processCpuChart.chartDom = echarts.init(this.$refs.processCpuChart);
}
this.processCpuChart.chartDom.setOption(this.processCpuChart.option);
});
},

/**
* Init operator cpu chart
* @param {Object} opInfo
* @param {Boolean} isClickNode
*/
initOperatorCpu(opInfo, isClickNode) {
this.operatorCpuChart.opList = {};
opInfo.op_list.forEach((data) => {
this.operatorCpuChart.opList[data.op_id] = data;
});
if (isClickNode) {
// Select first node as default node, and keep it in right style when page mounted
const node = document.getElementById(this.operatorCPUList[this.selIndex]);
if (node) {
this.clickEvent(node);
};
}
this.operatorCpuChart.cpuAvgTotalUser = opInfo.total_op_avg_value.user_utilization;
this.operatorCpuChart.cpuAvgTotalSystem = opInfo.total_op_avg_value.sys_utilization;
this.updateOperatorCpuChart(this.selIndex);
},
/**
* update cpu chart
* @param {String} opId
*/
updateOperatorCpuChart(opId) {
const series = [];
const legend = [];
if (this.operatorCpuChart.opList[opId]) {
const currentOpInfo = this.operatorCpuChart.opList[opId].metrics;
const numWorkers = this.operatorCpuChart.opList[opId].num_workers;
if (currentOpInfo) {
Object.keys(this.cpuInfo.cpuInfoStr).forEach((val) => {
const info = currentOpInfo[val];
if (info && info.metrics) {
const item = {
type: 'line',
name: this.cpuInfo.cpuInfoStr[val],
data: info.metrics,
showSymbol: false,
};
series.push(item);
legend.push(item.name);
}
});
this.operatorCpuChart.cpuAvgOpUser = currentOpInfo.user_utilization.avg_value;
this.operatorCpuChart.cpuAvgOpSystem = currentOpInfo.sys_utilization.avg_value;
this.operatorCpuChart.processNumber = numWorkers;
this.operatorCpuChart.option.series = series;
this.operatorCpuChart.option.xAxis.name = `${this.$t('profiling.sampleInterval')}\n${
this.$t('symbols.leftbracket')}${this.samplingInterval}ms${this.$t('symbols.rightbracket')}`;
this.operatorCpuChart.option.xAxis.data = currentOpInfo[Object.keys(currentOpInfo)[0]].metrics.map(
(val, index) => index + 1,
);
this.operatorCpuChart.option.legend.data = legend;
this.operatorCpuChart.option.tooltip.formatter = (params) => {
return this.formateCpuChartTip(params, this.cpuInfo.stepArray);
};
this.$nextTick(() => {
if (this.$refs.operatorCpuChart) {
if (!this.operatorCpuChart.chartDom) {
this.operatorCpuChart.chartDom = echarts.init(this.$refs.operatorCpuChart);
}
}
this.operatorCpuChart.chartDom.setOption(this.operatorCpuChart.option);
});
}
}
},
},
};
</script>

+ 215
- 0
mindinsight/ui/src/mixins/init-dot.vue View File

@@ -0,0 +1,215 @@
<!--
Copyright 2021 Huawei Technologies Co., Ltd.All Rights Reserved.

Licensed 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.
-->
<script>
export default {
/**
* The logic of transform object to string in 'dot' form
* @param {Object} object
* @return {String}
*/
objectToDot(object) {
const keys = Object.keys(object);
let attrTemp = '';
let nodesTemp = '';
let subTemp = '';
let arrowsTemp = '';
let mixTemp = '';
for (let i = 0; i < keys.length; i++) {
switch (keys[i]) {
case 'nodes':
const tempArray = this.nodesToDot(object[keys[i]]);
nodesTemp = tempArray[0];
arrowsTemp += tempArray[1];
break;
case 'mix':
const mixTempArray = this.mixToDot(object[keys[i]]);
mixTemp = mixTempArray[0];
arrowsTemp += mixTempArray[1];
break;
case 'subgraph':
const subTempArray = this.subToDot(object[keys[i]]);
subTemp = subTempArray[0];
arrowsTemp += subTempArray[1];
break;
default:
attrTemp += this.attrToDot(object[keys[i]], keys[i]);
break;
}
}
const dotTemp = `digraph {${attrTemp}${nodesTemp}${subTemp}${mixTemp}${arrowsTemp}}`;
return dotTemp;
},
/**
* The logic of transform object.subgraph to string in 'dot' form
* @param {Object} subgraph
* @return {String}
*/
subToDot(subgraph) {
let subTemp = '';
let arrowTemp = '';
for (let i = 0; i < subgraph.length; i++) {
subTemp += `subgraph <${subgraph[i].name}>{`;
const keys = Object.keys(subgraph[i]);
for (let j = 0; j < keys.length; j++) {
switch (keys[j]) {
case 'name':
break;
case 'nodes':
const tempArray = this.nodesToDot(subgraph[i].nodes);
subTemp += tempArray[0];
arrowTemp += tempArray[1];
break;
case 'next':
arrowTemp += this.nextToDot(subgraph[i].next, subgraph[i].name);
break;
default:
subTemp += `${keys[j]}="${subgraph[i][keys[j]]}";`;
}
}
subTemp += '};';
}
return [subTemp, arrowTemp];
},
/**
* The logic of transform 'next' of single item in object.nodes to string in 'dot' form
* @param {Object} object
* @param {Object} start
* @return {String}
*/
nextToDot(object, start) {
let arrowTemp = '';
if (Array.isArray(object)) {
for (let i = 0; i < object.length; i++) {
const keys = Object.keys(object[i]);
arrowTemp += `<${start}>-><${object[i].name}>[`;
for (let j = 0; j < keys.length; j++) {
if (keys[j] !== 'name') {
if (object[i][keys[j]][0] === '<') {
arrowTemp += `${keys[j]}=${object[i][keys[j]]};`;
} else {
arrowTemp += `${keys[j]}="${object[i][keys[j]]}";`;
}
}
}
arrowTemp += '];';
}
} else {
const keys = Object.keys(object);
arrowTemp += `<${start}>-><${object.name}>[`;
for (let i = 0; i < keys.length; i++) {
if (keys[i] !== 'name') {
if (object[keys[i]][0] === '<') {
arrowTemp += `${keys[i]}=${object[keys[i]]};`;
} else {
arrowTemp += `${keys[i]}="${object[keys[i]]}";`;
}
}
}
arrowTemp += '];';
}
return arrowTemp;
},
/**
* The logic of transform object.attr to string in 'dot' form
* @param {Object} object
* @param {String} title
* @return {String}
*/
attrToDot(object, title) {
const keys = Object.keys(object);
if (keys.length === 0) {
return;
}
if (title === 'total') {
let nodeTemp = '';
for (let i = 0; i < keys.length; i++) {
nodeTemp += `${keys[i]}="${object[keys[i]]}";`;
}
return nodeTemp;
} else {
let nodeTemp = `${title}[`;
for (let i = 0; i < keys.length; i++) {
nodeTemp += `${keys[i]}="${object[keys[i]]}";`;
}
return `${nodeTemp}];`;
}
},
/**
* The logic of transform object.nodes to string in 'dot' form
* @param {Array} nodes
* @return {Array<string>}
*/
nodesToDot(nodes) {
let nodesTemp = '';
let arrowsTemp = '';
for (let i = 0; i < nodes.length; i++) {
const tempArray = this.nodeToDot(nodes[i]);
nodesTemp += tempArray[0];
arrowsTemp += tempArray[1];
}
return [nodesTemp, arrowsTemp];
},
/**
* The logic of transform object.mix to string in 'dot' form
* @param {Array} mix
* @return {Array<string>}
*/
mixToDot(mix) {
let nodesTemp = '';
let arrowsTemp = '';
for (let i = 0; i < mix.length; i++) {
const keys = Object.keys(mix[i]);
let attrTemp = '';
let nodeTemp = '';
for (let j = 0; j <keys.length; j++) {
if (keys[j] === 'nodes') {
const tempArray = this.nodesToDot(mix[i].nodes);
nodeTemp += tempArray[0];
arrowsTemp += tempArray[1];
} else {
attrTemp += `${keys[j]}="${mix[i][keys[j]]}";`;
}
}
nodesTemp += `{${attrTemp}${nodeTemp}};`;
}
return [nodesTemp, arrowsTemp];
},
/**
* The logic of transform single item in object.nodes to string in 'dot' form
* @param {String} node
* @return {Array<string>}
*/
nodeToDot(node) {
let nodeTemp = `<${node.name}>[`;
let arrowTemp = '';
const keys = Object.keys(node);
for (let i = 0; i < keys.length; i++) {
switch (keys[i]) {
case 'name':
break;
case 'next':
arrowTemp += this.nextToDot(node.next, node.name);
break;
default:
nodeTemp += `${keys[i]}="${node[keys[i]]}";`;
break;
}
}
nodeTemp += '];';
return [nodeTemp, arrowTemp];
},
};
</script>

+ 8
- 0
mindinsight/ui/src/services/request-service.js View File

@@ -461,6 +461,14 @@ export default {
params: params,
});
},
getCpuUtilization(params) {
return axios({
method: 'post',
url: 'v1/mindinsight/profile/minddata-cpu-utilization-summary',
params: params.params,
data: params.body,
});
},
setRecommendWatchPoints(params) {
return axios({
method: 'post',


+ 2
- 1
mindinsight/ui/src/views/profiling-gpu/profiling.vue View File

@@ -1,5 +1,5 @@
<!--
Copyright 2020 Huawei Technologies Co., Ltd.All Rights Reserved.
Copyright 2020-2021 Huawei Technologies Co., Ltd.All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -73,6 +73,7 @@ export default {
'minddata_pipeline-generator_op',
'minddata_pipeline-map_op',
'minddata_pipeline-batch_op',
'minddata_cpu_utilization',
'minddata_warning_op',
],
moreParameter: ['minddata_device_queue', 'minddata_get_next_queue'],


+ 228
- 20
mindinsight/ui/src/views/profiling/data-process.vue View File

@@ -1,5 +1,5 @@
<!--
Copyright 2020 Huawei Technologies Co., Ltd.All Rights Reserved.
Copyright 2020-2021 Huawei Technologies Co., Ltd.All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -302,29 +302,146 @@ limitations under the License.
<p>{{initOver?$t("public.noData"):$t("public.dataLoading")}}</p>
</div>
</el-tab-pane>
<!-- CPU -->
<el-tab-pane :label="$t('profiling.cpuUtilization')"
name="cpuInfo">
<div class="cpu-info"
v-if="!cpuInfo.noData">
<div class="step-filter">
<label>{{cpuInfo.stepTip}}</label>
<label>{{$t('profiling.startStep')}}</label>
<el-input class="step-input"
v-model.number="cpuInfo.startStep.showStep"></el-input>
<label>{{$t('profiling.endStep')}}</label>
<el-input class="step-input"
v-model.number="cpuInfo.endStep.showStep"></el-input>
<el-button @click="viewStepFilter">{{$t('profiling.filterStep')}}</el-button>
<el-button @click="resetStepFilter">{{$t('profiling.resetStep')}}</el-button>
</div>
<div class="cpu-detail">
<div class="cpu-detail-item">
<div class="detail-item-title">{{$t('profiling.structuralCpuUtil')}}</div>
<div class="detail-item">
<div class="cpu-chart"
id="deviceCpuChart"
ref="deviceCpuChart"></div>
<div class="cpu-chart-info">
<div class="info-line">
<span>{{$t('profiling.logicCores')}}</span><span>{{deviceCpuChart.logicCores}}</span>
</div>
<div class="info-line">
<span>{{$t('profiling.avgUserUtilization')}}</span><span>{{deviceCpuChart.cpuAvgUser}}</span>
</div>
<div class="info-line">
<span>{{$t('profiling.avgSysUtilization')}}</span><span>{{deviceCpuChart.cpuAvgSystem}}</span>
</div>
<div class="info-line">
<span>{{$t('profiling.avgIOUtilization')}}</span><span>{{deviceCpuChart.cpuAvgIO}}</span>
</div>
<div class="info-line">
<span>{{$t('profiling.avgIdleUtilization')}}</span><span>{{deviceCpuChart.cpuAvgFree}}</span>
</div>
<div class="info-line">
<span>{{$t('profiling.avgWaitingProcess')}}</span><span>{{deviceCpuChart.cpuAvgProcess}}</span>
</div>
<div class="info-line">
<span>{{$t('profiling.avgSwitchCount')}}</span><span>{{deviceCpuChart.cpuAvgSwitch}}</span>
</div>
</div>
</div>
</div>
<div class="cpu-detail-item cpu-detail-item-top">
<div class="detail-item-title">{{$t('profiling.processCpuUtil')}}</div>
<div class="detail-item">
<div class="cpu-chart"
id="processCpuChart"
ref="processCpuChart">
</div>
<div class="cpu-chart-info">
<div class="info-line">
<span>{{$t('profiling.avgUserUtilization')}}</span><span>{{processCpuChart.cpuAvgUser}}</span>
</div>
<div class="info-line">
<span>{{$t('profiling.avgSysUtilization')}}</span><span>{{processCpuChart.cpuAvgSystem}}</span>
</div>
</div>
</div>
</div>
<div class="cpu-detail-item cpu-detail-item-top">
<div class="detail-item-title">{{$t('profiling.operatorCpuUtil')}}</div>
<div class="detail-item-graph"
id="operator-graph"></div>
<div class="detail-item">
<div class="cpu-chart"
id="operatorCpuChart"
ref="operatorCpuChart">
</div>
<div class="cpu-chart-info">
<div class="info-title">
{{$t('profiling.allOperators')}}
</div>
<div class="info-line">
<span>{{$t('profiling.avgUserUtilization')}}</span>
<span>{{operatorCpuChart.cpuAvgTotalUser}}</span>
</div>
<div class="info-line">
<span>{{$t('profiling.avgSysUtilization')}}</span>
<span>{{operatorCpuChart.cpuAvgTotalSystem}}</span>
</div>
<div class="info-title">
{{$t('profiling.currentOperator')}}
</div>
<div class="info-line">
<span>{{$t('profiling.avgUserUtilization')}}</span>
<span>{{operatorCpuChart.cpuAvgOpUser}}</span>
</div>
<div class="info-line">
<span>{{$t('profiling.avgSysUtilization')}}</span>
<span>{{operatorCpuChart.cpuAvgOpSystem}}</span>
</div>
<div class="info-line">
<span>{{$t('profiling.workersNum')}}{{$t('symbols.colon')}}</span>
<span>{{operatorCpuChart.processNumber}}</span>
</div>
</div>
</div>
</div>

</div>
</div>
<div class="image-noData"
v-else>
<div>
<img :src="require('@/assets/images/nodata.png')"
alt="" />
</div>
<p>{{cpuInfo.initOver?$t("public.noData"):$t("public.dataLoading")}}</p>
</div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import echarts from 'echarts';
import RequestService from '../../services/request-service';
import cpuUtilizaton from '../../mixins/cpu-utilization.vue';
import {select, selectAll, zoom} from 'd3';
import {event as currentEvent} from 'd3-selection';
import 'd3-graphviz';
const d3 = {select, selectAll, zoom};
export default {
mixins: [cpuUtilizaton],
props: {},
data() {
return {
dir: '', // Profiler path
currentCard: '', // Purrent card number
connectQueueChart: {
// Ponnect queue chart object
// Connect queue chart object
id: 'connect-queue',
chartDom: null,
data: [],
queueSummary: {},
advise: '',
type: 0,
params: 'device_queue',
noData: true,
@@ -338,7 +455,6 @@ export default {
chartDom: null,
data: [],
queueSummary: {},
advise: '',
type: 0,
params: 'get_next',
noData: true,
@@ -424,10 +540,15 @@ export default {
document.title = `${this.$t('profiling.mindData')}-MindInsight`;
}
if (this.activeName === 'queueInfo') {
this.initOver = false;
this.init();
} else {
} else if (this.activeName === 'pipeLine') {
this.queryAverageRate();
} else {
this.cpuInfo.startStep.showStep = '';
this.cpuInfo.startStep.step = '';
this.cpuInfo.endStep.showStep = '';
this.cpuInfo.endStep.step = '';
this.queryCpuInfo(false, true);
}
}
if (this.activeName === 'queueInfo' && this.$parent.curDashboardInfo.initOver) {
@@ -469,16 +590,19 @@ export default {
* Tabs switch
*/
handleClick() {
if (
this.activeName === 'pipeLine' &&
this.averageRateChart.deviceId !== this.currentCard
) {
if (this.activeName === 'pipeLine' && this.averageRateChart.deviceId !== this.currentCard) {
this.queryAverageRate();
} else if (this.activeName === 'queueInfo' && this.connectQueueChart.deviceId !== this.currentCard) {
this.init();
} else if (
this.activeName === 'queueInfo' &&
this.connectQueueChart.deviceId !== this.currentCard
this.activeName === 'cpuInfo' &&
this.cpuInfo.deviceId !== this.currentCard
) {
this.init();
this.cpuInfo.startStep.showStep = '';
this.cpuInfo.startStep.step = '';
this.cpuInfo.endStep.showStep = '';
this.cpuInfo.endStep.step = '';
this.queryCpuInfo(false, true);
}
this.$nextTick(() => {
this.resizeCallback();
@@ -499,6 +623,9 @@ export default {
'getNextChart',
'averageRateChart',
'queueDeepChart',
'deviceCpuChart',
'processCpuChart',
'operatorCpuChart',
];
chartArr.forEach((val) => {
if (this[val].chartDom) {
@@ -528,12 +655,9 @@ export default {
if (result.summary) {
chart.timeSummary = result.summary.time_summary || {};
Object.keys(chart.timeSummary).forEach((val) => {
chart.timeSummary[val] = parseFloat(
chart.timeSummary[val],
).toFixed(3);
chart.timeSummary[val] = parseFloat(chart.timeSummary[val]).toFixed(3);
});
}
chart.advise = result.advise;
if (result.size > 0) {
chart.noData = false;
this.$nextTick(() => {
@@ -576,7 +700,6 @@ export default {
if (result.summary) {
chart.queueSummary = result.summary.queue_summary || {};
}
chart.advise = result.advise;
if (result.size > 0) {
chart.noData = false;
chart.size = result.size;
@@ -1459,10 +1582,10 @@ export default {
.data-process-wrap .data-process-bottom .queue-step-wrap .chart-content .chart-wrap {
float: left;
width: calc(50% - 12px);
height: calc(100% - 10px);
height: calc(100% - 5px);
border-radius: 4px;
overflow-y: auto;
border: 1px solid #eee;
border: 1px solid #D9D9D9;
}
.data-process-wrap .data-process-bottom .queue-step-wrap .chart-content .chart-wrap:first-child {
margin-right: 20px;
@@ -1607,4 +1730,89 @@ export default {
font-size: 16px;
padding-top: 10px;
}
.data-process-wrap .el-button {
border: 1px solid #00a5a7;
border-radius: 2px;
background-color: white;
color: #00a5a7;
padding: 7px 15px;
}
.data-process-wrap .el-button:hover {
background: rgb(230, 246, 246);
}
.cpu-info {
height: 100%;
display: flex;
flex-direction: column;
}
.cpu-info .step-filter {
min-height: 44px;
}
.cpu-info .step-filter .step-input {
width: 100px;
margin-right: 20px;
}
.cpu-info .step-filter:first-child label {
margin-right: 10px;
}
.cpu-info .cpu-detail {
flex-grow: 1;
overflow-x: hidden;
overflow-y: scroll;
}
.cpu-info .cpu-detail .cpu-detail-item {
padding: 16px;
border: 1px solid #d9d9d9;
border-radius: 4px;
margin-right: 8px;
}
.cpu-info .cpu-detail .cpu-detail-item-top {
margin-top: 16px;
}
.cpu-info .cpu-detail .detail-item-title {
height: 20px;
font-size: 15px;
font-weight: bold;
}
.cpu-info .cpu-detail .detail-item-graph {
height: 120px;
background-color: #f7faff;
margin: 10px 0;
}
.cpu-info .cpu-detail .detail-item {
height: 400px;
display: flex;
}
.cpu-info .cpu-detail .detail-item:last-of-type {
padding-bottom: 0;
border-bottom: none;
}
.cpu-info .cpu-detail .detail-item .cpu-chart {
height: 100%;
flex-grow: 1;
}
.cpu-info .cpu-detail .detail-item .cpu-chart-info {
height: 100%;
width: 300px;
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 20px;
background-color: #f1f1f1;
}
.cpu-info .cpu-detail .detail-item .cpu-chart-info .info-title {
font-size: 14px;
font-weight: bold;
line-height: 30px;
}
.cpu-info .cpu-detail .detail-item .cpu-chart-info .info-line {
line-height: 30px;
}
.cpu-chart-tip {
display: inline-block;
margin-right: 5px;
border-radius: 10px;
width: 10px;
height: 10px;
}
</style>

+ 2
- 1
mindinsight/ui/src/views/profiling/profiling.vue View File

@@ -1,5 +1,5 @@
<!--
Copyright 2020 Huawei Technologies Co., Ltd.All Rights Reserved.
Copyright 2020-2021 Huawei Technologies Co., Ltd.All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -80,6 +80,7 @@ export default {
'minddata_pipeline-generator_op',
'minddata_pipeline-map_op',
'minddata_pipeline-batch_op',
'minddata_cpu_utilization',
'minddata_warning_op',
],
moreParameter: ['minddata_device_queue', 'minddata_get_next_queue'],


Loading…
Cancel
Save