Browse Source

!1311 Add scope name and step number in timeline

From: @gzhcv
Reviewed-by: @ouwenchang,@ouwenchang,@lilongfei15
Signed-off-by: @lilongfei15
pull/1311/MERGE
mindspore-ci-bot Gitee 4 years ago
parent
commit
762b662fde
9 changed files with 178 additions and 180 deletions
  1. +2
    -1
      mindinsight/backend/profiler/profile_api.py
  2. +6
    -1
      mindinsight/profiler/analyser/timeline_analyser.py
  3. +3
    -1
      mindinsight/ui/src/locales/en-us.json
  4. +4
    -2
      mindinsight/ui/src/locales/zh-cn.json
  5. +1
    -1
      mindinsight/ui/src/services/request-service.js
  6. +80
    -85
      mindinsight/ui/src/views/profiling-gpu/profiling-dashboard.vue
  7. +78
    -85
      mindinsight/ui/src/views/profiling/profiling-dashboard.vue
  8. +3
    -3
      tests/st/func/profiler/test_timeline_analyser.py
  9. +1
    -1
      tests/ut/profiler/analyser/test_timeline_analyser.py

+ 2
- 1
mindinsight/backend/profiler/profile_api.py View File

@@ -489,13 +489,14 @@ def get_timeline_detail():
device_id = request.args.get("device_id", default='0') device_id = request.args.get("device_id", default='0')
_ = to_int(device_id, 'device_id') _ = to_int(device_id, 'device_id')
device_type = request.args.get("device_type", default='ascend') device_type = request.args.get("device_type", default='ascend')
scope_name_num = request.args.get("scope_name_num", default='0')
if device_type not in ['gpu', 'ascend']: if device_type not in ['gpu', 'ascend']:
logger.info("Invalid device_type, device_type should be gpu or ascend.") logger.info("Invalid device_type, device_type should be gpu or ascend.")
raise ParamValueError("Invalid device_type.") raise ParamValueError("Invalid device_type.")


analyser = AnalyserFactory.instance().get_analyser( analyser = AnalyserFactory.instance().get_analyser(
'timeline', profiler_dir_abs, device_id) 'timeline', profiler_dir_abs, device_id)
timeline = analyser.get_display_timeline(device_type)
timeline = analyser.get_display_timeline(device_type, scope_name_num)


return jsonify(timeline) return jsonify(timeline)




+ 6
- 1
mindinsight/profiler/analyser/timeline_analyser.py View File

@@ -43,7 +43,7 @@ class TimelineAnalyser(BaseAnalyser):
filter_condition (dict): The filter condition. filter_condition (dict): The filter condition.
""" """


def get_display_timeline(self, device_type):
def get_display_timeline(self, device_type, scope_name_num):
""" """
Get timeline data for UI display. Get timeline data for UI display.


@@ -67,6 +67,11 @@ class TimelineAnalyser(BaseAnalyser):
try: try:
with open(file_path, 'r') as f_obj: with open(file_path, 'r') as f_obj:
timeline = json.load(f_obj) timeline = json.load(f_obj)
for idx, time_item in enumerate(timeline):
if time_item["tid"] == "Name Scope" and \
time_item["scope_level"] >= scope_name_num:
timeline[idx] = None
timeline = list(filter(lambda x: x, timeline))
except (IOError, OSError, json.JSONDecodeError) as err: except (IOError, OSError, json.JSONDecodeError) as err:
logger.error('Error occurred when read timeline display file: %s', err) logger.error('Error occurred when read timeline display file: %s', err)
raise ProfilerIOException raise ProfilerIOException


+ 3
- 1
mindinsight/ui/src/locales/en-us.json View File

