From fb0c4532daa5b29809c6af48a43190d70544f89b Mon Sep 17 00:00:00 2001 From: w30031080 Date: Thu, 21 Sep 2023 14:53:00 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E4=BF=AE=E6=94=B9=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E3=80=91=E3=80=90tbplugin=E3=80=91=E7=A6=BB=E7=BA=BF=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E6=9B=BF=E6=8D=A2=EF=BC=8C=E6=9B=BF=E6=8D=A2=E9=A5=BC?= =?UTF-8?q?=E5=9B=BE=E5=92=8C=E9=83=A8=E5=88=86=E6=9F=B1=E7=8A=B6=E5=9B=BE?= =?UTF-8?q?=20=E3=80=90=E4=BF=AE=E6=94=B9=E4=BA=BA=E3=80=91wuyulong=203003?= =?UTF-8?q?1080?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tensorboard-plugins/tb_plugin/README.md | 7 +- .../tb_plugin/fe/index.html | 5 +- .../tb_plugin/fe/src/app.tsx | 5 +- .../fe/src/components/DiffOverview.tsx | 131 ++++++++++++++---- .../fe/src/components/charts/NewLineChart.tsx | 9 +- .../fe/src/components/charts/PieChart.tsx | 129 +++++++++++------ .../tb_plugin/torch_tb_profiler/plugin.py | 1 + .../torch_tb_profiler/profiler/data.py | 2 +- .../torch_tb_profiler/profiler/loader.py | 2 +- .../static/trace_embedding.html | 2 +- .../torch_tb_profiler/static/trace_script.js | 27 ++++ 11 files changed, 236 insertions(+), 84 deletions(-) create mode 100644 plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/static/trace_script.js diff --git a/plugins/tensorboard-plugins/tb_plugin/README.md b/plugins/tensorboard-plugins/tb_plugin/README.md index 2ede6cae2..8772a1ba2 100644 --- a/plugins/tensorboard-plugins/tb_plugin/README.md +++ b/plugins/tensorboard-plugins/tb_plugin/README.md @@ -6,11 +6,12 @@ ### 快速安装说明 1. 插件方式安装 +* 插件下载地址 \ + 正式版:https://mindstudio-sample.obs.cn-north-4.myhuaweicloud.com/torch-tb-profiler-ascend/v0.4.0/torch_tb_profiler_ascend-0.4.0-py3-none-any.whl \ + 离线版:https://mindstudio-sample.obs.cn-north-4.myhuaweicloud.com/torch-tb-profiler-ascend/v0.4.0/offline/torch_tb_profiler_ascend-0.4.0-py3-none-any.whl + * 安装相关依赖: pandas >= 1.0.0 ,tensorboard >= 2.11.0 -* 使用依赖: - torch >= 1.8, - torchvision >= 0.8 * 插件形式为whl包,使用指令安装 diff --git a/plugins/tensorboard-plugins/tb_plugin/fe/index.html b/plugins/tensorboard-plugins/tb_plugin/fe/index.html index a58ddc088..e89c379fa 100644 --- a/plugins/tensorboard-plugins/tb_plugin/fe/index.html +++ b/plugins/tensorboard-plugins/tb_plugin/fe/index.html @@ -1,10 +1,9 @@ - - +
- + \ No newline at end of file diff --git a/plugins/tensorboard-plugins/tb_plugin/fe/src/app.tsx b/plugins/tensorboard-plugins/tb_plugin/fe/src/app.tsx index 2437f000e..9d0b90511 100644 --- a/plugins/tensorboard-plugins/tb_plugin/fe/src/app.tsx +++ b/plugins/tensorboard-plugins/tb_plugin/fe/src/app.tsx @@ -54,7 +54,6 @@ import { ModuleView } from './components/ModuleView' import { Operator } from './components/Operator' import { Overview } from './components/Overview' import { TraceView } from './components/TraceView' -import { setup } from './setup' import './styles.css' import { firstOrUndefined, sleep } from './utils' @@ -203,9 +202,7 @@ export const App = () => { // #endregion React.useEffect(() => { - setup().then(() => { - setLoaded(true) - }) + setLoaded(true) }, []) const continuouslyFetchRuns = async () => { diff --git a/plugins/tensorboard-plugins/tb_plugin/fe/src/components/DiffOverview.tsx b/plugins/tensorboard-plugins/tb_plugin/fe/src/components/DiffOverview.tsx index 0fc67e712..fbfb97066 100644 --- a/plugins/tensorboard-plugins/tb_plugin/fe/src/components/DiffOverview.tsx +++ b/plugins/tensorboard-plugins/tb_plugin/fe/src/components/DiffOverview.tsx @@ -15,6 +15,7 @@ import * as React from 'react' import * as api from '../api' import { useResizeEventDependency } from '../utils/resize' import { FullCircularProgress } from './FullCircularProgress' +import * as echarts from 'echarts' const { Option } = Select @@ -67,6 +68,15 @@ const DiffColumnChart: React.FC = ( const graphRef = React.useRef(null) const [resizeEventDependency] = useResizeEventDependency() + const getAngleByDataLength = (data: number) => { + if (data < 10) { + return 0 + } else { + // 数量越大越趋近于旋转90度 + return 90 * (1 - 10 / data) + } + } + React.useLayoutEffect(() => { const element = graphRef.current if (!element) return @@ -100,47 +110,114 @@ const DiffColumnChart: React.FC = ( right_accumulated_duration_max ) - var options = { - title: 'Execution Comparsion', - height: 500, - seriesType: 'bars', - series: { - 0: { type: 'bars', targetAxisIndex: 0 }, - 1: { type: 'bars', targetAxisIndex: 0 }, - 2: { type: 'line', targetAxisIndex: 1 }, - 3: { type: 'line', targetAxisIndex: 1 } + const chart = echarts.init(element) + + const options: echarts.EChartsOption = { + title: { + text: 'Execution Comparsion' }, - vAxes: { - 0: { - logScale: false, - maxValue: duration_max + legend: { + top: 10, + right: 10 + }, + tooltip: { + trigger: 'axis', + formatter: function (params: any) { + const index = params[0].name.indexOf('@') + var res = `${index > -1 ? params[0].name.slice(index + 1) : params[0].name}
` + for (const item of params) { + if (typeof item.value[item.encode.y[0]] === 'number') { + res += ` + + ${item.seriesName}: ${item.value[item.encode.y[0]]}
` + } + } + return res + } + }, + series: [ + { + type: 'bar', + itemStyle: { + color: '#3366cc' + }, + yAxisIndex: 0, + }, - 1: { - logScale: false, - maxValue: accumulated_max + { + type: 'bar', + itemStyle: { + color: '#dc3912' + }, + yAxisIndex: 0 + }, + { + type: 'line', + itemStyle: { + color: '#ff9900' + }, + yAxisIndex: 1 + }, + { + type: 'line', + itemStyle: { + color: '#109618' + }, + yAxisIndex: 1 + } + ], + xAxis: { + type: 'category', + axisLabel: { + interval: 0, + rotate: getAngleByDataLength(rawData.length), + formatter: (name: string) => { + const index = name.indexOf('@') + if (index > -1) { + name = name.slice(index + 1) + } + return name.length > 16 ? name.slice(0, 14) + "..." : name; + } } + }, + yAxis: [{ + type: 'value', + name: 'Time Difference(us)', + scale: true + }, { + type: 'value', + name: 'Accumulated Difference(us)', + scale: true + }], + dataset: { + source: rawData.map((item, idx) => { + // 添加索引保证x轴刻度不重复 + let param = [...item] + param[0] = `${idx}@${param[0]}` + return param + }) } } - const chart = new google.visualization.ComboChart(element) - const data = google.visualization.arrayToDataTable(rawData) - chart.draw(data, options) + options && chart.setOption(options, true) - google.visualization.events.addListener(chart, 'select', (entry: any) => { - var selectedItem = chart.getSelection()[0] - if (selectedItem && selectedItem.hasOwnProperty('row')) { - selectCallback(selectedItem.row, selectedItem.column) - } + chart.on('click', (param) => { + console.log(param) }) return () => { - chart.clearChart() + chart.dispose() } }, [rawData, resizeEventDependency]) return (
-
+
) } @@ -801,7 +878,7 @@ export const DiffOverview: React.FC = (props: IProps) => { rawData={columnChartData} selectCallback={handleChartColumnSelect} /> - + {/* */} )} {columnChartData.length === 1 && ( diff --git a/plugins/tensorboard-plugins/tb_plugin/fe/src/components/charts/NewLineChart.tsx b/plugins/tensorboard-plugins/tb_plugin/fe/src/components/charts/NewLineChart.tsx index 56f946f71..47ef11b4e 100644 --- a/plugins/tensorboard-plugins/tb_plugin/fe/src/components/charts/NewLineChart.tsx +++ b/plugins/tensorboard-plugins/tb_plugin/fe/src/components/charts/NewLineChart.tsx @@ -29,7 +29,6 @@ interface IProps { tag: string hAxisTitle?: string vAxisTitle?: string - explorerOptions?: object onSelectionChanged?: (start: number, end: number) => void record?: any } @@ -62,7 +61,6 @@ export const LineChart: React.FC = (props) => { if (!element) return element.oncontextmenu = () => { return false } - echarts.init(element).dispose() let myChart = echarts.init(element) let option: echarts.EChartsOption = { @@ -367,6 +365,9 @@ export const LineChart: React.FC = (props) => { }) setChartObj(myChart) + return () => { + myChart.dispose() + } }, [graph, height, resizeEventDependency]) React.useEffect(() => { @@ -409,8 +410,6 @@ export const LineChart: React.FC = (props) => { }, [graph, record, chartObj]) return ( -
-
-
+
) } diff --git a/plugins/tensorboard-plugins/tb_plugin/fe/src/components/charts/PieChart.tsx b/plugins/tensorboard-plugins/tb_plugin/fe/src/components/charts/PieChart.tsx index adae3cb9e..54c740334 100644 --- a/plugins/tensorboard-plugins/tb_plugin/fe/src/components/charts/PieChart.tsx +++ b/plugins/tensorboard-plugins/tb_plugin/fe/src/components/charts/PieChart.tsx @@ -1,5 +1,18 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. +/*-------------------------------------------------------------------------------------------- + * Copyright (c) 2023, Huawei Technologies. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. *--------------------------------------------------------------------------------------------*/ import { makeStyles } from '@material-ui/core/styles' @@ -7,6 +20,7 @@ import * as React from 'react' import { Graph } from '../../api' import { value } from '../../utils' import { useResizeEventDependency } from '../../utils/resize' +import * as echarts from 'echarts' interface IProps { graph: Graph @@ -47,60 +61,97 @@ export const PieChart: React.FC = (props) => { const element = graphRef.current if (!element) return - const data = new google.visualization.DataTable() - graph.columns.forEach((column) => { - data.addColumn({ - type: column.type, - label: column.name, - role: column.role, - p: column.p - }) - }) + const chart = echarts.init(element) - const rows = + let totalValue = 0 + const rowsWithUniqueName: Array<{ name: string, value: number }> = top === undefined - ? graph.rows + ? graph.rows.map((item, index) => { + totalValue += item[1] as number + return { name: `${index}_${item[0]}`, value: item[1] as number } + }) : graph.rows - .sort((a, b) => (value(b[1]) as number) - (value(a[1]) as number)) - .slice(0, top) - data.addRows(rows) + .sort((a, b) => (value(b[1]) as number) - (value(a[1]) as number)) + .slice(0, top).map((item, index) => { + totalValue += item[1] as number + return { name: `${index}_${item[0]}`, value: item[1] as number } + }) - const options = { + const option: echarts.EChartsOption = { height, width: '100%', - title, - pieHole: 0.4, - tooltip: { trigger: 'selection', isHtml: true, text: tooltip_mode }, + title: { + text: title + }, + tooltip: { + trigger: 'item', + formatter: (data) => { + const typedData = data as echarts.DefaultLabelFormatterCallbackParams + const index = typedData.name.indexOf('_') + return `${index > -1 ? typedData.name.slice(index + 1) : + typedData.name}
${tooltip_mode === 'both' ? + typedData.value : ''}(${typedData.percent}%)` + }, + confine: true, + extraCssText: `max-width: 300px; + word-wrap:break-word; + white-space:pre-wrap; + padding-right: 10px` + }, chartArea: noLegend ? noLegendArea : !title ? noTitleArea : normalArea, - legend: noLegend ? 'none' : undefined, + legend: { + type: noLegend ? 'plain' : 'scroll', + orient: 'vertical', + left: 'right', + z: 10, + // Display at most 36 characters. + formatter: (name) => { + // Show legends for datas with the same name. + const index = name.indexOf('_') + if (index > -1) { + name = name.slice(index + 1) + } + return name.length > 36 ? name.slice(0, 34) + "..." : name; + }, + tooltip: { + show: true, + triggerOn: 'mousemove', + formatter: (data) => { + const currentItem = rowsWithUniqueName.find(item => item.name === data.name) + const index = data.name.indexOf('_') + const percent = ((currentItem?.value || 0) * 100 / totalValue).toFixed(2) + return `${index > -1 ? data.name.slice(index + 1) : data.name}
${tooltip_mode === 'both' ? + (currentItem?.value || 0) : ''}(${percent}%)` + } + } + }, sliceVisibilityThreshold: 0, - colors + colors, + series: [ + { + type: 'pie', + radius: ['32%', '80%'], + center: ['32%', '50%'], + label: { + position: 'inside', + formatter: `{d}%`, + color: '#ffffff' + }, + data: rowsWithUniqueName + } + ] } - const chart = new google.visualization.PieChart(element) - - google.visualization.events.addListener( - chart, - 'onmouseover', - function (entry: any) { - chart.setSelection([{ row: entry.row }]) - } - ) - - google.visualization.events.addListener(chart, 'onmouseout', function () { - chart.setSelection([]) - }) - - chart.draw(data, options) + option && chart.setOption(option, true) return () => { - chart.clearChart() + chart.dispose() } }, [graph, height, top, resizeEventDependency]) return (
-
+
) } diff --git a/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/plugin.py b/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/plugin.py index bee96927f..093a80b01 100644 --- a/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/plugin.py +++ b/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/plugin.py @@ -111,6 +111,7 @@ class TorchProfilerPlugin(base_plugin.TBPlugin): '/index.html': self.static_file_route, '/trace_viewer_full.html': self.static_file_route, '/trace_embedding.html': self.static_file_route, + '/trace_script.js': self.static_file_route, '/runs': self.runs_route, '/views': self.views_route, '/workers': self.workers_route, diff --git a/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/profiler/data.py b/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/profiler/data.py index b3d402b25..2823d2b6b 100644 --- a/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/profiler/data.py +++ b/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/profiler/data.py @@ -235,7 +235,7 @@ class RunProfileData(object): start_ts = float('inf') for i in reversed(range(len(event_list))): if event_list[i].get('ts') is not None: - start_ts = min(start_ts, event_list[i]['ts']) + start_ts = min(start_ts, float(event_list[i]['ts'])) if device_target != 'Ascend': if event_list[i]['name'] == 'Record Window End': end_index = i diff --git a/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/profiler/loader.py b/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/profiler/loader.py index ce615c827..b7ec37140 100644 --- a/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/profiler/loader.py +++ b/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/profiler/loader.py @@ -52,7 +52,7 @@ class RunLoader(object): data_path = io.join(self.run_dir, path, 'ASCEND_PROFILER_OUTPUT') for file in io.listdir(data_path): if utils.is_npu_trace_path(file) or str(file) in ( - 'kernel_details.csv', 'memory_record.csv', 'memory_record.csv', + 'kernel_details.csv', 'operator_memory.csv', 'memory_record.csv', 'operator_details.csv'): match = consts.WORKER_SPAN_PATTERN.match(path) worker = match.group(1) diff --git a/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/static/trace_embedding.html b/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/static/trace_embedding.html index 7b5c2bb65..bb84da0d0 100644 --- a/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/static/trace_embedding.html +++ b/plugins/tensorboard-plugins/tb_plugin/torch_tb_profiler/static/trace_embedding.html @@ -6,7 +6,7 @@ found in the LICENSE file. --> - +