| @@ -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", | |||
| @@ -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": "内存分配概览", | |||
| @@ -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> | |||
| @@ -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> | |||
| @@ -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', | |||
| @@ -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'], | |||
| @@ -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> | |||
| @@ -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'], | |||