提交 311c5c16 编写于 作者: P ph

UI add GPU profiling module

上级 ee2cbbd1
......@@ -290,7 +290,7 @@ export default {
getActive() {
const str = this.$route.path.split('/');
if (str.length > 2) {
if (str[1] === 'train-manage' || str[1] === 'profiling') {
if (str[1] === 'train-manage' || str[1] === 'profiling' || str[1] === 'profiling-gpu') {
return '/summary-manage';
} else {
return '/' + str[1];
......
......@@ -226,13 +226,15 @@
"currentCard": "Number of cards",
"pie": "Pie",
"bar": "Bar",
"operatorStatistics": "Operator Statistics",
"operatorTypeStatistics": "Operator Type Statistics",
"allOperator": "All",
"classificationOperator": "Type",
"card": " ",
"searchByType": "Enter operator type",
"searchByName": "Enter operator name"
"searchByName": "Enter operator name",
"operatorInfo":"Operator",
"kernelInfo":"Kernel",
"searchByCoreName":"Enter kernel name",
"searchByCoreFullName":"Enter operator full name"
},
"profiling": {
"profilingDashboard": "Profiling Dashboard",
......@@ -389,7 +391,8 @@
"content31": "You can analyze whether the flow tiling policy is proper and whether the step interval and tail time are too long based on the timeline information.",
"content32": "You can also locate an operator and view and analyze its execution time."
},
"unit": "ms/time"
"unit": "ms/time",
"gpuunit": "us/time"
},
"hardwareVisual": {
"processor": "Ascend AI Processor",
......@@ -398,13 +401,13 @@
"allCpu": "Total CPUs:",
"chipNameTip": "Chip name",
"deviceIdTip": "Chip ID",
"availableTip": "Available or not(for reference only)",
"healthTip": "Chip health index",
"availableTip": "Is chip available(for reference only)",
"healthTip": "Chip health status",
"ipTip": "Chip IP address",
"aicoreTip": "Chip usage",
"hbmTip": "Used HBM memory",
"powerTip": "Chip power consumption",
"temperatureTip": "Chip temperature",
"aicoreTip": "Chip utilization",
"hbmTip": "Chip HBM usage",
"powerTip": "Chip real-time power",
"temperatureTip": "Chip real-time temperature",
"cpuUserTip": "Time for running in user mode (%)",
"cpuSystemTip": "Time for running in kernel mode (%)",
"cpuIdleTip": "Idle time (%)",
......@@ -426,7 +429,16 @@
"availableFree": "The chip is available.",
"availableBusy": "The chip is occupied or unavailable.",
"failQueryChip": "An error occurs during chip information query.",
"faliQuery": "Query error"
"faliQuery": "Query error",
"name": "Name",
"npu": "ID",
"available": "Available",
"health": "Health",
"ipAddress": "IP Address",
"aiCore": "AI Core(%)",
"hbmUsage": "HBM Usage(MB)",
"power": "Power(W)",
"temp": "Temp(℃)"
},
"components": {
"summaryTitle": "Training selection",
......
......@@ -224,13 +224,15 @@
"currentCard": "当前卡片",
"pie": "饼图",
"bar": "柱状图",
"operatorStatistics": "算子统计",
"operatorTypeStatistics": "算子类别统计",
"allOperator": "全部",
"classificationOperator": "分类",
"card": "卡",
"searchByType": "请输入算子类型搜索",
"searchByName": "请输入算子名称搜索"
"searchByName": "请输入算子名称搜索",
"searchByCoreName": "请输入内核名称搜索",
"searchByCoreFullName": "请输入算子全名搜索",
"operatorInfo": "算子信息",
"kernelInfo": "内核信息"
},
"profiling": {
"profilingDashboard": "性能看板",
......@@ -388,7 +390,8 @@
"content31": "您可以通过时间线信息分析流切分方法是否合理、迭代间隙和拖尾时间是否过长等;",
"content32": "也可以具体定位到某个算子,查看分析它的执行时间。"
},
"unit": "ms/次"
"unit": "ms/次",
"gpuunit": "us/次"
},
"hardwareVisual": {
"processor": "昇腾AI处理器",
......@@ -396,14 +399,14 @@
"selectedCpu": "CPU-选中:",
"allCpu": "CPU-总计:",
"chipNameTip": "芯片名称",
"deviceIdTip": "芯片号",
"deviceIdTip": "芯片号",
"availableTip": "芯片是否空闲(仅供参考)",
"healthTip": "芯片健康指数",
"ipTip": "芯片IP地址",
"aicoreTip": "芯片利用率",
"aicoreTip": "芯片AI Core利用率",
"hbmTip": "芯片已用HBM内存",
"powerTip": "芯片功耗",
"temperatureTip": "芯片温度",
"powerTip": "芯片实时功率",
"temperatureTip": "芯片实时温度",
"cpuUserTip": "运行于用户态的时间百分比",
"cpuSystemTip": "运行于内核态的时间百分比",
"cpuIdleTip": "处于空闲状态的时间百分比",
......@@ -425,7 +428,16 @@
"availableFree": "芯片空闲",
"availableBusy": "芯片已被占用或不可用",
"failQueryChip": "芯片信息查询有误",
"faliQuery": "查询有误"
"faliQuery": "查询有误",
"name":"名称",
"npu":"编号",
"available":"是否空闲",
"health":"健康指数",
"ipAddress":"IP 地址",
"aiCore":"AI Core利用率(%)",
"hbmUsage":"已用HBM内存(MB)",
"power":"功率(W)",
"temp":"温度(℃)"
},
"components": {
"summaryTitle": "训练选择",
......
......@@ -101,6 +101,22 @@ export default new Router({
},
],
},
{
path: '/profiling-gpu',
component: () => import('./views/profiling-gpu/profiling.vue'),
redirect: '/profiling-gpu/profiling-dashboard',
children: [
{
path: 'profiling-dashboard',
component: () =>
import('./views/profiling-gpu/profiling-dashboard.vue'),
},
{
path: 'operator',
component: () => import('./views/profiling-gpu/operator.vue'),
},
],
},
{
path: '/hardware-visual',
component: () => import('./views/train-manage/hardware-visual.vue'),
......
此差异已折叠。
<!--
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="prof-wrap">
<div class="prof-content">
<div class="prof-content-left"
:class="{collapse:collapse}">
<div class="helper"
v-show="!collapse">
<div class="cur-card">
<label>{{$t('profiling.curCard')}}</label>
<el-select v-model="curDashboardInfo.curCardNum"
class="card-select"
:placeholder="$t('public.select')"
@change="selectValueChange">
<el-option v-for="item in CardNumArr"
:key="item.value"
:label="item.value + $t('operator.card')"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="helper-title">
{{$t("profiling.smartHelper")}}
</div>
<div class="suggested-title">{{$t("profiling.suggestions")}}</div>
<div id="helper-tips"></div>
</div>
<div class="collapse-btn"
:class="{collapse:collapse}"
@click="collapseLeft()">
</div>
</div>
<div class="prof-content-right"
:class="{collapse:collapse}">
<router-view></router-view>
<div class="close"
@click="backToDdashboard"
v-if="$route.path !== '/profiling-gpu/profiling-dashboard'">
<img src="@/assets/images/close-page.png">
</div>
</div>
</div>
</div>
</template>
<script>
import RequestService from '../../services/request-service';
export default {
data() {
return {
tipsArrayList: [
'step_trace-iter_interval',
'minddata_pipeline-general',
'minddata_pipeline-dataset_op',
'minddata_pipeline-generator_op',
'minddata_pipeline-map_op',
'minddata_pipeline-batch_op',
'minddata_warning_op',
],
moreParameter: ['minddata_device_queue', 'minddata_get_next_queue'],
CardNumArr: [], // Card list
collapse: false,
curDashboardInfo: {
// Current Select card info
curCardNum: '',
query: {},
},
};
},
watch: {},
mounted() {
this.$nextTick(() => {
this.init();
});
},
methods: {
/**
* Init function
*/
init() {
if (this.$route.query && this.$route.query.id && this.$route.query.dir) {
this.curDashboardInfo.query.id = this.$route.query.id;
this.curDashboardInfo.query.dir = this.$route.query.dir;
this.curDashboardInfo.query.path = this.$route.query.path;
this.getDeviceList();
} else {
this.curDashboardInfo.query.trainingJobId = '';
this.curDashboardInfo.query.dir = '';
this.curDashboardInfo.query.path = '';
this.$message.error(this.$t('trainingDashboard.invalidId'));
}
},
/**
* When card mumber changed,request data again.
*/
selectValueChange() {
const helperDiv = document.getElementById('helper-tips');
helperDiv.innerHTML = '';
this.getDataOfProfileHelper();
},
/**
* Get card number list
*/
getDeviceList() {
const params = {
profile: this.curDashboardInfo.query.dir,
train_id: this.curDashboardInfo.query.id,
};
RequestService.getProfilerDeviceData(params)
.then(
(res) => {
if (res && res.data && res.data.length) {
const deviceList = res.data;
deviceList.forEach((item) => {
this.CardNumArr.push({
value: item,
});
});
this.curDashboardInfo.curCardNum = this.CardNumArr[0].value;
this.getDataOfProfileHelper();
} else {
this.CardNumArr = [];
this.curDashboardInfo.curCardNum = '';
this.curDashboardInfo.initOver = true;
}
},
(error) => {
this.CardNumArr = [];
this.curDashboardInfo.curCardNum = '';
this.curDashboardInfo.initOver = true;
},
)
.catch(() => {
this.curDashboardInfo.initOver = true;
});
},
/**
* Get profile helper data
*/
getDataOfProfileHelper() {
const params = {
train_id: this.curDashboardInfo.query.id,
profile: this.curDashboardInfo.query.dir,
device_id: this.curDashboardInfo.curCardNum.toString()
? this.curDashboardInfo.curCardNum.toString()
: '0',
};
RequestService.queryDataOfProfileHelper(params)
.then((resp) => {
if (resp && resp.data) {
const dataKeys = Object.keys(resp.data);
const helperDiv = document.getElementById('helper-tips');
helperDiv.innerHTML = '';
dataKeys.forEach((item) => {
if (
!this.tipsArrayList.includes(item) &&
!this.moreParameter.includes(item) &&
resp.data[item]
) {
this.$t(`profiling`)[item] = resp.data[item];
}
if (item.endsWith('type_label')) {
const divDom = document.createElement('div');
divDom.setAttribute('class', 'suggested-items-style');
divDom.innerHTML = `<div class="helper-icon"></div>
<div class="helper-container-title">
${this.$t(`profiling`)[item].desc}
</div>`;
helperDiv.appendChild(divDom);
} else if (this.tipsArrayList.includes(item)) {
const divDom = document.createElement('div');
divDom.setAttribute('class', 'content-style');
const content = `${this.$t(`profiling`)[item].desc}`.replace(
`{n1}`,
resp.data[item][0],
);
divDom.innerHTML = `<div class="content-icon el-icon-caret-right"></div>
<div class="helper-content-style">${content}</div>`;
helperDiv.appendChild(divDom);
} else if (item === 'minddata_device_queue') {
const deviceEmpty =
resp.data['minddata_device_queue'][0] >= 0
? resp.data['minddata_device_queue'][0]
: '--';
const deviceTotal =
resp.data['minddata_device_queue'][1] >= 0
? resp.data['minddata_device_queue'][1]
: '--';
const deviceFull =
resp.data['minddata_device_queue'][2] >= 0
? resp.data['minddata_device_queue'][2]
: '--';
const divDom = document.createElement('div');
divDom.setAttribute('class', 'content-style');
const content = `${this.$t(`profiling`)[item].desc}`
.replace(
`{n1}`,
`<span class="nowrap-style"> ${deviceEmpty}</span>`,
)
.replace(
`{n2}`,
`<span class="nowrap-style"> ${deviceTotal}</span>`,
)
.replace(
`{n3}`,
`<span class="nowrap-style"> ${deviceFull}</span>`,
)
.replace(
`{n4}`,
`<span class="nowrap-style"> ${deviceTotal}</span>`,
);
divDom.innerHTML = `<div class="content-icon el-icon-caret-right"></div>
<div class="helper-content-style">${content}</div>`;
helperDiv.appendChild(divDom);
} else if (item === 'minddata_get_next_queue') {
const getNextEmpty =
resp.data['minddata_get_next_queue'][0] >= 0
? resp.data['minddata_get_next_queue'][0]
: '--';
const getNextTotal =
resp.data['minddata_get_next_queue'][1] >= 0
? resp.data['minddata_get_next_queue'][1]
: '--';
const divDom = document.createElement('div');
divDom.setAttribute('class', 'content-style');
const content = `${this.$t(`profiling`)[item].desc}`
.replace(
`{n1}`,
`<span class="nowrap-style"> ${getNextEmpty}</span>`,
)
.replace(
`{n2}`,
`<span class="nowrap-style"> ${getNextTotal}</span>`,
);
divDom.innerHTML = `<div class="content-icon el-icon-caret-right"></div>
<div class="helper-content-style">${content}</div>`;
helperDiv.appendChild(divDom);
} else if (this.$t(`profiling`)[item].anchor) {
if (this.$t(`profiling`)[item].anchor.length === 1) {
const divDom = document.createElement('div');
divDom.setAttribute('class', 'content-style');
divDom.innerHTML = `<div class="content-icon el-icon-caret-right"></div>
<div class="helper-content-style">
<a target="_blank" href="${this.$t(`profiling`)[item].url[0]}">
${this.$t(`profiling`)[item].desc}</a></div>`;
helperDiv.appendChild(divDom);
} else {
const divDom = document.createElement('div');
divDom.setAttribute('class', 'content-style');
const anchorList = this.$t(`profiling`)[item].anchor;
let anchorContent = this.$t(`profiling`)[item].desc;
for (let i = 0; i < anchorList.length; i++) {
const desc = anchorContent.relpace(
anchorList[i],
`<a target="_blank" href="${
this.$t(`profiling`)[item].url[i]
}">
${anchorList[i]}</a>`,
);
anchorContent = desc;
}
divDom.innerHTML = `<div class="content-icon el-icon-caret-right">
</div><div class="helper-content-style">${anchorContent}</div>`;
helperDiv.appendChild(divDom);
}
} else {
const divDom = document.createElement('div');
divDom.setAttribute('class', 'content-style');
divDom.innerHTML = `${this.$t(`profiling`)[item].desc}`;
helperDiv.appendChild(divDom);
}
});
}
})
.catch(() => {});
},
/**
* Router back to profiling-dashboard
*/
backToDdashboard() {
this.$router.push({
path: '/profiling-gpu/profiling-dashboard',
query: {
dir: this.curDashboardInfo.query.dir,
id: this.curDashboardInfo.query.id,
path: this.curDashboardInfo.query.path,
},
});
},
collapseLeft() {
this.collapse = !this.collapse;
this.$bus.$emit('collapse');
},
},
destroyed() {
this.$bus.$off('collapse');
},
};
</script>
<style lang="scss">
.prof-wrap {
height: 100%;
background: #fff;
.prof-content {
height: 100%;
padding: 24px 24px 24px 0;
& > div {
float: left;
height: 100%;
}
.prof-content-left {
width: 22%;
transition: width 0.2s;
position: relative;
.el-input__inner {
padding: 0 10px;
}
.helper {
padding: 32px;
height: 100%;
overflow-y: auto;
margin-left: 24px;
background: #edf0f5;
word-wrap: break-word;
.nowrap-style {
white-space: nowrap;
}
.cur-card {
margin-bottom: 32px;
.card-select {
width: calc(100% - 120px);
}
& > label {
margin-right: 14px;
}
}
.helper-title {
font-size: 20px;
font-weight: bold;
margin-bottom: 32px;
.el-icon-rank {
float: right;
cursor: pointer;
}
}
.helper-container-title {
display: inline-block;
padding: 0 6px;
}
.helper-icon {
display: inline-block;
width: 6px;
height: 6px;
margin-top: 6px;
border-radius: 3px;
background-color: #00a5a7;
}
.suggested-title {
font-weight: bold;
margin-bottom: 20px;
font-size: 16px;
}
.container-bottom {
margin-bottom: 16px;
}
.suggested-items-style {
display: flex;
font-weight: bold;
margin-bottom: 6px;
margin-top: 10px;
}
.helper-content-style {
margin-left: 6px;
line-height: 20px;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 8;
}
}
.content-icon {
color: #00a5a7;
padding-top: 3px;
}
.content-style {
display: flex;
}
.collapse-btn {
position: absolute;
right: -21px;
width: 31px;
height: 100px;
top: 50%;
margin-top: -50px;
cursor: pointer;
line-height: 86px;
z-index: 1;
text-align: center;
background-image: url('../../assets/images/collapse-left.svg');
}
.collapse-btn.collapse {
background-image: url('../../assets/images/collapse-right.svg');
}
}
.prof-content-left.collapse {
width: 0;
}
.prof-content-right {
width: 78%;
padding-left: 20px;
transition: width 0.2s;
position: relative;
.close {
position: absolute;
right: 0;
top: -10px;
cursor: pointer;
}
}
.prof-content-right.collapse {
width: 100%;
}
}
}
</style>
......@@ -25,9 +25,6 @@ limitations under the License.
:class="{fullScreen:fullScreen}"
v-if="coreCharts.data.length">
<div>
<span class="profiler-title">
{{$t('operator.operatorTypeStatistics')}}
</span>
<el-radio-group class="chart-radio-group"
v-model="coreCharts.type"
@change="coreChartChange"
......@@ -49,9 +46,6 @@ limitations under the License.
<div class="cl-profiler-bottom"
:class="{fullScreen:fullScreen}"
v-if="coreCharts.data.length">
<span class="profiler-title">
{{ $t('operator.operatorStatistics') }}
</span>
<img src="../../assets/images/full-screen.png"
:title="$t('graph.fullScreen')"
class="fullScreen"
......@@ -90,7 +84,7 @@ limitations under the License.
@expand-change="expandTypeItem"
@sort-change="opTypeSortChange"
stripe
height="calc(100% - 75px)"
height="calc(100% - 40px)"
width="100%">
<el-table-column type="expand">
<template slot-scope="props">
......@@ -144,7 +138,7 @@ limitations under the License.
stripe
ref="opAllTable"
width="100%"
height="calc(100% - 114px)"
height="calc(100% - 80px)"
@cell-click="showInfoDetail"
@sort-change="(...args)=>{coreDetailSortChange(opAllTypeList, ...args)}"
tooltip-effect="light">
......@@ -186,11 +180,6 @@ limitations under the License.
name="cpu">
<div class="cl-profiler-top"
v-if="false">
<div>
<span class="profiler-title">
{{ $t('operator.operatorStatistics') }}
</span>
</div>
<div class="cl-profiler-echarts">
<div class
id="cpu-echarts"></div>
......@@ -198,9 +187,6 @@ limitations under the License.
</div>
<div class="cl-profiler-bottom"
v-if="cpuCharts.data.length">
<span class="profiler-title">
{{ $t('operator.operatorStatistics') }}
</span>
<div class="cl-search-box">
<el-input v-model="searchByCPUTypeInput"
:placeholder="$t('operator.searchByType')"
......@@ -324,7 +310,7 @@ export default {
pageTotal: 0,
opDetailPage: {
offset: 0,
limit: 8,
limit: 15,
},
op_filter_condition: {},
op_sort_condition: {},
......@@ -444,7 +430,7 @@ export default {
pageTotal: 0,
opDetailPage: {
offset: 0,
limit: 8,
limit: 15,
},
op_filter_condition: {},
op_sort_condition: {},
......@@ -480,7 +466,7 @@ export default {
opDetailCol: [],
opDetailPage: {
offset: 0,
limit: 8,
limit: 15,
},
pageTotal: 0,
op_filter_condition: {
......@@ -871,6 +857,9 @@ export default {
}
return legendStr;
},
tooltip: {
show: true,
},
itemWidth: 18,
itemHeight: 18,
padding: [0, 50, 0, 0],
......@@ -1186,12 +1175,6 @@ export default {
height: 100%;
}
}
.profiler-title {
font-size: 16px;
font-weight: bold;
line-height: 32px;
display: inline-block;
}
.cl-profiler-echarts {
width: 100%;
height: calc(100% - 32px);
......
......@@ -1364,6 +1364,7 @@ export default {
align-items: baseline;
.cell-container {
width: 20%;
min-width:110px;
padding: 20px 0;
border: 2px solid transparent;
.title {
......@@ -1428,7 +1429,7 @@ export default {
font-size: 12px;
line-height: 12px;
white-space: nowrap;
overflow: hidden;
overflow: visible;
width: 100%;
text-align: center;
.line {
......
......@@ -121,7 +121,8 @@ export default {
train_id: this.curDashboardInfo.query.id,
};
RequestService.getProfilerDeviceData(params)
.then((res) => {
.then(
(res) => {
if (res && res.data && res.data.length) {
const deviceList = res.data;
deviceList.forEach((item) => {
......@@ -136,7 +137,13 @@ export default {
this.curDashboardInfo.curCardNum = '';
this.curDashboardInfo.initOver = true;
}
})
},
(error) => {
this.CardNumArr = [];
this.curDashboardInfo.curCardNum = '';
this.curDashboardInfo.initOver = true;
},
)
.catch(() => {
this.curDashboardInfo.initOver = true;
});
......@@ -310,13 +317,13 @@ export default {
background: #fff;
.prof-content {
height: 100%;
padding: 32px 32px 32px 0;
padding: 24px 24px 24px 0;
& > div {
float: left;
height: 100%;
}
.prof-content-left {
width: 25%;
width: 22%;
transition: width 0.2s;
position: relative;
.el-input__inner {
......@@ -326,7 +333,7 @@ export default {
padding: 32px;
height: 100%;
overflow-y: auto;
margin-left: 32px;
margin-left: 24px;
background: #edf0f5;
word-wrap: break-word;
.nowrap-style {
......@@ -415,7 +422,7 @@ export default {
width: 0;
}
.prof-content-right {
width: 75%;
width: 78%;
padding-left: 20px;
transition: width 0.2s;
position: relative;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册