提交 32100432 编写于 作者: M mindspore-ci-bot 提交者: Gitee

!387 UI timeline dowload and operator show AI CPU

Merge pull request !387 from 潘慧/r0.5
...@@ -248,9 +248,7 @@ ...@@ -248,9 +248,7 @@
"suggestions": "优化建议", "suggestions": "优化建议",
"common-profiler_tutorial": { "common-profiler_tutorial": {
"desc": "如何使用Profiler进行性能分析", "desc": "如何使用Profiler进行性能分析",
"anchor": [ "anchor": ["desc"],
"desc"
],
"url": [ "url": [
"https://www.mindspore.cn/tutorial/zh-CN/master/advanced_use/performance_profiling.html" "https://www.mindspore.cn/tutorial/zh-CN/master/advanced_use/performance_profiling.html"
] ]
...@@ -361,7 +359,21 @@ ...@@ -361,7 +359,21 @@
"approximateTime": "总时长 ≈ ", "approximateTime": "总时长 ≈ ",
"stepInputTip": "请输入step值(1~{max}的正整数)", "stepInputTip": "请输入step值(1~{max}的正整数)",
"inputError": "输入参数异常,请输入一个1~{max}的正整数", "inputError": "输入参数异常,请输入一个1~{max}的正整数",
"defaultTip": "默认展示平均值" "defaultTip": "默认展示平均值",
"downloadTimeline": "下载",
"timelineTips": {
"title1": "时间线功能可以帮您对训练过程进行分析,它可以展示:",
"content11": "- 算子分配到哪个设备 (AICPU/AI Core) 执行;",
"content12": "- MindSpore对该网络的流切分策略;",
"content13": "- 算子在Device上的执行序列和执行时长。",
"title2": "如何查看时间线:",
"content21": "要查看时间线的详细信息,您可以点击 \"下载\" 按钮将带有时间线信息的文件保存到本地,再通过工具查看。",
"content22": "我们推荐您使用谷歌插件:chrome://tracing,或 Perfetto工具:https://ui.perfetto.dev/#!/viewer",
"content23": "选择一个工具,在浏览器地址栏输入地址并回车,进入页面点击按钮加载文件查看时间线(tracing工具点击左上角 \"load\",Perfetto工具点击左侧栏 \"Open trace file\")。",
"title3": "如何使用时间线:",
"content31": "您可以通过时间线信息分析流切分方法是否合理、迭代间隙和拖尾时间是否过长等;",
"content32": "也可以具体定位到某个算子,查看分析它的执行时间。"
}
}, },
"components": { "components": {
"summaryTitle": "训练选择", "summaryTitle": "训练选择",
......
...@@ -1350,6 +1350,7 @@ export default { ...@@ -1350,6 +1350,7 @@ export default {
.chart { .chart {
height: calc(100% - 70px); height: calc(100% - 70px);
min-height: 150px; min-height: 150px;
overflow: hidden;
} }
} }
.chart-wrap.highlight { .chart-wrap.highlight {
......
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
:property="ele" :property="ele"
:key="key" :key="key"
:sortable="ele === 'op_info' ? false : 'custom'" :sortable="ele === 'op_info' ? false : 'custom'"
:width="(ele==='execution_time'|| ele==='subgraph' || :width="(ele==='avg_execution_time (ms)'|| ele==='subgraph' ||
ele==='op_name'|| ele==='op_type')?'220':''" ele==='op_name'|| ele==='op_type')?'220':''"
show-overflow-tooltip show-overflow-tooltip
:label="ele"> :label="ele">
...@@ -122,7 +122,7 @@ ...@@ -122,7 +122,7 @@
:key="$index" :key="$index"
:label="item" :label="item"
:sortable="item === 'op_info' ? false : 'custom'" :sortable="item === 'op_info' ? false : 'custom'"
:width="(item==='execution_time'|| item==='subgraph' || :width="(item==='avg_execution_time (ms)'|| item==='subgraph' ||
item==='op_name'|| item==='op_type')?'220':''" item==='op_name'|| item==='op_type')?'220':''"
show-overflow-tooltip> show-overflow-tooltip>
</el-table-column> </el-table-column>
...@@ -147,10 +147,9 @@ ...@@ -147,10 +147,9 @@
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="AI CPU" <el-tab-pane label="AI CPU"
class="cpu-tab" class="cpu-tab"
name="cpu" name="cpu">
v-if="false">
<div class="cl-profiler-top" <div class="cl-profiler-top"
v-if="cpuCharts.data.length"> v-if="false">
<div> <div>
<span class="profiler-title"> <span class="profiler-title">
{{ $t('operator.operatorStatistics') }} {{ $t('operator.operatorStatistics') }}
...@@ -268,7 +267,7 @@ export default { ...@@ -268,7 +267,7 @@ export default {
pageTotal: 0, pageTotal: 0,
opDetailPage: { opDetailPage: {
offset: 0, offset: 0,
limit: 8, limit: 15,
}, },
op_filter_condition: {}, op_filter_condition: {},
op_sort_condition: { op_sort_condition: {
...@@ -365,7 +364,7 @@ export default { ...@@ -365,7 +364,7 @@ export default {
pageTotal: 0, pageTotal: 0,
opDetailPage: { opDetailPage: {
offset: 0, offset: 0,
limit: 20, limit: 15,
}, },
op_filter_condition: {}, op_filter_condition: {},
op_sort_condition: { op_sort_condition: {
...@@ -572,10 +571,6 @@ export default { ...@@ -572,10 +571,6 @@ export default {
}); });
this.setOption(this.cpuCharts); this.setOption(this.cpuCharts);
} }
if (res.data.object.length > 8) {
this.opCpuList.opDetailPage.limit = 8;
res.data.object.splice(8);
}
this.formatterDetailData(this.opCpuList, res.data); this.formatterDetailData(this.opCpuList, res.data);
if (isSort) { if (isSort) {
this.$nextTick(() => { this.$nextTick(() => {
...@@ -733,7 +728,10 @@ export default { ...@@ -733,7 +728,10 @@ export default {
row.opDetailCol = []; row.opDetailCol = [];
row.opDetailPage.offset = 0; row.opDetailPage.offset = 0;
row.pageTotal = 0; row.pageTotal = 0;
row.op_sort_condition = {name: 'execution_time', type: 'descending'}; row.op_sort_condition = {
name: 'avg_execution_time',
type: 'descending',
};
this.getCoreDetailList(row, true); this.getCoreDetailList(row, true);
} else { } else {
this.curActiveRow = { this.curActiveRow = {
...@@ -772,7 +770,7 @@ export default { ...@@ -772,7 +770,7 @@ export default {
coreTableChange() { coreTableChange() {
if (this.statisticType && !this.opAllTypeList.opDetailCol.length) { if (this.statisticType && !this.opAllTypeList.opDetailCol.length) {
this.opAllTypeList.op_sort_condition = { this.opAllTypeList.op_sort_condition = {
name: 'execution_time', name: 'avg_execution_time',
type: 'descending', type: 'descending',
}; };
this.getCoreDetailList(this.opAllTypeList, true); this.getCoreDetailList(this.opAllTypeList, true);
...@@ -811,7 +809,7 @@ export default { ...@@ -811,7 +809,7 @@ export default {
: chart.data[i].name; : chart.data[i].name;
legendStr = `{a|${i + 1}}{b|${name} ${chart.data[ legendStr = `{a|${i + 1}}{b|${name} ${chart.data[
i i
].value.toFixed(3)}}\n{c|${chart.data[i].percent.toFixed(2)}%}`; ].value.toFixed(6)}}\n{c|${chart.data[i].percent.toFixed(2)}%}`;
} }
} }
return legendStr; return legendStr;
...@@ -877,9 +875,7 @@ export default { ...@@ -877,9 +875,7 @@ export default {
option.tooltip = { option.tooltip = {
trigger: 'axis', trigger: 'axis',
formatter: (params) => { formatter: (params) => {
return `${params[0].axisValue}<br>${ return `${params[0].axisValue}<br>${params[0].marker}${params[0].value}`;
params[0].marker
}${params[0].value.toFixed(4)}`;
}, },
confine: true, confine: true,
}; };
...@@ -1108,7 +1104,7 @@ export default { ...@@ -1108,7 +1104,7 @@ export default {
height: calc(36% + 32px); height: calc(36% + 32px);
} }
.cl-profiler-bottom { .cl-profiler-bottom {
height: calc(64% - 32px); height: 100%;
} }
} }
.profiler-title { .profiler-title {
...@@ -1128,7 +1124,7 @@ export default { ...@@ -1128,7 +1124,7 @@ export default {
width: 100%; width: 100%;
height: 100%; height: 100%;
min-width: 1300px; min-width: 1300px;
min-height: 232px; min-height: 306px;
overflow: hidden; overflow: hidden;
} }
} }
......
...@@ -292,10 +292,33 @@ limitations under the License. ...@@ -292,10 +292,33 @@ limitations under the License.
<div class="title-wrap"> <div class="title-wrap">
<div class="title">{{ $t('profiling.timeLine') }}</div> <div class="title">{{ $t('profiling.timeLine') }}</div>
<div class="view-detail"> <div class="view-detail">
<button @click="toPerfetto()" <button @click="downloadPerfetto()"
:disabled="perfetto.waiting" :disabled="timeLine.waiting"
:class="{disabled:perfetto.waiting}">{{ $t('profiling.viewDetail') }} :class="{disabled:timeLine.waiting}">{{ $t('profiling.downloadTimeline') }}
<i class="el-icon-d-arrow-right"></i></button> </button>
</div>
<div class="tip-icon">
<el-tooltip placement="bottom"
effect="light">
<div slot="content"
class="tooltip-container">
<div class="font-size-style">{{$t("profiling.features")}}</div>
<div class="font-style">{{$t("profiling.timelineTips.title1")}}</div>
<div>{{$t("profiling.timelineTips.content11")}}</div>
<div>{{$t("profiling.timelineTips.content12")}}</div>
<div>{{$t("profiling.timelineTips.content13")}}</div>
<br>
<div class="font-style">{{$t("profiling.timelineTips.title2")}}</div>
<div>{{$t("profiling.timelineTips.content21")}}</div>
<div>{{$t("profiling.timelineTips.content22")}}</div>
<div>{{$t("profiling.timelineTips.content23")}}</div>
<br>
<div class="font-style">{{$t("profiling.timelineTips.title3")}}</div>
<div>{{$t("profiling.timelineTips.content31")}}</div>
<div>{{$t("profiling.timelineTips.content32")}}</div>
</div>
<i class="el-icon-info"></i>
</el-tooltip>
</div> </div>
</div> </div>
<div class="timeline-info" <div class="timeline-info"
...@@ -374,10 +397,8 @@ export default { ...@@ -374,10 +397,8 @@ export default {
topN: [], topN: [],
colorList: ['#6C92FA', '#6CBFFF', '#4EDED2', '#7ADFA0', '#A6DD82'], colorList: ['#6C92FA', '#6CBFFF', '#4EDED2', '#7ADFA0', '#A6DD82'],
}, },
perfetto: { timeLine: {
url: 'https://ui.perfetto.dev/#!',
data: null, data: null,
delay: 5000,
waiting: true, waiting: true,
}, },
timelineInfo: { timelineInfo: {
...@@ -584,7 +605,7 @@ export default { ...@@ -584,7 +605,7 @@ export default {
.map((i) => { .map((i) => {
return { return {
name: i.name, name: i.name,
time: i.value.toFixed(4), time: i.value,
frequency: i.frequency, frequency: i.frequency,
}; };
}); });
...@@ -728,7 +749,7 @@ export default { ...@@ -728,7 +749,7 @@ export default {
name = this.$t('profiling.lterationGap'); name = this.$t('profiling.lterationGap');
break; break;
case 'fp_and_bp': case 'fp_and_bp':
name = this.$t('profiling.deviceQueueOp'); name = this.$t('profiling.deviceQueueOpTip');
break; break;
case 'tail': case 'tail':
name = this.$t('profiling.lterationTail'); name = this.$t('profiling.lterationTail');
...@@ -879,24 +900,6 @@ export default { ...@@ -879,24 +900,6 @@ export default {
} }
return new Uint8Array(arr); return new Uint8Array(arr);
}, },
toPerfetto() {
if (this.perfetto.data) {
const popupwin = window.open(this.perfetto.url);
setTimeout(() => {
const params = {
perfetto: {
title: '',
buffer: this.perfetto.data,
},
};
if (popupwin) {
popupwin.postMessage(params, this.perfetto.url);
}
}, this.perfetto.delay);
} else {
this.perfetto.waiting = true;
}
},
queryTimeline() { queryTimeline() {
const params = { const params = {
dir: this.relativePath, dir: this.relativePath,
...@@ -917,18 +920,28 @@ export default { ...@@ -917,18 +920,28 @@ export default {
.catch(() => { .catch(() => {
this.timelineInfo.noData = true; this.timelineInfo.noData = true;
}); });
this.perfetto.waiting = true; this.timeLine.waiting = true;
RequestService.queryTimeline(params) RequestService.queryTimeline(params)
.then((res) => { .then((res) => {
if (res && res.data) { if (res && res.data) {
this.perfetto.data = this.stringToUint8Array( this.timeLine.data = this.stringToUint8Array(
JSON.stringify(res.data), JSON.stringify(res.data),
); );
this.perfetto.waiting = false; this.timeLine.waiting = false;
} }
}) })
.catch(() => {}); .catch(() => {});
}, },
downloadPerfetto() {
const downloadLink = document.createElement('a');
downloadLink.download = this.getDocName();
downloadLink.style.display = 'none';
const blob = new Blob([this.timeLine.data]);
downloadLink.href = URL.createObjectURL(blob);
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
},
dealProcess(data) { dealProcess(data) {
this.processSummary.device = { this.processSummary.device = {
empty: 0, empty: 0,
...@@ -960,6 +973,22 @@ export default { ...@@ -960,6 +973,22 @@ export default {
this.processSummary.noData = false; this.processSummary.noData = false;
} }
}, },
getDocName() {
const dealNumber = (value) => {
const prefix = value < 10 ? '0' : '';
return prefix + value;
};
const date = new Date();
const year = date.getFullYear();
const mouth = dealNumber(date.getMonth() + 1);
const day = dealNumber(date.getDate());
const hour = dealNumber(date.getHours());
const minute = dealNumber(date.getMinutes());
const second = dealNumber(date.getSeconds());
const millisecond = date.getMilliseconds();
const timestamp = `${year}${mouth}${day}${hour}${minute}${second}${millisecond}`;
return `timeline_${this.trainingJobId}_${this.currentCard}_${timestamp}.json`;
},
}, },
destroyed() { destroyed() {
window.removeEventListener('resize', this.resizeTrace, false); window.removeEventListener('resize', this.resizeTrace, false);
......
...@@ -29,6 +29,7 @@ limitations under the License. ...@@ -29,6 +29,7 @@ limitations under the License.
<el-input ref="step" <el-input ref="step"
v-model.number="steps.step" v-model.number="steps.step"
:disabled="steps.disabled" :disabled="steps.disabled"
@blur="resetStep"
@keyup.native.enter="changeStep"> @keyup.native.enter="changeStep">
</el-input> </el-input>
<el-button @click="changeStep" <el-button @click="changeStep"
...@@ -150,6 +151,7 @@ export default { ...@@ -150,6 +151,7 @@ export default {
bp_end: '--', bp_end: '--',
steps: { steps: {
step: null, step: null,
trueStep: null,
max: 0, max: 0,
disabled: true, disabled: true,
label: this.$t('profiling.stepInputTip'), label: this.$t('profiling.stepInputTip'),
...@@ -269,19 +271,26 @@ export default { ...@@ -269,19 +271,26 @@ export default {
changeStep(value) { changeStep(value) {
if (value === 0) { if (value === 0) {
this.steps.step = null; this.steps.step = null;
this.steps.trueStep = null;
this.queryTrainingTrace(0); this.queryTrainingTrace(0);
} else if ( } else if (
/^[0-9]*[1-9][0-9]*$/.test(this.steps.step) && /^[0-9]*[1-9][0-9]*$/.test(this.steps.step) &&
this.steps.step <= this.steps.max this.steps.step <= this.steps.max
) { ) {
this.steps.trueStep = this.steps.step;
this.queryTrainingTrace(this.steps.step); this.queryTrainingTrace(this.steps.step);
} else { } else {
this.steps.step = null; this.steps.step = this.steps.trueStep;
this.$message.error( this.$message.error(
this.$t('profiling.inputError').replace('{max}', this.steps.max), this.$t('profiling.inputError').replace('{max}', this.steps.max),
); );
} }
}, },
resetStep() {
setTimeout(() => {
this.steps.step = this.steps.trueStep;
}, 200);
},
getTimeInfo(id, type) { getTimeInfo(id, type) {
const params = { const params = {
dir: this.relativePath, dir: this.relativePath,
...@@ -535,7 +544,7 @@ export default { ...@@ -535,7 +544,7 @@ export default {
name = this.$t('profiling.lterationGap'); name = this.$t('profiling.lterationGap');
break; break;
case 'fp_and_bp': case 'fp_and_bp':
name = this.$t('profiling.deviceQueueOp'); name = this.$t('profiling.deviceQueueOpTip');
break; break;
case 'tail': case 'tail':
name = this.$t('profiling.lterationTail'); name = this.$t('profiling.lterationTail');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册