提交 b3ef9496 编写于 作者: F fengxuefeng

Add hardware resource visualization

上级 6c82ec3e
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1920px" height="1080px" viewBox="0 0 1920 1080" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
<title>矩形</title>
<desc>Created with Sketch.</desc>
<defs>
<polygon id="path-1" points="0 0 1920 0 1920 1080 0 1080"></polygon>
<pattern id="pattern-3" width="16.4850993" height="16.4850993" x="-16.4850993" y="-16.4850993" patternUnits="userSpaceOnUse">
<use xlink:href="#image-4" transform="scale(0.34343957,0.34343957)"></use>
</pattern>
<image id="image-4" width="48" height="48" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAEGWlDQ1BrQ0dDb2xvclNwYWNlR2VuZXJpY1JHQgAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia219thzg25abkRE/BpDc3pqvphHvRFys2weqvp+krbWKIX7nhDbzLOItiM8358pTwdirqpPFnMF2xLc1WvLyOwTAibpbmvHHcvttU57y5+XqNZrLe3lE/Pq8eUj2fXKfOe3pfOjzhJYtB/yll5SDFcSDiH+hRkH25+L+sdxKEAMZahrlSX8ukqMOWy/jXW2m6M9LDBc31B9LFuv6gVKg/0Szi3KAr1kGq1GMjU/aLbnq6/lRxc4XfJ98hTargX++DbMJBSiYMIe9Ck1YAxFkKEAG3xbYaKmDDgYyFK0UGYpfoWYXG+fAPPI6tJnNwb7ClP7IyF+D+bjOtCpkhz6CFrIa/I6sFtNl8auFXGMTP34sNwI/JhkgEtmDz14ySfaRcTIBInmKPE32kxyyE2Tv+thKbEVePDfW/byMM1Kmm0XdObS7oGD/MypMXFPXrCwOtoYjyyn7BV29/MZfsVzpLDdRtuIZnbpXzvlf+ev8MvYr/Gqk4H/kV/G3csdazLuyTMPsbFhzd1UabQbjFvDRmcWJxR3zcfHkVw9GfpbJmeev9F08WW8uDkaslwX6avlWGU6NRKz0g/SHtCy9J30o/ca9zX3Kfc19zn3BXQKRO8ud477hLnAfc1/G9mrzGlrfexZ5GLdn6ZZrrEohI2wVHhZywjbhUWEy8icMCGNCUdiBlq3r+xafL549HQ5jH+an+1y+LlYBifuxAvRN/lVVVOlwlCkdVm9NOL5BE4wkQ2SMlDZU97hX86EilU/lUmkQUztTE6mx1EEPh7OmdqBtAvv8HdWpbrJS6tJj3n0CWdM6busNzRV3S9KTYhqvNiqWmuroiKgYhshMjmhTh9ptWhsF7970j/SbMrsPE1suR5z7DMC+P/Hs+y7ijrQAlhyAgccjbhjPygfeBTjzhNqy28EdkUh8C+DU9+z2v/oyeH791OncxHOs5y2AtTc7nb/f73TWPkD/qwBnjX8BoJ98VQNcC+8AAAFFSURBVGgF7djbDYMwDAXQBjEMYqyqY1WMxTppLiJIQIA8ariWkp8IPuweO60am67r7MstY8wwjuPH7dMz3uUua63p+/7r9rePIRW/9QmQzCV9ub0YgSIgzhxvQkjFb1EZBAdEKolkfJTqtnb7bv/zOJm58moRE0AzYgFoRawAGhE7gDZEEKAJcQjQgjgFaEBcAtgRUQBmRDSAFZEEYEQkA9gQWQAmRDaABVEEYEAUAx5H4EaGOyw+SMl66mbXzNOD4k6gCPNUY/CFwF1YOn5zRxJJRINqaUbUuZA/79sd3wm3xIdbdS60rXzo2XVCbO60/HxKJgFKKv4CkEziuyKBWAE0InYAbYggQBPiEKAFcQrQgLgEsCOiAMyIaAArIgnAiEgGsCGyAEyIbAALogjAgCgGPI7AX9w6F3JtqHMhnMWLFSrSD9jOnakVHpZYAAAAAElFTkSuQmCC"></image>
</defs>
<g id="硬件资源可视-特性文档" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<g id="矩形">
<use fill="#F2F5FC" xlink:href="#path-1"></use>
<use fill-opacity="0.2" fill="url(#pattern-3)" style="mix-blend-mode: multiply;" xlink:href="#path-1"></use>
</g>
</g>
</svg>
\ No newline at end of file
...@@ -32,6 +32,7 @@ limitations under the License. ...@@ -32,6 +32,7 @@ limitations under the License.
<el-menu-item index="/model-traceback">{{$t("summaryManage.modelTraceback")}}</el-menu-item> <el-menu-item index="/model-traceback">{{$t("summaryManage.modelTraceback")}}</el-menu-item>
<el-menu-item index="/data-traceback">{{$t("summaryManage.dataTraceback")}}</el-menu-item> <el-menu-item index="/data-traceback">{{$t("summaryManage.dataTraceback")}}</el-menu-item>
<el-menu-item index="/compare-plate">{{$t("summaryManage.comparePlate")}}</el-menu-item> <el-menu-item index="/compare-plate">{{$t("summaryManage.comparePlate")}}</el-menu-item>
<el-menu-item index="/hardware-visual">{{$t("summaryManage.hardwareVisual")}}</el-menu-item>
</el-menu> </el-menu>
</div> </div>
</div> </div>
...@@ -42,28 +43,61 @@ limitations under the License. ...@@ -42,28 +43,61 @@ limitations under the License.
|| this.$route.path.indexOf('/histogram') > 0 || this.$route.path.indexOf('/histogram') > 0
|| this.$route.path.indexOf('/tensor') > 0 || this.$route.path.indexOf('/tensor') > 0
|| this.$route.path.indexOf('/training-dashboard') > 0 || this.$route.path.indexOf('/training-dashboard') > 0
|| !this.$route.path.indexOf('/compare-plate')"> || !this.$route.path.indexOf('/compare-plate')
<!-- automatic refresh switch --> || !this.$route.path.indexOf('/hardware-visual')">
<el-switch v-model="isTimeReload" <div class="reload-training"
:active-text="$t('header.timeReload')+$t('symbols.leftbracket')+ v-if="this.$route.path.indexOf('/scalar') > 0
timeReloadValue+$t('header.timeSecond')+$t('symbols.rightbracket')" || this.$route.path.indexOf('/image') > 0
@change="timeReload"></el-switch> || this.$route.path.indexOf('/histogram') > 0
<i class="el-icon-edit" || this.$route.path.indexOf('/training-dashboard') > 0
:title="$t('header.timeReloadScope')" || !this.$route.path.indexOf('/compare-plate')">
v-if="isTimeReload && !isShowInp" <!-- automatic refresh switch -->
@click="editTime"></i> <el-switch v-model="isTimeReload"
:active-text="$t('header.timeReload')+$t('symbols.leftbracket')+
timeReloadValue+$t('header.timeSecond')+$t('symbols.rightbracket')"
@change="timeReload"></el-switch>
<i class="el-icon-edit"
:title="$t('header.timeReloadScope')"
v-if="isTimeReload && !isShowInp"
@click="editTime"></i>
<el-input v-if="isTimeReload && isShowInp" <el-input v-if="isTimeReload && isShowInp"
v-model="newReloadValue" v-model="newReloadValue"
type="text" type="text"
@input="timeValueChange"></el-input> @input="timeValueChange"></el-input>
<i class="el-icon-check"
v-if="isTimeReload && isShowInp"
@click="saveTimeValue"></i>
<i class="el-icon-close"
v-if="isTimeReload && isShowInp"
@click="cancelTimeValue"></i>
</div>
<div class="reload-hardware"
v-if="!this.$route.path.indexOf('/hardware-visual')">
<!-- automatic refresh switch -->
<el-switch v-model="isHardwareTimeReload"
:active-text="$t('header.timeReload')+$t('symbols.leftbracket')+
hardwareTimeReloadValue+$t('header.timeSecond')+$t('symbols.rightbracket')"
@change="hardwareTimeReload"></el-switch>
<i class="el-icon-edit"
:title="$t('header.timeReloadScope')"
v-if="isHardwareTimeReload && !isShowHardwareInp"
@click="editHardwareTime"></i>
<el-input v-if="isHardwareTimeReload && isShowHardwareInp"
v-model="newHardwareReloadValue"
type="text"
@input="hardwareTimeValueChange"></el-input>
<i class="el-icon-check"
v-if="isHardwareTimeReload && isShowHardwareInp"
@click="saveHardwareTimeValue"></i>
<i class="el-icon-close"
v-if="isHardwareTimeReload && isShowHardwareInp"
@click="cancelHardwareTimeValue"></i>
</div>
<i class="el-icon-check"
v-if="isTimeReload && isShowInp"
@click="saveTimeValue"></i>
<i class="el-icon-close"
v-if="isTimeReload && isShowInp"
@click="cancleTimeValue"></i>
<!-- manual refresh switch --> <!-- manual refresh switch -->
<img src="../assets/images/reload.png" <img src="../assets/images/reload.png"
...@@ -90,6 +124,9 @@ export default { ...@@ -90,6 +124,9 @@ export default {
isShowInp: false, isShowInp: false,
timeReloadValue: this.$store.state.timeReloadValue, timeReloadValue: this.$store.state.timeReloadValue,
newReloadValue: this.$store.state.timeReloadValue, newReloadValue: this.$store.state.timeReloadValue,
isShowHardwareInp: false,
hardwareTimeReloadValue: this.$store.state.hardwareTimeReloadValue,
newHardwareReloadValue: this.$store.state.hardwareTimeReloadValue,
}; };
}, },
computed: { computed: {
...@@ -104,6 +141,13 @@ export default { ...@@ -104,6 +141,13 @@ export default {
}, },
set(val) {}, set(val) {},
}, },
// set and get isHardwareTimeReload status
isHardwareTimeReload: {
get() {
return this.$store.state.isHardwareTimeReload;
},
set(val) {},
},
}, },
watch: {}, watch: {},
mounted() {}, mounted() {},
...@@ -117,7 +161,7 @@ export default { ...@@ -117,7 +161,7 @@ export default {
relPath(path) { relPath(path) {
this.$router.push(path); this.$router.push(path);
}, },
// save isTimeReload status // training reload setting
timeReload(val) { timeReload(val) {
localStorage.isTimeReload = val; localStorage.isTimeReload = val;
this.$store.commit('setIsTimeReload', val); this.$store.commit('setIsTimeReload', val);
...@@ -128,7 +172,7 @@ export default { ...@@ -128,7 +172,7 @@ export default {
}, },
saveTimeValue() { saveTimeValue() {
if (this.newReloadValue) { if (this.newReloadValue >= 0) {
this.newReloadValue = this.newReloadValue =
this.newReloadValue < 3 this.newReloadValue < 3
? 3 ? 3
...@@ -141,10 +185,10 @@ export default { ...@@ -141,10 +185,10 @@ export default {
this.$store.commit('setTimeReloadValue', timeValue); this.$store.commit('setTimeReloadValue', timeValue);
this.isShowInp = false; this.isShowInp = false;
} else { } else {
this.cancleTimeValue(); this.cancelTimeValue();
} }
}, },
cancleTimeValue() { cancelTimeValue() {
this.isShowInp = false; this.isShowInp = false;
this.newReloadValue = this.timeReloadValue; this.newReloadValue = this.timeReloadValue;
}, },
...@@ -155,6 +199,45 @@ export default { ...@@ -155,6 +199,45 @@ export default {
.replace(/\./g, ''); .replace(/\./g, '');
this.newReloadValue = Number(this.newReloadValue); this.newReloadValue = Number(this.newReloadValue);
}, },
// hardware reload setting
hardwareTimeReload(val) {
localStorage.isHardwareTimeReload = val;
this.$store.commit('setIsHardwareTimeReload', val);
},
editHardwareTime() {
this.isShowHardwareInp = true;
},
saveHardwareTimeValue() {
if (this.newHardwareReloadValue >= 0) {
this.newHardwareReloadValue =
this.newHardwareReloadValue < 3
? 3
: this.newHardwareReloadValue > 300
? 300
: this.newHardwareReloadValue;
const timeValue = this.newHardwareReloadValue;
this.hardwareTimeReloadValue = timeValue;
localStorage.hardwareTimeReloadValue = timeValue;
this.$store.commit('setHardwareTimeReloadValue', timeValue);
this.isShowHardwareInp = false;
} else {
this.cancelHardwareTimeValue();
}
},
cancelHardwareTimeValue() {
this.isShowHardwareInp = false;
this.newHardwareReloadValue = this.timeReloadValue;
},
hardwareTimeValueChange() {
this.newHardwareReloadValue = this.newHardwareReloadValue
.toString()
.replace(/[^\.\d]/g, '')
.replace(/\./g, '');
this.newHardwareReloadValue = Number(this.newHardwareReloadValue);
},
// get active menu item // get active menu item
getActive() { getActive() {
const str = this.$route.path.split('/'); const str = this.$route.path.split('/');
...@@ -217,6 +300,13 @@ export default { ...@@ -217,6 +300,13 @@ export default {
.el-icon-close { .el-icon-close {
color: #f56c6c; color: #f56c6c;
} }
.el-input {
width: 45px;
input {
padding: 0;
text-align: center;
}
}
} }
// reload style // reload style
...@@ -232,16 +322,10 @@ export default { ...@@ -232,16 +322,10 @@ export default {
transform: rotate(1turn); transform: rotate(1turn);
} }
} }
.cl-header-right .el-input {
width: 45px;
input {
padding: 0;
text-align: center;
}
}
.cl-header-nav { .cl-header-nav {
margin-left: 50px; margin-left: 50px;
flex: 1; flex: 1.5;
.el-menu { .el-menu {
border-bottom: none; border-bottom: none;
......
...@@ -45,7 +45,8 @@ ...@@ -45,7 +45,8 @@
"modelTraceback": "模型溯源", "modelTraceback": "模型溯源",
"dataTraceback": "数据溯源", "dataTraceback": "数据溯源",
"comparePlate": "对比看板", "comparePlate": "对比看板",
"disableProfilerTip": "无profiler日志,无法查看性能分析" "disableProfilerTip": "无profiler日志,无法查看性能分析",
"hardwareVisual": "硬件资源"
}, },
"modelTraceback": { "modelTraceback": {
"summaryPath": "训练日志路径", "summaryPath": "训练日志路径",
...@@ -367,7 +368,7 @@ ...@@ -367,7 +368,7 @@
"FPMessage": "前向起始算子:", "FPMessage": "前向起始算子:",
"BPMessage": "反向终止算子:", "BPMessage": "反向终止算子:",
"approximateTime": "总时长 ≈ ", "approximateTime": "总时长 ≈ ",
"stepInputTip": "请输入step值(1~{max}的正整数)", "stepInputTip": "请输入step值(1~{max}的正整数,值为空时展示平均值)",
"inputError": "输入参数异常,请输入一个1~{max}的正整数", "inputError": "输入参数异常,请输入一个1~{max}的正整数",
"defaultTip": "默认展示平均值", "defaultTip": "默认展示平均值",
"downloadTimeline": "下载", "downloadTimeline": "下载",
...@@ -383,7 +384,35 @@ ...@@ -383,7 +384,35 @@
"title3": "如何使用时间线:", "title3": "如何使用时间线:",
"content31": "您可以通过时间线信息分析流切分方法是否合理、迭代间隙和拖尾时间是否过长等;", "content31": "您可以通过时间线信息分析流切分方法是否合理、迭代间隙和拖尾时间是否过长等;",
"content32": "也可以具体定位到某个算子,查看分析它的执行时间。" "content32": "也可以具体定位到某个算子,查看分析它的执行时间。"
} },
"unit": "ms/次"
},
"hardwareVisual": {
"processor": "昇腾AI处理器",
"ram": "内存",
"selectedCpu": "CPU-选中:",
"allCpu": "CPU-总计:",
"chipNameTip": "芯片名称",
"deviceIdTip": "芯片号",
"availableTip": "芯片是否空闲",
"healthTip": "芯片健康指数(正常、一般警告、重要警告、紧急警告)",
"ipTip": "芯片IP地址",
"aicoreTip": "芯片利用率",
"hbmTip": "芯片已用HBM内存",
"powerTip": "芯片功耗",
"temperatureTip": "芯片温度",
"cpuUserTip": "运行于用户态的时间百分比",
"cpuSystemTip": "运行于内核态的时间百分比",
"cpuIdleTip": "处于空闲状态的时间百分比",
"cpuNiceTip": "运行低优先级进程的时间百分比",
"cpuIowaitTip": "等待IO的时间百分比",
"cpuIrqTip": "处理硬中断的时间百分比",
"cpuSoftirqTip": "处理软中断的时间百分比",
"cpuStealTip": "被其他虚拟机抢夺的时间百分比",
"cpuGuestTip": "运行虚拟机的时间百分比",
"cpuGuestniceTip": "运行低优先级虚拟机的时间百分比",
"cpuInterruptTip": "处理硬中断的时间百分比",
"cpuDpcTip": "远程调用的时间百分比"
}, },
"components": { "components": {
"summaryTitle": "训练选择", "summaryTitle": "训练选择",
...@@ -423,4 +452,4 @@ ...@@ -423,4 +452,4 @@
"50545013": "请求的数据过大,无法返回,请使用其他维度重试。", "50545013": "请求的数据过大,无法返回,请使用其他维度重试。",
"50545014": "查询的张量数据已被新数据替换,请刷新。" "50545014": "查询的张量数据已被新数据替换,请刷新。"
} }
} }
\ No newline at end of file
...@@ -102,5 +102,9 @@ export default new Router({ ...@@ -102,5 +102,9 @@ export default new Router({
}, },
], ],
}, },
{
path: '/hardware-visual',
component: () => import('./views/train-manage/hardware-visual.vue'),
},
], ],
}); });
...@@ -288,4 +288,13 @@ export default { ...@@ -288,4 +288,13 @@ export default {
}, },
}); });
}, },
getMetricsData() {
return axios({
method: 'get',
url: 'v1/mindinsight/resource_monitor/current/metrics',
headers: {
ignoreError: true,
},
});
},
}; };
...@@ -30,6 +30,12 @@ export default new Vuex.Store({ ...@@ -30,6 +30,12 @@ export default new Vuex.Store({
timeReloadValue: localStorage.timeReloadValue timeReloadValue: localStorage.timeReloadValue
? localStorage.timeReloadValue ? localStorage.timeReloadValue
: 3, : 3,
// Scheduled hardware reload flag
isHardwareTimeReload: localStorage.isHardwareTimeReload === 'false' ? false : true,
// hardware reload time
hardwareTimeReloadValue: localStorage.hardwareTimeReloadValue
? localStorage.hardwareTimeReloadValue
: 3,
// multiSelevtGroup component count // multiSelevtGroup component count
multiSelectedGroupCount: 0, multiSelectedGroupCount: 0,
tableId: 0, tableId: 0,
...@@ -75,6 +81,13 @@ export default new Vuex.Store({ ...@@ -75,6 +81,13 @@ export default new Vuex.Store({
setTimeReloadValue: (state, val) => { setTimeReloadValue: (state, val) => {
state.timeReloadValue = val; state.timeReloadValue = val;
}, },
// set isHardwareTimeReload
setIsHardwareTimeReload: (state, val) => {
state.isHardwareTimeReload = val;
},
setHardwareTimeReloadValue: (state, val) => {
state.hardwareTimeReloadValue = val;
},
multiSelectedGroupComponentNum(state) { multiSelectedGroupComponentNum(state) {
state.multiSelectedGroupCount++; state.multiSelectedGroupCount++;
}, },
......
<!--
Copyright 2020 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.
-->
<template>
<div class="cl-hardware-visual">
<div class="cl-hardware-content"
v-if="!(chipTableData.length === 0 && cpuList.length===0)">
<div class="cl-hardware-top">
<div class="cl-hardware-left">
<div class="cl-sub-title">
{{$t('hardwareVisual.processor')}}
</div>
<div class="cl-chip-wrap">
<el-table v-if="!(chipTableData.length === 0)"
:data="chipTableData"
width="100%"
height="100%">
<el-table-column prop="chip_name"
width="120">
<template slot="header">
Name
<el-tooltip class="item"
effect="light"
:content="$t('hardwareVisual.chipNameTip')"
placement="top-start">
<i class="el-icon-info"></i>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="device_id"
width="80">
<template slot="header">
NPU
<el-tooltip class="item"
effect="light"
:content="$t('hardwareVisual.deviceIdTip')"
placement="top-start">
<i class="el-icon-info"></i>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="available"
width="110">
<template slot="header">
Available
<el-tooltip class="item"
effect="light"
:content="$t('hardwareVisual.availableTip')"
placement="top-start">
<i class="el-icon-info"></i>
</el-tooltip>
</template>
<template slot-scope="scope">
<i class="el-icon-success"
v-if="scope.row.available"></i>
<i class="el-icon-error"
v-else></i>
</template>
</el-table-column>
<el-table-column prop="health"
width="80">
<template slot="header">
Health
<el-tooltip class="item"
effect="light"
:content="$t('hardwareVisual.healthTip')"
placement="top-start">
<i class="el-icon-info"></i>
</el-tooltip>
</template>
<template slot-scope="scope">
<i class="el-icon-success"
v-if="scope.row.health===0"></i>
<i class="el-icon-warning normal"
v-if="scope.row.health===1"></i>
<i class="el-icon-warning important"
v-if="scope.row.health===2"></i>
<i class="el-icon-warning emergency"
v-if="scope.row.health===3"></i>
<i class="el-icon-remove"
v-if="scope.row.health=== 0xffffffff"></i>
</template>
</el-table-column>
<el-table-column prop="ip_address"
width="130">
<template slot="header">
IP Address
<el-tooltip class="item"
effect="light"
:content="$t('hardwareVisual.ipTip')"
placement="top-start">
<i class="el-icon-info"></i>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="aicore">
<template slot="header">
AI Core(%)
<el-tooltip class="item"
effect="light"
:content="$t('hardwareVisual.aicoreTip')"
placement="top-start">
<i class="el-icon-info"></i>
</el-tooltip>
</template>
<template slot-scope="scope">
<el-progress :percentage="scope.row.aicore_rate"
:format="format"></el-progress>
</template>
</el-table-column>
<el-table-column prop="hbm_usage"
min-width="100">
<template slot="header">
HBM-Usage(MB)
<el-tooltip class="item"
effect="light"
:content="$t('hardwareVisual.hbmTip')"
placement="top-start">
<i class="el-icon-info"></i>
</el-tooltip>
</template>
<template slot-scope="scope">
<div class="hbs-wrap">
<el-progress :percentage="
parseInt(scope.row.hbm_info.memory_usage/scope.row.hbm_info.memory_size*100)"
:format="formatHbm(scope.row.hbm_info)"></el-progress>
</div>
</template>
</el-table-column>
<el-table-column prop="power">
<template slot="header">
Power(W)
<el-tooltip class="item"
effect="light"
:content="$t('hardwareVisual.powerTip')"
placement="top-start">
<i class="el-icon-info"></i>
</el-tooltip>
</template>
<template slot-scope="scope">
<div class="power-wrap">
<div class="power"
:style="{width:`${scope.row.power/powerMax*100}%`}">{{scope.row.power}}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="temp"
width="150">
<template slot="header">
Temp(℃)
<el-tooltip class="item"
effect="light"
:content="$t('hardwareVisual.temperatureTip')"
placement="top-start">
<i class="el-icon-info"></i>
</el-tooltip>
</template>
<template slot-scope="scope">
<div class="temp-wrap">
<div class="circle"
:class="{zero:!scope.row.temperature}"></div>
<div class="process-wrap">
<div class="process-cover"
:style="{width:scope.row.temperature/temperatureMax*100+'%'}"></div>
</div>
<span>{{scope.row.temperature}}</span>
</div>
</template>
</el-table-column>
</el-table>
<div class="image-noData"
v-if="chipTableData.length === 0">
<div>
<img :src="require('@/assets/images/nodata.png')"
alt="" />
</div>
<p>{{$t("public.noData")}}</p>
</div>
</div>
</div>
</div>
<div class="cl-hardware-bottom">
<div class="cl-hardware-left">
<div class="cl-sub-title">
CPU
</div>
<div class="cl-cpu-wrap">
<div class="cpu-items">
<div class="cpu-item"
v-for="(item,key) in cpuList"
:key="key">
<div class="cpu"
:class="{selected:item.selected}"
:style="{backgroundColor:item.idle!==undefined?
`rgba(250,152,65,${(100-item.idle).toFixed(2)/100}`:'#ccc'}"
:title="item.idle!==undefined?`Core ${key}`:''"
@click="viewPerCpuInfo(key)">
{{ item.idle!==undefined?(100-item.idle).toFixed(2):'' }}
</div>
</div>
</div>
<div class="cpu-detail">
<div class="all-cpu-info">
<span>{{$t('hardwareVisual.allCpu')}}</span>
<div class="info-item"
v-for="(item,index) in overallCpuInfo"
:key="index">
<el-tooltip class="item"
effect="light"
:content="item.tips"
placement="top-start">
<span>
<span class="label">{{item.label}}</span>
<span class="value">{{`${item.value}%`}}</span>
</span>
</el-tooltip>
</div>
</div>
<div class="selected-cpu-info"
v-if="selectedCpuIndex!==null">
<span>{{$t('hardwareVisual.selectedCpu')}}</span>
<div class="info-item"
v-for="(item,index) in selectedCpuInfo"
:key="index">
<el-tooltip class="item"
effect="light"
:content="item.tips"
placement="top-start">
<span>
<span class="label">{{item.label}}</span>
<span class="value">{{`${item.value}%`}}</span>
</span>
</el-tooltip>
</div>
</div>
</div>
</div>
</div>
<div class="cl-hardware-right">
<div class="cl-sub-title ram">
{{$t('hardwareVisual.ram')}}
</div>
<div class="cl-ram-wrap">
<div class="virtual-wrap">
<div id="virtual"></div>
</div>
</div>
</div>
</div>
</div>
<div class="image-noData"
v-if="chipTableData.length === 0 && cpuList.length===0">
<div>
<img :src="require('@/assets/images/nodata.png')"
alt="" />
</div>
<p>{{$t("public.noData")}}</p>
</div>
</div>
</template>
<script>
import echarts from 'echarts';
import RequestService from '../../services/request-service';
export default {
data() {
return {
chipTableData: [],
powerMax: null,
temperatureMax: null,
virtualChart: {
id: 'virtual',
chartDom: null,
data: [],
legend: [],
totalValue: null,
},
defaultCpuNum: 96,
cpuList: [],
overallCpuInfo: [],
selectedCpuInfo: [],
selectedCpuIndex: null,
pieColorArr: ['#5e7ce0', '#a6dd82'],
autoUpdateTimer: null, // Automatic refresh timer
isReloading: false, // Manually refresh
};
},
computed: {
/**
* Global refresh switch
* @return {Boolean}
*/
isReload() {
return this.$store.state.isReload;
},
/**
* Automatic hardware refresh switch
* @return {Boolean}
*/
isHardwareTimeReload() {
return this.$store.state.isHardwareTimeReload;
},
/**
* Automatic hardware refresh value
* @return {Boolean}
*/
hardwareTimeReloadValue() {
return this.$store.state.hardwareTimeReloadValue;
},
},
watch: {
/**
* Global refresh switch Listener
* @param {Boolean} newVal Value After Change
* @param {Boolean} oldVal Value Before Change
*/
isReload(newVal, oldVal) {
if (newVal) {
this.isReloading = true;
if (this.isHardwareTimeReload) {
this.autoUpdateSamples();
}
this.init();
}
},
/**
* Automatic refresh switch Listener
* @param {Boolean} newVal Value After Change
* @param {Boolean} oldVal Value Before Change
*/
isHardwareTimeReload(newVal, oldVal) {
if (newVal) {
this.autoUpdateSamples();
} else {
this.stopUpdateSamples();
}
},
/**
* The refresh time is changed.
*/
hardwareTimeReloadValue() {
this.autoUpdateSamples();
},
},
destroyed() {
// Disable the automatic refresh function
if (this.autoUpdateTimer) {
clearInterval(this.autoUpdateTimer);
this.autoUpdateTimer = null;
}
// Stop Refreshing
if (this.isReloading) {
this.$store.commit('setIsReload', false);
this.isReloading = false;
}
},
mounted() {
document.title = this.$t('summaryManage.hardwareVisual') + '-MindInsight';
// Automatic refresh
if (this.isHardwareTimeReload) {
this.autoUpdateSamples();
}
this.init();
},
methods: {
/**
* Initialization data
*/
init() {
RequestService.getMetricsData().then(
(res) => {
if (this.isReloading) {
this.$store.commit('setIsReload', false);
this.isReloading = false;
}
if (res && res.data) {
this.chipTableData = res.data.npu || [];
this.powerMax =
Math.max(...this.chipTableData.map((val) => val.power)) * 1.2;
this.temperatureMax =
Math.max(...this.chipTableData.map((val) => val.temperature)) * 1.2;
// 1.2 In order to Demonstrated effect
if (res.data.momory && res.data.momory.virtual) {
this.dealChartData(this.virtualChart, res.data.momory.virtual);
this.setOption(this.virtualChart);
}
if (res.data.cpu) {
const overall = res.data.cpu.overall || {};
this.overallCpuInfo = Object.keys(overall).map((val) => {
return {
label: val,
value: overall[val],
};
});
this.addtips(this.overallCpuInfo);
this.cpuList = (res.data.cpu.percpu || []).map((val) => {
return {...val, selected: false};
});
while (this.cpuList.length < this.defaultCpuNum) {
this.cpuList.push({});
}
if (this.selectedCpuIndex !== null) {
this.viewPerCpuInfo(this.selectedCpuIndex);
} else {
this.selectedCpuInfo = [];
}
}
}
},
(err) => {
this.chipTableData = [];
this.cpuList = [];
if (this.isReloading) {
this.$store.commit('setIsReload', false);
this.isReloading = false;
}
},
);
},
/**
* add tips
* @param {Array} arr cpu Info
*/
addtips(arr) {
arr.forEach((val) => {
switch (val.label) {
case 'user':
val.tips = this.$t('hardwareVisual.cpuUserTip');
break;
case 'nice':
val.tips = this.$t('hardwareVisual.cpuNiceTip');
break;
case 'system':
val.tips = this.$t('hardwareVisual.cpuSystemTip');
break;
case 'idle':
val.tips = this.$t('hardwareVisual.cpuIdleTip');
break;
case 'iowait':
val.tips = this.$t('hardwareVisual.cpuIowaitTip');
break;
case 'irq':
val.tips = this.$t('hardwareVisual.cpuIrqTip');
break;
case 'softirq':
val.tips = this.$t('hardwareVisual.cpuSoftirqTip');
break;
case 'steal':
val.tips = this.$t('hardwareVisual.cpuStealTip');
break;
case 'guest':
val.tips = this.$t('hardwareVisual.cpuGuestTip');
break;
case 'guest_nice':
val.tips = this.$t('hardwareVisual.cpuGuestniceTip');
break;
case 'interrupt':
val.tips = this.$t('hardwareVisual.cpuInterruptTip');
break;
case 'dpc':
val.tips = this.$t('hardwareVisual.cpuDpcTip');
break;
}
});
},
/**
* View the information of each cpu
* @param {Number} index index
*/
viewPerCpuInfo(index) {
this.cpuList.forEach((val, key) => {
if (val.idle !== undefined) {
if (index === key) {
this.selectedCpuIndex = key;
val.selected = true;
this.selectedCpuInfo = Object.keys(this.cpuList[index]).map((val) => {
return {
label: val,
value: this.cpuList[index][val],
};
});
this.selectedCpuInfo.pop();
} else {
if (this.cpuList[index].idle !== undefined) {
val.selected = false;
}
}
}
});
this.addtips(this.selectedCpuInfo);
},
/**
* Handling pie chart data
* @param {Object} chart chart obejct
* @param {Object} data chart data
*/
dealChartData(chart, data) {
const virtual = Object.keys(data);
chart.legend = virtual.reverse();
chart.data = virtual.map((val) => {
return {
value: data[val],
name: val,
};
});
chart.totalValue = 0;
chart.data.forEach((val) => {
chart.totalValue += val.value;
});
},
/**
* Data unit conversion
* @param {Number} n chart obejct
* @param {Boolean} type format type
* @return {String}
*/
bytesHuman(n, type) {
const symbols = 'KMG'
.split('')
.map((symbol, index) => [symbol, 1 << ((index + 1) * 10)]);
for (const [symbol, prefix] of symbols.reverse()) {
if (n >= prefix) {
if (type) {
return `${n}(${(n / prefix).toFixed(1)}${symbol})`;
} else {
return `${(n / prefix).toFixed(1)}${symbol}`;
}
}
}
return `${n}`;
},
format(percentage, item) {
return `${percentage}`;
},
formatHbm(hbmInfo) {
return function() {
return `${hbmInfo.memory_usage}/${hbmInfo.memory_size}`;
};
},
/**
* Enable automatic hardware refresh
*/
autoUpdateSamples() {
if (this.autoUpdateTimer) {
clearInterval(this.autoUpdateTimer);
this.autoUpdateTimer = null;
}
this.autoUpdateTimer = setInterval(() => {
this.$store.commit('clearToken');
this.init();
}, this.hardwareTimeReloadValue * 1000);
},
/**
* Disable automatic refresh
*/
stopUpdateSamples() {
if (this.autoUpdateTimer) {
clearInterval(this.autoUpdateTimer);
this.autoUpdateTimer = null;
}
},
setOption(chart) {
const option = {
tooltip: {
trigger: 'item',
formatter: (params) => {
return `${params.name}<br>
${params.marker}${this.bytesHuman(params.value, true)}`;
},
confine: true,
},
legend: {
orient: 'vertical',
left: '50%',
top: '35%',
icon: 'circle',
data: chart.legend,
formatter: (params) => {
let legendStr = '';
for (let i = 0; i < chart.data.length; i++) {
if (chart.data[i].name === params) {
const name = chart.data[i].name;
legendStr = `{a|${this.bytesHuman(
chart.data[i].value,
true,
)}}\n{b|${name}}`;
}
}
return legendStr;
},
textStyle: {
rich: {
a: {
fontSize: 14,
},
b: {
color: '#aeb2bf',
},
},
},
},
series: [
{
name: '',
center: ['25%', '50%'],
type: 'pie',
radius: ['40%', '60%'],
avoidLabelOverlap: false,
label: {
show: true,
formatter: () => {
return `{a|${this.bytesHuman(chart.totalValue)}}{b|All}`;
},
position: 'center',
textStyle: {
rich: {
a: {
fontSize: 20,
color: '#000',
},
b: {
color: '#aeb2bf',
},
},
},
},
labelLine: {
show: false,
},
data: chart.data,
itemStyle: {
normal: {
color: (params) => {
return this.pieColorArr[params.dataIndex];
},
},
},
},
],
};
this.$nextTick(() => {
const cpuDom = document.getElementById(chart.id);
if (cpuDom) {
chart.chartDom = echarts.init(cpuDom, null);
chart.chartDom.setOption(option, true);
chart.chartDom.resize();
}
});
},
},
};
</script>
<style lang="scss" >
.cl-hardware-visual {
height: 100%;
background-color: #fff;
.cl-hardware-content {
height: 100%;
padding: 0 24px 24px 24px;
.cl-hardware-top {
height: calc(100% - 372px);
padding-top: 16px;
& > div {
width: 100%;
.el-table_1_column_1,
.el-table_1_column_2,
.el-table_1_column_3,
.el-table_1_column_4,
.el-table_1_column_5 {
text-align: center;
}
.el-table::before {
height: 0px;
}
}
}
.cl-hardware-bottom {
height: 360px;
.cl-hardware-left {
width: calc(100% - 466px);
margin-right: 16px;
}
.cl-hardware-right {
width: 450px;
}
}
& > div {
height: calc(50% - 8px);
margin-bottom: 16px;
& > div {
float: left;
height: 100%;
border: 1px solid #eee;
border-radius: 4px;
padding: 16px;
.cl-sub-title {
font-weight: bold;
font-size: 16px;
margin-bottom: 15px;
}
.cl-sub-title.ram {
margin-bottom: 10px;
}
.cl-chip-wrap {
height: calc(100% - 36px);
overflow: auto;
.el-icon-success:before {
color: #57d7ac;
}
.el-icon-error:before {
color: #e37783;
}
.el-icon-warning.normal:before {
color: #6f81e4;
}
.el-icon-warning.important:before {
color: #faa048;
}
.el-icon-warning.emergency:before {
color: #f06281;
}
.el-icon-remove:before {
color: #8b8e95;
}
.temp-wrap {
.circle {
width: 10px;
height: 10px;
border-radius: 5px;
background: #ffaa00;
display: inline-block;
position: absolute;
left: 1px;
top: 50%;
margin-top: -4px;
}
.circle.zero {
background: #e6ebf5;
}
.process-wrap {
background: #e6ebf5;
width: calc(100% - 50px);
height: 6px;
display: inline-block;
border-top-right-radius: 50px;
border-bottom-right-radius: 50px;
margin-right: 5px;
.process-cover {
height: 6px;
border-top-right-radius: 50px;
border-bottom-right-radius: 50px;
background: #ff5100;
background-image: linear-gradient(to right, #ffaa00, #ff5100);
}
}
}
.hbs-wrap {
.el-progress-bar {
padding-right: 140px;
margin-right: -145px;
}
}
.power {
background: #e5f6f6;
padding-left: 10px;
}
}
.cl-ram-wrap {
height: calc(100% - 36px);
.virtual-wrap {
height: 100%;
overflow: auto;
#virtual {
height: 100%;
overflow: hidden;
}
}
}
.cl-disk-wrap {
height: calc(100% - 36px);
overflow: auto;
}
.cl-cpu-wrap {
height: 201px;
.cpu-items {
height: 100%;
overflow: auto;
background: url('../../assets/images/cpu-bg.svg') repeat;
padding: 3px 0 0 3px;
.cpu-item {
float: left;
width: calc(6.25% - 3px);
height: 30px;
text-align: center;
background: #fff;
margin-right: 3px;
margin-bottom: 3px;
cursor: pointer;
.cpu {
height: 100%;
line-height: 30px;
}
.cpu.selected {
line-height: 30px;
outline: 3px solid #00a5a7;
}
}
}
.cpu-detail {
& > div {
margin-top: 10px;
& > span {
margin-right: 5px;
color: #b2b4bb;
}
& > div {
display: inline-block;
padding: 0 7px;
border-right: 1px solid #ccc;
&:last-child {
border-right: none;
}
.label {
margin-right: 5px;
cursor: pointer;
}
.value {
display: inline-block;
width: 40px;
text-align: right;
cursor: pointer;
}
}
}
}
}
}
}
.el-table thead tr {
background: #f0f3fa;
}
.el-table th.is-leaf .cell {
border-left: 1px solid #d4d9e6;
}
.el-table th.is-leaf:first-child .cell {
border-left: none;
}
.el-pagination {
margin: 7px 0;
float: right;
}
}
.el-table th {
height: 32px;
}
.image-noData {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
p {
font-size: 16px;
padding-top: 10px;
}
}
.el-icon-info:before {
color: #6c7280;
}
}
</style>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册