From: @gzhcv Reviewed-by: @ouwenchang,@ouwenchang,@lilongfei15 Signed-off-by: @lilongfei15pull/1311/MERGE
| @@ -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) | ||||
| @@ -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 | ||||
| @@ -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": { | ||||
| @@ -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": { | ||||
| @@ -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', | ||||
| @@ -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; | ||||
| @@ -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; | ||||
| @@ -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) | |||||
| @@ -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( | ||||