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') | |||
| _ = to_int(device_id, 'device_id') | |||
| 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']: | |||
| logger.info("Invalid device_type, device_type should be gpu or ascend.") | |||
| raise ParamValueError("Invalid device_type.") | |||
| analyser = AnalyserFactory.instance().get_analyser( | |||
| '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) | |||
| @@ -43,7 +43,7 @@ class TimelineAnalyser(BaseAnalyser): | |||
| 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. | |||
| @@ -67,6 +67,11 @@ class TimelineAnalyser(BaseAnalyser): | |||
| try: | |||
| with open(file_path, 'r') as 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: | |||
| logger.error('Error occurred when read timeline display file: %s', err) | |||
| raise ProfilerIOException | |||
| @@ -438,6 +438,7 @@ | |||
| "content11": "- Device(AI CPU or AI core) to which an operator is allocated for execution.", | |||
| "content12": "- Flow tiling policy of MindSpore on the network.", | |||
| "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?", | |||
| "content21": { | |||
| "part1": "Click ", | |||
| @@ -520,7 +521,8 @@ | |||
| "fpStart": "Forward", | |||
| "bpEnd": "Backward" | |||
| }, | |||
| "isHeterogeneous": "Heterogeneous training scenarios are not supported temporarily." | |||
| "isHeterogeneous": "Heterogeneous training scenarios are not supported temporarily.", | |||
| "scopeNameNum": "ScopeName Layer Counts: " | |||
| }, | |||
| "profilingGPU": { | |||
| "minddata_get_next_queue": { | |||
| @@ -436,7 +436,8 @@ | |||
| "title1": "时间线功能可以帮您对训练过程进行分析,它可以展示:", | |||
| "content11": "- 算子分配到哪个设备 (AI CPU/AI Core) 执行;", | |||
| "content12": "- MindSpore对该网络的流切分策略;", | |||
| "content13": "- 算子在Device上的执行序列和执行时长。", | |||
| "content13": "- 算子在Device上的执行序列和执行时长;", | |||
| "content14": "- 算子ScopeName信息,例如算子Conv2D-op11的全名为:Default/network/lenet5/Conv2D-op11,该算子的第一层ScopeName为Default、第二层为network。", | |||
| "title2": "如何查看时间线:", | |||
| "content21": { | |||
| "part1": "要查看时间线的详细信息,您可以点击 \"", | |||
| @@ -519,7 +520,8 @@ | |||
| "fpStart": "前向", | |||
| "bpEnd": "后向" | |||
| }, | |||
| "isHeterogeneous":"暂不支持异构训练场景" | |||
| "isHeterogeneous":"暂不支持异构训练场景", | |||
| "scopeNameNum":"展示算子ScopeName层数: " | |||
| }, | |||
| "profilingGPU": { | |||
| "minddata_get_next_queue": { | |||
| @@ -247,7 +247,7 @@ export default { | |||
| }, | |||
| }); | |||
| }, | |||
| queryTimlineInfo(params) { | |||
| queryTimelineInfo(params) { | |||
| return axios({ | |||
| method: 'get', | |||
| url: 'v1/mindinsight/profile/timeline-summary', | |||
| @@ -16,7 +16,7 @@ limitations under the License. | |||
| <template> | |||
| <div class="pro-router-wrap"> | |||
| <div class="pro-router-left"> | |||
| <!-- Step trace area --> | |||
| <!-- Step trace area --> | |||
| <div class="step-trace"> | |||
| <div class="title-wrap"> | |||
| <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>{{$t("profiling.timelineTips.content12")}}</div> | |||
| <div>{{$t("profiling.timelineTips.content13")}}</div> | |||
| <div>{{$t("profiling.timelineTips.content14")}}</div> | |||
| <br> | |||
| <div class="font-style">{{$t("profiling.timelineTips.title2")}}</div> | |||
| <div> | |||
| @@ -359,6 +360,20 @@ limitations under the License. | |||
| <!-- Time line detail --> | |||
| <div class="timeline-info" | |||
| 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"> | |||
| <span>{{$t('profiling.opTotalTime')}}</span><span>{{timelineInfo.totalTime}}ms</span> | |||
| </div> | |||
| @@ -463,7 +478,7 @@ export default { | |||
| timeLine: { | |||
| // Time line data | |||
| data: null, | |||
| waiting: true, // Is it waiting for interface return | |||
| waiting: false, // Is it waiting for interface return | |||
| disable: true, | |||
| }, | |||
| timelineInfo: { | |||
| @@ -474,6 +489,8 @@ export default { | |||
| opTimes: 0, // Operator time consuming | |||
| noData: true, | |||
| initOver: false, // Is initialization complete | |||
| scopeNameNum: '', | |||
| scopeNameNumArr: [], | |||
| }, | |||
| isHeterogeneous: false, | |||
| }; | |||
| @@ -496,23 +513,17 @@ export default { | |||
| this.timelineInfo.initOver = true; | |||
| 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.trainingJobId = newValue.query.id; | |||
| this.relativePath = newValue.query.path; | |||
| this.currentCard = newValue.curCardNum; | |||
| 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', | |||
| )}-MindInsight`; | |||
| } else { | |||
| document.title = `${this.$t('profiling.profilingDashboard')}-MindInsight`; | |||
| } | |||
| this.svg.initOver = false; | |||
| this.pieChart.initOver = false; | |||
| @@ -530,7 +541,7 @@ export default { | |||
| * Initialization function | |||
| */ | |||
| init() { | |||
| this.queryTimeline(); | |||
| this.queryTimelineInfo(); | |||
| this.initPieChart(); | |||
| this.getProccessSummary(); | |||
| this.queryTrainingTrace(); | |||
| @@ -702,15 +713,13 @@ export default { | |||
| }); | |||
| this.setPieOption(); | |||
| 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 | |||
| */ | |||
| queryTimeline() { | |||
| this.timeLine.waiting = true; | |||
| this.timeLine.disable = true; | |||
| queryTimelineInfo() { | |||
| const params = { | |||
| dir: this.relativePath, | |||
| device_id: this.currentCard, | |||
| device_type: 'gpu', | |||
| }; | |||
| RequestService.queryTimlineInfo(params) | |||
| RequestService.queryTimelineInfo(params) | |||
| .then((res) => { | |||
| this.timelineInfo.initOver = true; | |||
| if (res && res.data) { | |||
| this.timelineInfo.noData = false; | |||
| 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 { | |||
| this.timelineInfo.noData = true; | |||
| this.timeLine.disable = true; | |||
| } | |||
| }) | |||
| .catch(() => { | |||
| this.timelineInfo.noData = 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) | |||
| .then((res) => { | |||
| this.timeLine.waiting = false; | |||
| @@ -829,9 +857,7 @@ export default { | |||
| this.svg.noData = false; | |||
| this.removeTrace(); | |||
| 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 | |||
| @@ -964,10 +990,7 @@ export default { | |||
| * @return {Object} Generated DOM object | |||
| */ | |||
| createMultipleRowContainer(item) { | |||
| const rectContainer = document.createElementNS( | |||
| this.svg.namespaceURI, | |||
| 'g', | |||
| ); | |||
| const rectContainer = document.createElementNS(this.svg.namespaceURI, 'g'); | |||
| rectContainer.setAttribute('class', 'container'); | |||
| const rect = document.createElementNS(this.svg.namespaceURI, 'rect'); | |||
| @@ -978,10 +1001,7 @@ export default { | |||
| rect.setAttribute('style', 'fill:#edf0f5;stroke:#E2E2E2;stroke-width:1'); | |||
| 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); | |||
| return rectContainer; | |||
| }, | |||
| @@ -995,10 +1015,7 @@ export default { | |||
| const g = document.createElementNS(this.svg.namespaceURI, 'g'); | |||
| 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) => { | |||
| if (i.duration) { | |||
| let temp; | |||
| @@ -1022,18 +1039,11 @@ export default { | |||
| */ | |||
| createRect(data, startY) { | |||
| 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 | |||
| 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 | |||
| 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 | |||
| let name = ''; | |||
| @@ -1069,20 +1079,14 @@ export default { | |||
| rect.setAttribute('width', width); | |||
| 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.setAttribute( | |||
| 'x', | |||
| normalSize | |||
| ? x1 | |||
| : 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), | |||
| ), | |||
| ); | |||
| @@ -1091,10 +1095,7 @@ export default { | |||
| foreignObject.setAttribute('height', this.svg.cellHeight); | |||
| foreignObject.setAttribute('width', width); | |||
| 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'); | |||
| title.textContent = textContent; | |||
| @@ -1112,9 +1113,7 @@ export default { | |||
| */ | |||
| createArrow(data, startY) { | |||
| 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 g = document.createElementNS(this.svg.namespaceURI, 'g'); | |||
| @@ -1136,21 +1135,14 @@ export default { | |||
| const text = document.createElementNS(this.svg.namespaceURI, 'text'); | |||
| 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`; | |||
| 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 | |||
| text.setAttribute( | |||
| 'x', | |||
| 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), | |||
| ), | |||
| ); | |||
| @@ -1512,6 +1504,9 @@ export default { | |||
| .pro-router-wrap .pro-router-right .time-line .info-line { | |||
| line-height: 30px; | |||
| } | |||
| .pro-router-wrap .pro-router-right .time-line .info-line .scope-name{ | |||
| width: 100px; | |||
| } | |||
| .pro-router-wrap .op-time-content { | |||
| height: calc(100% - 54px); | |||
| overflow: auto; | |||
| @@ -329,6 +329,7 @@ limitations under the License. | |||
| <div>{{$t("profiling.timelineTips.content11")}}</div> | |||
| <div>{{$t("profiling.timelineTips.content12")}}</div> | |||
| <div>{{$t("profiling.timelineTips.content13")}}</div> | |||
| <div>{{$t("profiling.timelineTips.content14")}}</div> | |||
| <br> | |||
| <div class="font-style">{{$t("profiling.timelineTips.title2")}}</div> | |||
| <div> | |||
| @@ -359,6 +360,20 @@ limitations under the License. | |||
| <!-- Time line detail --> | |||
| <div class="timeline-info" | |||
| 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"> | |||
| <span>{{$t('profiling.opTotalTime')}}</span><span>{{timelineInfo.totalTime}}ms</span> | |||
| </div> | |||
| @@ -446,7 +461,7 @@ export default { | |||
| timeLine: { | |||
| // Time line data | |||
| data: null, | |||
| waiting: true, // Is it waiting for interface return | |||
| waiting: false, // Is it waiting for interface return | |||
| disable: true, | |||
| }, | |||
| timelineInfo: { | |||
| @@ -457,6 +472,8 @@ export default { | |||
| opTimes: 0, // Operator time consuming | |||
| noData: true, | |||
| initOver: false, // Is initialization complete | |||
| scopeNameNum: '', | |||
| scopeNameNumArr: [], | |||
| }, | |||
| processSummary: { | |||
| // Data of process summary | |||
| @@ -497,24 +514,17 @@ export default { | |||
| this.processSummary.initOver = true; | |||
| 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.trainingJobId = newValue.query.id; | |||
| this.relativePath = newValue.query.path; | |||
| this.currentCard = newValue.curCardNum; | |||
| 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', | |||
| )}-MindInsight`; | |||
| } else { | |||
| document.title = `${this.$t('profiling.profilingDashboard')}-MindInsight`; | |||
| } | |||
| this.svg.initOver = false; | |||
| this.pieChart.initOver = false; | |||
| @@ -532,7 +542,7 @@ export default { | |||
| * Initialization function | |||
| */ | |||
| init() { | |||
| this.queryTimeline(); | |||
| this.queryTimelineInfo(); | |||
| this.queryTrainingTrace(); | |||
| this.getProccessSummary(); | |||
| this.initPieChart(); | |||
| @@ -667,15 +677,13 @@ export default { | |||
| }); | |||
| this.setPieOption(); | |||
| 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.removeTrace(); | |||
| 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 | |||
| @@ -841,10 +847,7 @@ export default { | |||
| * @return {Object} Generated DOM object | |||
| */ | |||
| createMultipleRowContainer(item) { | |||
| const rectContainer = document.createElementNS( | |||
| this.svg.namespaceURI, | |||
| 'g', | |||
| ); | |||
| const rectContainer = document.createElementNS(this.svg.namespaceURI, 'g'); | |||
| rectContainer.setAttribute('class', 'container'); | |||
| const rect = document.createElementNS(this.svg.namespaceURI, 'rect'); | |||
| @@ -855,10 +858,7 @@ export default { | |||
| rect.setAttribute('style', 'fill:#edf0f5;stroke:#E2E2E2;stroke-width:1'); | |||
| 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); | |||
| return rectContainer; | |||
| }, | |||
| @@ -872,10 +872,7 @@ export default { | |||
| const g = document.createElementNS(this.svg.namespaceURI, 'g'); | |||
| 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) => { | |||
| if (i.duration) { | |||
| let temp; | |||
| @@ -899,18 +896,11 @@ export default { | |||
| */ | |||
| createRect(data, startY) { | |||
| 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 | |||
| 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 | |||
| 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 | |||
| let name = ''; | |||
| @@ -946,20 +936,14 @@ export default { | |||
| rect.setAttribute('width', width); | |||
| 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.setAttribute( | |||
| 'x', | |||
| normalSize | |||
| ? x1 | |||
| : 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), | |||
| ), | |||
| ); | |||
| @@ -968,10 +952,7 @@ export default { | |||
| foreignObject.setAttribute('height', this.svg.cellHeight); | |||
| foreignObject.setAttribute('width', width); | |||
| 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'); | |||
| title.textContent = textContent; | |||
| @@ -989,9 +970,7 @@ export default { | |||
| */ | |||
| createArrow(data, startY) { | |||
| 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 g = document.createElementNS(this.svg.namespaceURI, 'g'); | |||
| @@ -1013,21 +992,14 @@ export default { | |||
| const text = document.createElementNS(this.svg.namespaceURI, 'text'); | |||
| 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`; | |||
| 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 | |||
| text.setAttribute( | |||
| 'x', | |||
| 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), | |||
| ), | |||
| ); | |||
| @@ -1101,37 +1073,55 @@ export default { | |||
| /** | |||
| * Query the data of time line | |||
| */ | |||
| queryTimeline() { | |||
| this.timeLine.waiting = true; | |||
| this.timeLine.disable = true; | |||
| queryTimelineInfo() { | |||
| const params = { | |||
| dir: this.relativePath, | |||
| device_id: this.currentCard, | |||
| }; | |||
| RequestService.queryTimlineInfo(params) | |||
| RequestService.queryTimelineInfo(params) | |||
| .then((res) => { | |||
| this.timelineInfo.initOver = true; | |||
| if (res && res.data) { | |||
| this.timelineInfo.noData = false; | |||
| 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 { | |||
| this.timelineInfo.noData = true; | |||
| this.timeLine.disable = true; | |||
| } | |||
| }) | |||
| .catch(() => { | |||
| this.timelineInfo.noData = 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) | |||
| .then((res) => { | |||
| this.timeLine.waiting = false; | |||
| @@ -1518,6 +1508,9 @@ export default { | |||
| .pro-router-wrap .pro-router-right .time-line .info-line { | |||
| line-height: 30px; | |||
| } | |||
| .pro-router-wrap .pro-router-right .time-line .info-line .scope-name { | |||
| width: 100px; | |||
| } | |||
| .pro-router-wrap .op-time-content { | |||
| height: calc(100% - 54px); | |||
| overflow: auto; | |||
| @@ -62,10 +62,10 @@ class TestTimelineAnalyser: | |||
| 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) | |||
| result = self._analyser.get_display_timeline("ascend") | |||
| result = self._analyser.get_display_timeline("ascend", 0) | |||
| compare_result_with_file(result, ascend_file_path) | |||
| @pytest.mark.level0 | |||
| @@ -103,4 +103,4 @@ class TestTimelineAnalyser: | |||
| analyser = AnalyserFactory.instance().get_analyser( | |||
| 'timeline', self.profiler, device_id) | |||
| 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) | |||
| ) | |||
| result = self._analyser.get_display_timeline(device_target) | |||
| result = self._analyser.get_display_timeline(device_target, 0) | |||
| compare_result_with_file(result, file_path) | |||
| @pytest.mark.parametrize( | |||