@@ -438,6 +438,7 @@
"content11": "- Device(AI CPU or AI core) to which an operator is allocated for execution.", "content11": "- Device(AI CPU or AI core) to which an operator is allocated for execution.",
"content12": "- Flow tiling policy of MindSpore on the network.", "content12": "- Flow tiling policy of MindSpore on the network.",
"content13": "- Execution sequence and duration of an operator on a device.", "content13": "- Execution sequence and duration of an operator on a device.",
"content14": "- Scope Name of Operator. For example, the full name of one operator is `Default/network/lenet5/Conv2D-op11`, the first scope of this operator is `Default`, the second scope is `network`. ",
"title2": "How to view the timeline details?", "title2": "How to view the timeline details?",
"content21": { "content21": {
"part1": "Click ", "part1": "Click ",
@@ -520,7 +521,8 @@
"fpStart": "Forward", "fpStart": "Forward",
"bpEnd": "Backward" "bpEnd": "Backward"
}, },
"isHeterogeneous": "Heterogeneous training scenarios are not supported temporarily."
"isHeterogeneous": "Heterogeneous training scenarios are not supported temporarily.",
"scopeNameNum": "ScopeName Layer Counts: "
}, },
"profilingGPU": { "profilingGPU": {
"minddata_get_next_queue": { "minddata_get_next_queue": {


+ 4
- 2
mindinsight/ui/src/locales/zh-cn.json View File

@@ -436,7 +436,8 @@
"title1": "时间线功能可以帮您对训练过程进行分析,它可以展示:", "title1": "时间线功能可以帮您对训练过程进行分析,它可以展示:",
"content11": "- 算子分配到哪个设备 (AI CPU/AI Core) 执行;", "content11": "- 算子分配到哪个设备 (AI CPU/AI Core) 执行;",
"content12": "- MindSpore对该网络的流切分策略;", "content12": "- MindSpore对该网络的流切分策略;",
"content13": "- 算子在Device上的执行序列和执行时长。",
"content13": "- 算子在Device上的执行序列和执行时长;",
"content14": "- 算子ScopeName信息,例如算子Conv2D-op11的全名为:Default/network/lenet5/Conv2D-op11,该算子的第一层ScopeName为Default、第二层为network。",
"title2": "如何查看时间线:", "title2": "如何查看时间线:",
"content21": { "content21": {
"part1": "要查看时间线的详细信息,您可以点击 \"", "part1": "要查看时间线的详细信息,您可以点击 \"",
@@ -519,7 +520,8 @@
"fpStart": "前向", "fpStart": "前向",
"bpEnd": "后向" "bpEnd": "后向"
}, },
"isHeterogeneous":"暂不支持异构训练场景"
"isHeterogeneous":"暂不支持异构训练场景",
"scopeNameNum":"展示算子ScopeName层数: "
}, },
"profilingGPU": { "profilingGPU": {
"minddata_get_next_queue": { "minddata_get_next_queue": {


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

@@ -247,7 +247,7 @@ export default {
}, },
}); });
}, },
queryTimlineInfo(params) {
queryTimelineInfo(params) {
return axios({ return axios({
method: 'get', method: 'get',
url: 'v1/mindinsight/profile/timeline-summary', url: 'v1/mindinsight/profile/timeline-summary',


+ 80
- 85
mindinsight/ui/src/views/profiling-gpu/profiling-dashboard.vue View File

@@ -16,7 +16,7 @@ limitations under the License.
<template> <template>
<div class="pro-router-wrap"> <div class="pro-router-wrap">
<div class="pro-router-left"> <div class="pro-router-left">
<!-- Step trace area -->
<!-- Step trace area -->
<div class="step-trace"> <div class="step-trace">
<div class="title-wrap"> <div class="title-wrap">
<div class="title">{{ $t('profiling.stepTrace') }}</div> <div class="title">{{ $t('profiling.stepTrace') }}</div>
@@ -329,6 +329,7 @@ limitations under the License.
<div class="font-style">{{$t("profiling.timelineTips.title1")}}</div> <div class="font-style">{{$t("profiling.timelineTips.title1")}}</div>
<div>{{$t("profiling.timelineTips.content12")}}</div> <div>{{$t("profiling.timelineTips.content12")}}</div>
<div>{{$t("profiling.timelineTips.content13")}}</div> <div>{{$t("profiling.timelineTips.content13")}}</div>
<div>{{$t("profiling.timelineTips.content14")}}</div>
<br> <br>
<div class="font-style">{{$t("profiling.timelineTips.title2")}}</div> <div class="font-style">{{$t("profiling.timelineTips.title2")}}</div>
<div> <div>
@@ -359,6 +360,20 @@ limitations under the License.
<!-- Time line detail --> <!-- Time line detail -->
<div class="timeline-info" <div class="timeline-info"
v-if="!timelineInfo.noData"> v-if="!timelineInfo.noData">
<div class="info-line">
<span>{{$t('profiling.scopeNameNum')}}</span><span>
<el-select v-model="timelineInfo.scopeNameNum"
:placeholder="$t('public.select')"
class="scope-name"
@change="queryTimeline">
<el-option v-for="item in timelineInfo.scopeNameNumArr"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</span>
</div>
<div class="info-line"> <div class="info-line">
<span>{{$t('profiling.opTotalTime')}}</span><span>{{timelineInfo.totalTime}}ms</span> <span>{{$t('profiling.opTotalTime')}}</span><span>{{timelineInfo.totalTime}}ms</span>
</div> </div>
@@ -463,7 +478,7 @@ export default {
timeLine: { timeLine: {
// Time line data // Time line data
data: null, data: null,
waiting: true, // Is it waiting for interface return
waiting: false, // Is it waiting for interface return
disable: true, disable: true,
}, },
timelineInfo: { timelineInfo: {
@@ -474,6 +489,8 @@ export default {
opTimes: 0, // Operator time consuming opTimes: 0, // Operator time consuming
noData: true, noData: true,
initOver: false, // Is initialization complete initOver: false, // Is initialization complete
scopeNameNum: '',
scopeNameNumArr: [],
}, },
isHeterogeneous: false, isHeterogeneous: false,
}; };
@@ -496,23 +513,17 @@ export default {
this.timelineInfo.initOver = true; this.timelineInfo.initOver = true;
this.timeLine.waiting = false; this.timeLine.waiting = false;
} }
if (newValue.query.dir &&
newValue.query.id &&
newValue.query.path &&
newValue.curCardNum
) {
if (newValue.query.dir && newValue.query.id && newValue.query.path && newValue.curCardNum) {
this.summaryPath = newValue.query.dir; this.summaryPath = newValue.query.dir;
this.trainingJobId = newValue.query.id; this.trainingJobId = newValue.query.id;
this.relativePath = newValue.query.path; this.relativePath = newValue.query.path;
this.currentCard = newValue.curCardNum; this.currentCard = newValue.curCardNum;
if (this.trainingJobId) { if (this.trainingJobId) {
document.title = `${decodeURIComponent(
this.trainingJobId,
)}-${this.$t('profiling.profilingDashboard')}-MindInsight`;
} else {
document.title = `${this.$t(
document.title = `${decodeURIComponent(this.trainingJobId)}-${this.$t(
'profiling.profilingDashboard', 'profiling.profilingDashboard',
)}-MindInsight`; )}-MindInsight`;
} else {
document.title = `${this.$t('profiling.profilingDashboard')}-MindInsight`;
} }
this.svg.initOver = false; this.svg.initOver = false;
this.pieChart.initOver = false; this.pieChart.initOver = false;
@@ -530,7 +541,7 @@ export default {
* Initialization function * Initialization function
*/ */
init() { init() {
this.queryTimeline();
this.queryTimelineInfo();
this.initPieChart(); this.initPieChart();
this.getProccessSummary(); this.getProccessSummary();
this.queryTrainingTrace(); this.queryTrainingTrace();
@@ -702,15 +713,13 @@ export default {
}); });
this.setPieOption(); this.setPieOption();
this.pieChart.noData = !!!this.pieChart.data.length; this.pieChart.noData = !!!this.pieChart.data.length;
this.pieChart.topN = this.pieChart.data
.slice(0, Math.min(this.pieChart.data.length, 5))
.map((i) => {
return {
name: i.name,
time: i.value,
frequency: i.frequency,
};
});
this.pieChart.topN = this.pieChart.data.slice(0, Math.min(this.pieChart.data.length, 5)).map((i) => {
return {
name: i.name,
time: i.value,
frequency: i.frequency,
};
});
} }
} }
}) })
@@ -723,38 +732,57 @@ export default {
/** /**
* Query the data of time line * Query the data of time line
*/ */
queryTimeline() {
this.timeLine.waiting = true;
this.timeLine.disable = true;
queryTimelineInfo() {
const params = { const params = {
dir: this.relativePath, dir: this.relativePath,
device_id: this.currentCard, device_id: this.currentCard,
device_type: 'gpu', device_type: 'gpu',
}; };
RequestService.queryTimlineInfo(params)
RequestService.queryTimelineInfo(params)
.then((res) => { .then((res) => {
this.timelineInfo.initOver = true; this.timelineInfo.initOver = true;
if (res && res.data) { if (res && res.data) {
this.timelineInfo.noData = false; this.timelineInfo.noData = false;


this.timelineInfo.totalTime = this.timelineInfo.totalTime =
this.toFixedFun(res.data.total_time, 4) ||
(res.data.total_time === 0 ? 0 : '--');
this.timelineInfo.streamNum =
res.data.num_of_streams ||
(res.data.num_of_streams === 0 ? 0 : '--');
this.timelineInfo.opNum =
res.data.num_of_ops || (res.data.num_of_ops === 0 ? 0 : '--');
this.timelineInfo.opTimes =
res.data.op_exe_times || (res.data.op_exe_times === 0 ? 0 : '--');
this.toFixedFun(res.data.total_time, 4) || (res.data.total_time === 0 ? 0 : '--');
this.timelineInfo.streamNum = res.data.num_of_streams || (res.data.num_of_streams === 0 ? 0 : '--');
this.timelineInfo.opNum = res.data.num_of_ops || (res.data.num_of_ops === 0 ? 0 : '--');
this.timelineInfo.opTimes = res.data.op_exe_times || (res.data.op_exe_times === 0 ? 0 : '--');
if (res.data.max_scope_name_num >= 0) {
this.timelineInfo.scopeNameNum = res.data.max_scope_name_num;
this.timelineInfo.scopeNameNumArr = Array(res.data.max_scope_name_num + 1)
.fill()
.map((value, key) => {
return {
label: key,
value: key,
};
});
this.queryTimeline();
} else {
this.timeLine.disable = true;
}
} else { } else {
this.timelineInfo.noData = true; this.timelineInfo.noData = true;
this.timeLine.disable = true;
} }
}) })
.catch(() => { .catch(() => {
this.timelineInfo.noData = true; this.timelineInfo.noData = true;
this.timelineInfo.initOver = true; this.timelineInfo.initOver = true;
this.timeLine.disable = true;
}); });
},
queryTimeline() {
this.timeLine.waiting = true;
this.timeLine.disable = true;
const params = {
dir: this.relativePath,
device_id: this.currentCard,
device_type: 'gpu',
scope_name_num: this.timelineInfo.scopeNameNum,
};
RequestService.queryTimeline(params) RequestService.queryTimeline(params)
.then((res) => { .then((res) => {
this.timeLine.waiting = false; this.timeLine.waiting = false;
@@ -829,9 +857,7 @@ export default {
this.svg.noData = false; this.svg.noData = false;
this.removeTrace(); this.removeTrace();
this.$nextTick(() => { this.$nextTick(() => {
this.packageTraceData(
JSON.parse(JSON.stringify(res.data.training_trace_graph)),
);
this.packageTraceData(JSON.parse(JSON.stringify(res.data.training_trace_graph)));
}); });


// Set the display information in tip // Set the display information in tip
@@ -964,10 +990,7 @@ export default {
* @return {Object} Generated DOM object * @return {Object} Generated DOM object
*/ */
createMultipleRowContainer(item) { createMultipleRowContainer(item) {
const rectContainer = document.createElementNS(
this.svg.namespaceURI,
'g',
);
const rectContainer = document.createElementNS(this.svg.namespaceURI, 'g');
rectContainer.setAttribute('class', 'container'); rectContainer.setAttribute('class', 'container');


const rect = document.createElementNS(this.svg.namespaceURI, 'rect'); const rect = document.createElementNS(this.svg.namespaceURI, 'rect');
@@ -978,10 +1001,7 @@ export default {
rect.setAttribute('style', 'fill:#edf0f5;stroke:#E2E2E2;stroke-width:1'); rect.setAttribute('style', 'fill:#edf0f5;stroke:#E2E2E2;stroke-width:1');
rectContainer.appendChild(rect); rectContainer.appendChild(rect);


const temp = this.createRowContainer(
item.data,
item.startY + this.svg.rowPadding,
);
const temp = this.createRowContainer(item.data, item.startY + this.svg.rowPadding);
rectContainer.appendChild(temp); rectContainer.appendChild(temp);
return rectContainer; return rectContainer;
}, },
@@ -995,10 +1015,7 @@ export default {
const g = document.createElementNS(this.svg.namespaceURI, 'g'); const g = document.createElementNS(this.svg.namespaceURI, 'g');


data.forEach((row, index) => { data.forEach((row, index) => {
const y =
startY +
this.svg.rowPadding +
index * (this.svg.cellPadding + this.svg.cellHeight);
const y = startY + this.svg.rowPadding + index * (this.svg.cellPadding + this.svg.cellHeight);
row.forEach((i) => { row.forEach((i) => {
if (i.duration) { if (i.duration) {
let temp; let temp;
@@ -1022,18 +1039,11 @@ export default {
*/ */
createRect(data, startY) { createRect(data, startY) {
const color = const color =
data.name && this.svg.colors[data.name]
? this.svg.colors[data.name]
: this.svg.colors.stream_parallel;
data.name && this.svg.colors[data.name] ? this.svg.colors[data.name] : this.svg.colors.stream_parallel;
// Start x position of box // Start x position of box
const x1 =
(data.start / this.svg.totalTime) * this.svg.totalWidth +
this.svg.svgPadding;
const x1 = (data.start / this.svg.totalTime) * this.svg.totalWidth + this.svg.svgPadding;
// The width of the box // The width of the box
const width = Math.max(
this.svg.minWidth,
(data.duration / this.svg.totalTime) * this.svg.totalWidth,
);
const width = Math.max(this.svg.minWidth, (data.duration / this.svg.totalTime) * this.svg.totalWidth);


// Contents of the box // Contents of the box
let name = ''; let name = '';
@@ -1069,20 +1079,14 @@ export default {
rect.setAttribute('width', width); rect.setAttribute('width', width);
rect.setAttribute('style', `fill:${color[1]};stroke:${color[0]};`); rect.setAttribute('style', `fill:${color[1]};stroke:${color[0]};`);


const foreignObject = document.createElementNS(
this.svg.namespaceURI,
'foreignObject',
);
const foreignObject = document.createElementNS(this.svg.namespaceURI, 'foreignObject');
foreignObject.textContent = textContent; foreignObject.textContent = textContent;
foreignObject.setAttribute( foreignObject.setAttribute(
'x', 'x',
normalSize normalSize
? x1 ? x1
: Math.min( : Math.min(
this.svg.svgPadding * 2 +
this.svg.totalWidth -
textWidth -
this.svg.textMargin,
this.svg.svgPadding * 2 + this.svg.totalWidth - textWidth - this.svg.textMargin,
Math.max(this.svg.textMargin, x1 + width / 2 - textWidth / 2), Math.max(this.svg.textMargin, x1 + width / 2 - textWidth / 2),
), ),
); );
@@ -1091,10 +1095,7 @@ export default {
foreignObject.setAttribute('height', this.svg.cellHeight); foreignObject.setAttribute('height', this.svg.cellHeight);
foreignObject.setAttribute('width', width); foreignObject.setAttribute('width', width);
foreignObject.setAttribute('style', `color:${color[0]}`); foreignObject.setAttribute('style', `color:${color[0]}`);
foreignObject.setAttribute(
'class',
`content${normalSize ? '' : ' content-mini'}`,
);
foreignObject.setAttribute('class', `content${normalSize ? '' : ' content-mini'}`);


const title = document.createElementNS(this.svg.namespaceURI, 'title'); const title = document.createElementNS(this.svg.namespaceURI, 'title');
title.textContent = textContent; title.textContent = textContent;
@@ -1112,9 +1113,7 @@ export default {
*/ */
createArrow(data, startY) { createArrow(data, startY) {
const width = (data.duration / this.svg.totalTime) * this.svg.totalWidth; const width = (data.duration / this.svg.totalTime) * this.svg.totalWidth;
const x1 =
(data.start / this.svg.totalTime) * this.svg.totalWidth +
this.svg.svgPadding;
const x1 = (data.start / this.svg.totalTime) * this.svg.totalWidth + this.svg.svgPadding;
const centerY = startY + this.svg.cellHeight / 2; const centerY = startY + this.svg.cellHeight / 2;


const g = document.createElementNS(this.svg.namespaceURI, 'g'); const g = document.createElementNS(this.svg.namespaceURI, 'g');
@@ -1136,21 +1135,14 @@ export default {


const text = document.createElementNS(this.svg.namespaceURI, 'text'); const text = document.createElementNS(this.svg.namespaceURI, 'text');
text.textContent = `${ text.textContent = `${
data.duration === this.svg.totalTime
? this.$t('profiling.approximateTime')
: ''
data.duration === this.svg.totalTime ? this.$t('profiling.approximateTime') : ''
}${this.toFixedFun(data.duration, 4)}ms`; }${this.toFixedFun(data.duration, 4)}ms`;
const textWidth = text.textContent
? this.getTextWidth(text.textContent)
: 0;
const textWidth = text.textContent ? this.getTextWidth(text.textContent) : 0;
// The position of the text cannot go beyond the border of the SVG // The position of the text cannot go beyond the border of the SVG
text.setAttribute( text.setAttribute(
'x', 'x',
Math.min( Math.min(
this.svg.svgPadding * 2 +
this.svg.totalWidth -
textWidth -
this.svg.textMargin,
this.svg.svgPadding * 2 + this.svg.totalWidth - textWidth - this.svg.textMargin,
Math.max(this.svg.textMargin, width / 2 + x1 - textWidth / 2), Math.max(this.svg.textMargin, width / 2 + x1 - textWidth / 2),
), ),
); );
@@ -1512,6 +1504,9 @@ export default {
.pro-router-wrap .pro-router-right .time-line .info-line { .pro-router-wrap .pro-router-right .time-line .info-line {
line-height: 30px; line-height: 30px;
} }
.pro-router-wrap .pro-router-right .time-line .info-line .scope-name{
width: 100px;
}
.pro-router-wrap .op-time-content { .pro-router-wrap .op-time-content {
height: calc(100% - 54px); height: calc(100% - 54px);
overflow: auto; overflow: auto;


+ 78
- 85
mindinsight/ui/src/views/profiling/profiling-dashboard.vue View File

@@ -329,6 +329,7 @@ limitations under the License.
<div>{{$t("profiling.timelineTips.content11")}}</div> <div>{{$t("profiling.timelineTips.content11")}}</div>
<div>{{$t("profiling.timelineTips.content12")}}</div> <div>{{$t("profiling.timelineTips.content12")}}</div>
<div>{{$t("profiling.timelineTips.content13")}}</div> <div>{{$t("profiling.timelineTips.content13")}}</div>
<div>{{$t("profiling.timelineTips.content14")}}</div>
<br> <br>
<div class="font-style">{{$t("profiling.timelineTips.title2")}}</div> <div class="font-style">{{$t("profiling.timelineTips.title2")}}</div>
<div> <div>
@@ -359,6 +360,20 @@ limitations under the License.
<!-- Time line detail --> <!-- Time line detail -->
<div class="timeline-info" <div class="timeline-info"
v-if="!timelineInfo.noData"> v-if="!timelineInfo.noData">
<div class="info-line">
<span>{{$t('profiling.scopeNameNum')}}</span><span>
<el-select v-model="timelineInfo.scopeNameNum"
:placeholder="$t('public.select')"
class="scope-name"
@change="queryTimeline">
<el-option v-for="item in timelineInfo.scopeNameNumArr"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</span>
</div>
<div class="info-line"> <div class="info-line">
<span>{{$t('profiling.opTotalTime')}}</span><span>{{timelineInfo.totalTime}}ms</span> <span>{{$t('profiling.opTotalTime')}}</span><span>{{timelineInfo.totalTime}}ms</span>
</div> </div>
@@ -446,7 +461,7 @@ export default {
timeLine: { timeLine: {
// Time line data // Time line data
data: null, data: null,
waiting: true, // Is it waiting for interface return
waiting: false, // Is it waiting for interface return
disable: true, disable: true,
}, },
timelineInfo: { timelineInfo: {
@@ -457,6 +472,8 @@ export default {
opTimes: 0, // Operator time consuming opTimes: 0, // Operator time consuming
noData: true, noData: true,
initOver: false, // Is initialization complete initOver: false, // Is initialization complete
scopeNameNum: '',
scopeNameNumArr: [],
}, },
processSummary: { processSummary: {
// Data of process summary // Data of process summary
@@ -497,24 +514,17 @@ export default {
this.processSummary.initOver = true; this.processSummary.initOver = true;
this.timeLine.waiting = false; this.timeLine.waiting = false;
} }
if (
newValue.query.dir &&
newValue.query.id &&
newValue.query.path &&
newValue.curCardNum
) {
if (newValue.query.dir && newValue.query.id && newValue.query.path && newValue.curCardNum) {
this.summaryPath = newValue.query.dir; this.summaryPath = newValue.query.dir;
this.trainingJobId = newValue.query.id; this.trainingJobId = newValue.query.id;
this.relativePath = newValue.query.path; this.relativePath = newValue.query.path;
this.currentCard = newValue.curCardNum; this.currentCard = newValue.curCardNum;
if (this.trainingJobId) { if (this.trainingJobId) {
document.title = `${decodeURIComponent(
this.trainingJobId,
)}-${this.$t('profiling.profilingDashboard')}-MindInsight`;
} else {
document.title = `${this.$t(
document.title = `${decodeURIComponent(this.trainingJobId)}-${this.$t(
'profiling.profilingDashboard', 'profiling.profilingDashboard',
)}-MindInsight`; )}-MindInsight`;
} else {
document.title = `${this.$t('profiling.profilingDashboard')}-MindInsight`;
} }
this.svg.initOver = false; this.svg.initOver = false;
this.pieChart.initOver = false; this.pieChart.initOver = false;
@@ -532,7 +542,7 @@ export default {
* Initialization function * Initialization function
*/ */
init() { init() {
this.queryTimeline();
this.queryTimelineInfo();
this.queryTrainingTrace(); this.queryTrainingTrace();
this.getProccessSummary(); this.getProccessSummary();
this.initPieChart(); this.initPieChart();
@@ -667,15 +677,13 @@ export default {
}); });
this.setPieOption(); this.setPieOption();
this.pieChart.noData = !!!this.pieChart.data.length; this.pieChart.noData = !!!this.pieChart.data.length;
this.pieChart.topN = this.pieChart.data
.slice(0, Math.min(this.pieChart.data.length, 5))
.map((i) => {
return {
name: i.name,
time: i.value,
frequency: i.frequency,
};
});
this.pieChart.topN = this.pieChart.data.slice(0, Math.min(this.pieChart.data.length, 5)).map((i) => {
return {
name: i.name,
time: i.value,
frequency: i.frequency,
};
});
} }
} }
}) })
@@ -707,9 +715,7 @@ export default {
this.svg.noData = false; this.svg.noData = false;
this.removeTrace(); this.removeTrace();
this.$nextTick(() => { this.$nextTick(() => {
this.packageTraceData(
JSON.parse(JSON.stringify(res.data.training_trace_graph)),
);
this.packageTraceData(JSON.parse(JSON.stringify(res.data.training_trace_graph)));
}); });


// Set the display information in tip // Set the display information in tip
@@ -841,10 +847,7 @@ export default {
* @return {Object} Generated DOM object * @return {Object} Generated DOM object
*/ */
createMultipleRowContainer(item) { createMultipleRowContainer(item) {
const rectContainer = document.createElementNS(
this.svg.namespaceURI,
'g',
);
const rectContainer = document.createElementNS(this.svg.namespaceURI, 'g');
rectContainer.setAttribute('class', 'container'); rectContainer.setAttribute('class', 'container');


const rect = document.createElementNS(this.svg.namespaceURI, 'rect'); const rect = document.createElementNS(this.svg.namespaceURI, 'rect');
@@ -855,10 +858,7 @@ export default {
rect.setAttribute('style', 'fill:#edf0f5;stroke:#E2E2E2;stroke-width:1'); rect.setAttribute('style', 'fill:#edf0f5;stroke:#E2E2E2;stroke-width:1');
rectContainer.appendChild(rect); rectContainer.appendChild(rect);


const temp = this.createRowContainer(
item.data,
item.startY + this.svg.rowPadding,
);
const temp = this.createRowContainer(item.data, item.startY + this.svg.rowPadding);
rectContainer.appendChild(temp); rectContainer.appendChild(temp);
return rectContainer; return rectContainer;
}, },
@@ -872,10 +872,7 @@ export default {
const g = document.createElementNS(this.svg.namespaceURI, 'g'); const g = document.createElementNS(this.svg.namespaceURI, 'g');


data.forEach((row, index) => { data.forEach((row, index) => {
const y =
startY +
this.svg.rowPadding +
index * (this.svg.cellPadding + this.svg.cellHeight);
const y = startY + this.svg.rowPadding + index * (this.svg.cellPadding + this.svg.cellHeight);
row.forEach((i) => { row.forEach((i) => {
if (i.duration) { if (i.duration) {
let temp; let temp;
@@ -899,18 +896,11 @@ export default {
*/ */
createRect(data, startY) { createRect(data, startY) {
const color = const color =
data.name && this.svg.colors[data.name]
? this.svg.colors[data.name]
: this.svg.colors.stream_parallel;
data.name && this.svg.colors[data.name] ? this.svg.colors[data.name] : this.svg.colors.stream_parallel;
// Start x position of box // Start x position of box
const x1 =
(data.start / this.svg.totalTime) * this.svg.totalWidth +
this.svg.svgPadding;
const x1 = (data.start / this.svg.totalTime) * this.svg.totalWidth + this.svg.svgPadding;
// The width of the box // The width of the box
const width = Math.max(
this.svg.minWidth,
(data.duration / this.svg.totalTime) * this.svg.totalWidth,
);
const width = Math.max(this.svg.minWidth, (data.duration / this.svg.totalTime) * this.svg.totalWidth);


// Contents of the box // Contents of the box
let name = ''; let name = '';
@@ -946,20 +936,14 @@ export default {
rect.setAttribute('width', width); rect.setAttribute('width', width);
rect.setAttribute('style', `fill:${color[1]};stroke:${color[0]};`); rect.setAttribute('style', `fill:${color[1]};stroke:${color[0]};`);


const foreignObject = document.createElementNS(
this.svg.namespaceURI,
'foreignObject',
);
const foreignObject = document.createElementNS(this.svg.namespaceURI, 'foreignObject');
foreignObject.textContent = textContent; foreignObject.textContent = textContent;
foreignObject.setAttribute( foreignObject.setAttribute(
'x', 'x',
normalSize normalSize
? x1 ? x1
: Math.min( : Math.min(
this.svg.svgPadding * 2 +
this.svg.totalWidth -
textWidth -
this.svg.textMargin,
this.svg.svgPadding * 2 + this.svg.totalWidth - textWidth - this.svg.textMargin,
Math.max(this.svg.textMargin, x1 + width / 2 - textWidth / 2), Math.max(this.svg.textMargin, x1 + width / 2 - textWidth / 2),
), ),
); );
@@ -968,10 +952,7 @@ export default {
foreignObject.setAttribute('height', this.svg.cellHeight); foreignObject.setAttribute('height', this.svg.cellHeight);
foreignObject.setAttribute('width', width); foreignObject.setAttribute('width', width);
foreignObject.setAttribute('style', `color:${color[0]}`); foreignObject.setAttribute('style', `color:${color[0]}`);
foreignObject.setAttribute(
'class',
`content${normalSize ? '' : ' content-mini'}`,
);
foreignObject.setAttribute('class', `content${normalSize ? '' : ' content-mini'}`);


const title = document.createElementNS(this.svg.namespaceURI, 'title'); const title = document.createElementNS(this.svg.namespaceURI, 'title');
title.textContent = textContent; title.textContent = textContent;
@@ -989,9 +970,7 @@ export default {
*/ */
createArrow(data, startY) { createArrow(data, startY) {
const width = (data.duration / this.svg.totalTime) * this.svg.totalWidth; const width = (data.duration / this.svg.totalTime) * this.svg.totalWidth;
const x1 =
(data.start / this.svg.totalTime) * this.svg.totalWidth +
this.svg.svgPadding;
const x1 = (data.start / this.svg.totalTime) * this.svg.totalWidth + this.svg.svgPadding;
const centerY = startY + this.svg.cellHeight / 2; const centerY = startY + this.svg.cellHeight / 2;


const g = document.createElementNS(this.svg.namespaceURI, 'g'); const g = document.createElementNS(this.svg.namespaceURI, 'g');
@@ -1013,21 +992,14 @@ export default {


const text = document.createElementNS(this.svg.namespaceURI, 'text'); const text = document.createElementNS(this.svg.namespaceURI, 'text');
text.textContent = `${ text.textContent = `${
data.duration === this.svg.totalTime
? this.$t('profiling.approximateTime')
: ''
data.duration === this.svg.totalTime ? this.$t('profiling.approximateTime') : ''
}${this.toFixedFun(data.duration, 4)}ms`; }${this.toFixedFun(data.duration, 4)}ms`;
const textWidth = text.textContent
? this.getTextWidth(text.textContent)
: 0;
const textWidth = text.textContent ? this.getTextWidth(text.textContent) : 0;
// The position of the text cannot go beyond the border of the SVG // The position of the text cannot go beyond the border of the SVG
text.setAttribute( text.setAttribute(
'x', 'x',
Math.min( Math.min(
this.svg.svgPadding * 2 +
this.svg.totalWidth -
textWidth -
this.svg.textMargin,
this.svg.svgPadding * 2 + this.svg.totalWidth - textWidth - this.svg.textMargin,
Math.max(this.svg.textMargin, width / 2 + x1 - textWidth / 2), Math.max(this.svg.textMargin, width / 2 + x1 - textWidth / 2),
), ),
); );
@@ -1101,37 +1073,55 @@ export default {
/** /**
* Query the data of time line * Query the data of time line
*/ */
queryTimeline() {
this.timeLine.waiting = true;
this.timeLine.disable = true;
queryTimelineInfo() {
const params = { const params = {
dir: this.relativePath, dir: this.relativePath,
device_id: this.currentCard, device_id: this.currentCard,
}; };
RequestService.queryTimlineInfo(params)
RequestService.queryTimelineInfo(params)
.then((res) => { .then((res) => {
this.timelineInfo.initOver = true; this.timelineInfo.initOver = true;
if (res && res.data) { if (res && res.data) {
this.timelineInfo.noData = false; this.timelineInfo.noData = false;


this.timelineInfo.totalTime = this.timelineInfo.totalTime =
this.toFixedFun(res.data.total_time, 4) ||
(res.data.total_time === 0 ? 0 : '--');
this.timelineInfo.streamNum =
res.data.num_of_streams ||
(res.data.num_of_streams === 0 ? 0 : '--');
this.timelineInfo.opNum =
res.data.num_of_ops || (res.data.num_of_ops === 0 ? 0 : '--');
this.timelineInfo.opTimes =
res.data.op_exe_times || (res.data.op_exe_times === 0 ? 0 : '--');
this.toFixedFun(res.data.total_time, 4) || (res.data.total_time === 0 ? 0 : '--');
this.timelineInfo.streamNum = res.data.num_of_streams || (res.data.num_of_streams === 0 ? 0 : '--');
this.timelineInfo.opNum = res.data.num_of_ops || (res.data.num_of_ops === 0 ? 0 : '--');
this.timelineInfo.opTimes = res.data.op_exe_times || (res.data.op_exe_times === 0 ? 0 : '--');
if (res.data.max_scope_name_num >= 0) {
this.timelineInfo.scopeNameNum = res.data.max_scope_name_num;
this.timelineInfo.scopeNameNumArr = Array(res.data.max_scope_name_num + 1)
.fill()
.map((value, key) => {
return {
label: key,
value: key,
};
});
this.queryTimeline();
} else {
this.timeLine.disable = true;
}
} else { } else {
this.timelineInfo.noData = true; this.timelineInfo.noData = true;
this.timeLine.disable = true;
} }
}) })
.catch(() => { .catch(() => {
this.timelineInfo.noData = true; this.timelineInfo.noData = true;
this.timelineInfo.initOver = true; this.timelineInfo.initOver = true;
this.timeLine.disable = true;
}); });
},
queryTimeline() {
this.timeLine.waiting = true;
this.timeLine.disable = true;
const params = {
dir: this.relativePath,
device_id: this.currentCard,
scope_name_num: this.timelineInfo.scopeNameNum,
};
RequestService.queryTimeline(params) RequestService.queryTimeline(params)
.then((res) => { .then((res) => {
this.timeLine.waiting = false; this.timeLine.waiting = false;
@@ -1518,6 +1508,9 @@ export default {
.pro-router-wrap .pro-router-right .time-line .info-line { .pro-router-wrap .pro-router-right .time-line .info-line {
line-height: 30px; line-height: 30px;
} }
.pro-router-wrap .pro-router-right .time-line .info-line .scope-name {
width: 100px;
}
.pro-router-wrap .op-time-content { .pro-router-wrap .op-time-content {
height: calc(100% - 54px); height: calc(100% - 54px);
overflow: auto; overflow: auto;


+ 3
- 3
tests/st/func/profiler/test_timeline_analyser.py View File

@@ -62,10 +62,10 @@ class TestTimelineAnalyser:
self.ascend_display_filename.format(self.device_id) self.ascend_display_filename.format(self.device_id)
) )


result = self._analyser.get_display_timeline("gpu")
result = self._analyser.get_display_timeline("gpu", 0)
compare_result_with_file(result, gpu_file_path) compare_result_with_file(result, gpu_file_path)


result = self._analyser.get_display_timeline("ascend")
result = self._analyser.get_display_timeline("ascend", 0)
compare_result_with_file(result, ascend_file_path) compare_result_with_file(result, ascend_file_path)


@pytest.mark.level0 @pytest.mark.level0
@@ -103,4 +103,4 @@ class TestTimelineAnalyser:
analyser = AnalyserFactory.instance().get_analyser( analyser = AnalyserFactory.instance().get_analyser(
'timeline', self.profiler, device_id) 'timeline', self.profiler, device_id)
analyser.get_timeline_summary("gpu") analyser.get_timeline_summary("gpu")
analyser.get_display_timeline("gpu")
analyser.get_display_timeline("gpu", 0)

+ 1
- 1
tests/ut/profiler/analyser/test_timeline_analyser.py View File

@@ -47,7 +47,7 @@ class TestTimelineAnalyser:
filename.format(self.device_id) filename.format(self.device_id)
) )


result = self._analyser.get_display_timeline(device_target)
result = self._analyser.get_display_timeline(device_target, 0)
compare_result_with_file(result, file_path) compare_result_with_file(result, file_path)


@pytest.mark.parametrize( @pytest.mark.parametrize(


Loading…
Cancel
Save