You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

debugger-tensor.vue 47 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473
  1. <!--
  2. Copyright 2020 Huawei Technologies Co., Ltd.All Rights Reserved.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. -->
  13. <template>
  14. <div class="deb-tensor-wrap">
  15. <div class="deb-tensor-left"
  16. :class="{collapse:leftShow}">
  17. <div class="deb-tensor-left-content"
  18. v-show="!leftShow">
  19. <div class="left-content-title">
  20. <span>{{ $t('debugger.optimizationOrientation') }}</span>
  21. </div>
  22. <div class="left-advice"
  23. v-show="leftDataShow">
  24. <div class="left-content-list"
  25. v-for="item in tensorList"
  26. :key="item.id">
  27. <div class="detection-judgment">
  28. <span>{{ $t('debugger.watchPoint') }}{{item.id}}</span>
  29. <span>{{ $t('symbols.colon') }}</span>
  30. <span>{{ $parent.transCondition(item.condition) }}</span>
  31. </div>
  32. <div class="reason"
  33. v-for="(ele,key) in item.params"
  34. :key="key">
  35. <div class="tensor-icon icon-secondary"></div>
  36. <div class="tensor-content">{{ele.content}}</div>
  37. </div>
  38. <div class="hit-tip"
  39. v-if="item.tip">
  40. <i class="el-icon-warning"></i>{{item.tip}}
  41. </div>
  42. <div class="tensor-advice"
  43. v-if="!item.tip">
  44. <span>{{ $t('debugger.tuningAdvice') }}</span>
  45. <div class="advice-list-title">
  46. <div class="adviceTitle">{{ item.tuningAdviceTitle }}</div>
  47. <div class="advice-list">
  48. <div class="advice-content"
  49. v-for="(element, key) in item.tuningAdvice"
  50. :key="key">{{ element }}</div>
  51. </div>
  52. </div>
  53. </div>
  54. </div>
  55. </div>
  56. <div v-show="!leftDataShow"
  57. class="leftNoData">{{ $t('debugger.noWatchPoint') }}</div>
  58. </div>
  59. <div class="collapse-btn"
  60. :class="{collapse:leftShow}"
  61. @click="collapseBtnClick">
  62. </div>
  63. </div>
  64. <div class="deb-tensor-right"
  65. :class="{collapse:leftShow}">
  66. <div class="deb-con-title">
  67. <div class="deb-con-title-left"
  68. :title="curRowObj.name">
  69. {{ curRowObj.name }}
  70. </div>
  71. <div class="deb-con-title-right">
  72. <div class="close-btn">
  73. <img src="@/assets/images/close-page.png"
  74. @click="closeTensor">
  75. </div>
  76. </div>
  77. </div>
  78. <div class="deb-compare-detail">
  79. <div v-for="(statistics,key) in statisticsArr"
  80. :key="key">
  81. <label v-if="key===0">
  82. {{gridType==='preStep'?$t('debugger.preStatisticsLabel'):$t('debugger.curStatisticsLabel')}}
  83. <span>{{ gridType==='preStep'?curRowObj.step-1:curRowObj.step}}</span>
  84. </label>
  85. <label v-if="key===1">{{$t('debugger.preStatisticsLabel')}}<span>{{ curRowObj.step-1 }}</span></label>
  86. <label v-if="key===2">{{$t('debugger.diffStatisticsLabel')}}</label>
  87. <span>{{ $t('debugger.max') }} {{ statistics.overall_max===undefined?'--':statistics.overall_max }}</span>
  88. <span>{{ $t('debugger.min') }} {{ statistics.overall_min===undefined?'--':statistics.overall_min }}</span>
  89. <span>{{ $t('debugger.mean') }} {{ statistics.overall_avg===undefined?'--':statistics.overall_avg }}</span>
  90. <span>{{ $t('debugger.nan') }}
  91. {{ statistics.overall_nan_count===undefined?'--':statistics.overall_nan_count }}
  92. </span>
  93. <span>{{ $t('debugger.negativeInf') }}
  94. {{ statistics.overall_neg_inf_count===undefined?'--':statistics.overall_neg_inf_count }}
  95. </span>
  96. <span>{{ $t('debugger.inf') }}
  97. {{ statistics.overall_pos_inf_count===undefined?'--': statistics.overall_pos_inf_count}}
  98. </span>
  99. <span>{{ $t('debugger.zero') }}
  100. {{ statistics.overall_zero_count===undefined?'--': statistics.overall_zero_count}}</span>
  101. <span>{{ $t('debugger.negativeNum') }}
  102. {{ statistics.overall_neg_zero_count===undefined?'--':statistics.overall_neg_zero_count }}</span>
  103. <span>{{ $t('debugger.positiveNum') }}
  104. {{ statistics.overall_pos_zero_count===undefined?'--':statistics.overall_pos_zero_count }}</span>
  105. </div>
  106. </div>
  107. <div class="deb-con-slide">
  108. <div class="deb-con-slide-right">
  109. <el-button size="mini"
  110. class="custom-btn"
  111. :class="{green:gridType==='value'}"
  112. :disabled="state==='running'"
  113. @click="tabChange('value')">{{ $t('debugger.curStep') }}</el-button>
  114. <el-button size="mini"
  115. class="custom-btn"
  116. :class="{green:gridType==='preStep'}"
  117. :disabled="!curRowObj.has_prev_step || state==='running'"
  118. @click="tabChange('preStep')">{{ $t('debugger.preStep') }}</el-button>
  119. <el-button size="mini"
  120. class="custom-btn"
  121. :class="{green:gridType==='compare'}"
  122. :disabled="!curRowObj.has_prev_step || state==='running'"
  123. @click="tabChange('compare')">{{ $t('debugger.compareResult') }}</el-button>
  124. </div>
  125. <div class="deb-con-slide-left"
  126. v-if="gridType === 'compare'">
  127. <div class="deb-slide-title">{{ $t('debugger.tolerance') }}</div>
  128. <div class="deb-slide-width">
  129. <el-slider v-model="tolerance"
  130. :format-tooltip="formatTolenrance"
  131. @change="tensorComparisons(curRowObj,dims)"
  132. @input="toleranceInputChange()"></el-slider>
  133. </div>
  134. <div class="deb-slide-input">
  135. <el-input v-model="toleranceInput"
  136. @input="toleranceValueChange"
  137. @keyup.native.enter="tensorComparisons(curRowObj,dims)"></el-input>
  138. </div>
  139. </div>
  140. <div class="deb-con-slide-middle">
  141. MIN
  142. <div class="grident">0</div>
  143. MAX
  144. </div>
  145. </div>
  146. <div class="deb-con-table">
  147. <div class="deb-compare-wrap">
  148. <debuggerGridTable v-if="gridType==='value'"
  149. :fullData="tensorValue"
  150. :showFilterInput="showFilterInput"
  151. ref="tensorValue"
  152. gridType="value"
  153. @martixFilterChange="tensorFilterChange($event)">
  154. </debuggerGridTable>
  155. <debuggerGridTable v-else-if="gridType==='preStep'"
  156. :fullData="tensorValue"
  157. :showFilterInput="showFilterInput"
  158. ref="tensorValue"
  159. gridType="value"
  160. @martixFilterChange="tensorFilterChange($event)">
  161. </debuggerGridTable>
  162. <debuggerGridTable v-else
  163. :fullData="tensorValue"
  164. :showFilterInput="showFilterInput"
  165. ref="tensorValue"
  166. gridType="compare"
  167. @martixFilterChange="tensorFilterChange($event)">
  168. </debuggerGridTable>
  169. </div>
  170. </div>
  171. <div class="deb-graph-container">
  172. <div class="graph-title">
  173. {{$t('debugger.tensorDiagram')}}
  174. <span class="tip">
  175. <el-tooltip placement="bottom"
  176. effect="light"
  177. popper-class="legend-tip">
  178. <i class="el-icon-warning"></i>
  179. <div slot="content">
  180. <div>{{$t('debugger.selectDetail')}}</div>
  181. <div class="legend">
  182. <div class="item">
  183. {{$t('debugger.tensorTip')}}
  184. <img :src="require('@/assets/images/deb-slot.png')"
  185. alt="" />
  186. </div>
  187. <div class="item">
  188. {{$t('debugger.operator')}}
  189. <img :src="require('@/assets/images/deb-operator.png')"
  190. alt="" />
  191. </div>
  192. </div>
  193. </div>
  194. </el-tooltip>
  195. </span>
  196. </div>
  197. <div id="tensor-graph"
  198. class="deb-graph"
  199. v-if="graphShow"></div>
  200. <div class="nodata"
  201. v-else-if="!graphShow">
  202. {{ $t('public.noData') }}
  203. </div>
  204. <div class="deb-tensor-info">
  205. <div class="tensor">
  206. <div class="tensor-title">{{$t('debugger.tensorMsg')}}</div>
  207. <div class="tensor-detail">
  208. <span>{{ $t('graph.name') + $t('symbols.colon') }} {{ statistics.name }}</span>
  209. <span>{{ $t('debugger.max') }} {{ statistics.overall_max }}</span>
  210. <span>{{ $t('debugger.min') }} {{ statistics.overall_min }}</span>
  211. <span>{{ $t('debugger.mean') }} {{ statistics.overall_avg }}</span>
  212. <span>{{ $t('debugger.nan') }} {{ statistics.overall_nan_count }}</span>
  213. <span>{{ $t('debugger.negativeInf') }}
  214. {{ statistics.overall_neg_inf_count }}</span>
  215. <span>{{ $t('debugger.inf') }} {{ statistics.overall_pos_inf_count }}</span>
  216. <span>{{ $t('debugger.zero') }} {{ statistics.overall_zero_count }}</span>
  217. <span>{{ $t('debugger.negativeNum') }}
  218. {{ statistics.overall_neg_zero_count }}</span>
  219. <span>{{ $t('debugger.positiveNum') }}
  220. {{ statistics.overall_pos_zero_count }}</span>
  221. </div>
  222. </div>
  223. <div class="watch-point">
  224. <div class="watchPoint-title">{{ $t('debugger.watchList') }}</div>
  225. <div class="point-list"
  226. v-show="rightDataShow">
  227. <div v-for="(item,key) in watchPoints"
  228. :key="key">
  229. <div class="watch-judgment">
  230. <span>{{ $t('debugger.watchPoint') }}{{item.id}}</span>
  231. <span>{{ $t('symbols.colon') }}</span>
  232. <span>{{ getFormateWatchPoint(item) }}</span>
  233. </div>
  234. </div>
  235. </div>
  236. <div v-show="!rightDataShow"
  237. class="leftNoData">{{ $t('debugger.noWatchPoint') }}</div>
  238. </div>
  239. </div>
  240. </div>
  241. </div>
  242. </div>
  243. </template>
  244. <script>
  245. import RequestService from '@/services/request-service';
  246. import debuggerGridTable from './debugger-grid-table-simple.vue';
  247. import {select, selectAll, zoom} from 'd3';
  248. import {event as currentEvent} from 'd3-selection';
  249. import 'd3-graphviz';
  250. const d3 = {select, selectAll, zoom};
  251. export default {
  252. mixins: [],
  253. components: {debuggerGridTable},
  254. props: {
  255. row: {
  256. type: Object,
  257. default: () => {},
  258. },
  259. formateWatchpointParams: Function,
  260. },
  261. data() {
  262. return {
  263. leftShow: false,
  264. tensorList: [],
  265. tuningRule: '',
  266. tolerance: 0,
  267. toleranceInput: 0,
  268. showFilterInput: true,
  269. gridType: 'compare',
  270. dims: null,
  271. statisticsArr: [],
  272. tensorValue: [],
  273. loadingOption: {
  274. lock: true,
  275. text: this.$t('public.dataLoading'),
  276. spinner: 'el-icon-loading',
  277. background: 'rgba(0, 0, 0, 0.3)',
  278. },
  279. curRowObj: this.row,
  280. tensorGraphData: {},
  281. tensorGraphviz: null,
  282. selectedNode: {},
  283. statistics: {},
  284. leftDataShow: true,
  285. rightDataShow: true,
  286. tuningAdvice: [],
  287. tuningAdviceTitle: '',
  288. watchPoints: [],
  289. callbackFun: null,
  290. graphShow: true,
  291. statisticsKeys: [
  292. 'name',
  293. 'overall_avg',
  294. 'overall_count',
  295. 'overall_max',
  296. 'overall_min',
  297. 'overall_nan_count',
  298. 'overall_neg_inf_count',
  299. 'overall_neg_zero_count',
  300. 'overall_pos_inf_count',
  301. 'overall_pos_zero_count',
  302. 'overall_zero_count',
  303. ],
  304. };
  305. },
  306. computed: {
  307. state() {
  308. return this.$parent.metadata.state;
  309. },
  310. },
  311. mounted() {
  312. this.$nextTick(() => {
  313. this.callbackFun = this.debounce(this.resizeCallback, 200);
  314. window.addEventListener('resize', this.callbackFun);
  315. this.init();
  316. });
  317. },
  318. methods: {
  319. init() {
  320. if (this.curRowObj.type === 'value') {
  321. this.gridType = 'value';
  322. this.viewValueDetail(this.curRowObj);
  323. } else {
  324. this.gridType = 'compare';
  325. this.tensorComparisons(this.curRowObj);
  326. }
  327. this.getTensorGraphData(true);
  328. this.getTensorHitsData();
  329. },
  330. getTensorGraphData(initPage) {
  331. const params = {
  332. tensor_name: this.curRowObj.name,
  333. graph_name: this.curRowObj.graph_name,
  334. };
  335. RequestService.getTensorGraphData(params).then(
  336. (res) => {
  337. if (res && res.data && res.data.graph && res.data.graph.nodes && res.data.graph.nodes.length) {
  338. this.graphShow = true;
  339. const nodes = JSON.parse(JSON.stringify(res.data.graph.nodes));
  340. this.tensorGraphData = {};
  341. nodes.forEach((node) => {
  342. this.tensorGraphData[node.name] = {...node, type: 'node'};
  343. if (node.slots && node.slots.length) {
  344. node.slots.forEach((slot) => {
  345. const obj = {
  346. ...slot,
  347. name: `${node.name}:${slot.slot}`,
  348. graph_name: node.graph_name,
  349. type: 'slot',
  350. };
  351. this.tensorGraphData[obj.name] = obj;
  352. });
  353. }
  354. });
  355. if (initPage) {
  356. this.selectedNode.name = this.curRowObj.name;
  357. const dot = this.packageData();
  358. this.initGraph(dot);
  359. } else {
  360. if (this.selectedNode.name) {
  361. this.setNodeData();
  362. }
  363. }
  364. } else {
  365. this.graphShow = false;
  366. this.rightDataShow = false;
  367. this.statisticsKeys.forEach((key) => {
  368. this.statistics[key] = '--';
  369. });
  370. }
  371. },
  372. (err) => {
  373. this.graphShow = false;
  374. this.statisticsKeys.forEach((key) => {
  375. this.statistics[key] = '--';
  376. });
  377. },
  378. );
  379. },
  380. updateGraphData(graphName, tensorName) {
  381. if (graphName === this.curRowObj.graph_name && tensorName === this.curRowObj.name) {
  382. this.getTensorGraphData(false);
  383. }
  384. },
  385. getTensorHitsData() {
  386. const params = {
  387. tensor_name: this.curRowObj.name,
  388. graph_name: this.curRowObj.graph_name,
  389. };
  390. RequestService.tensorHitsData(params).then(
  391. (res) => {
  392. if (res && res.data && res.data.watch_points && res.data.watch_points.length) {
  393. this.leftDataShow = true;
  394. this.tensorList = res.data.watch_points.map((val) => {
  395. return {
  396. id: val.id,
  397. condition: val.watch_condition.id,
  398. params: val.watch_condition.params || [],
  399. selected: false,
  400. tip:
  401. val.error_list && val.error_list.length
  402. ? val.error_list
  403. .map((i) => {
  404. return this.$t('debugger.checkTips')[i];
  405. })
  406. .join('') + this.$t('debugger.checkTips').cannotCheck
  407. : '',
  408. };
  409. });
  410. const tensorAdvice = this.$t(`debugger.tensorTuningAdvice`);
  411. this.tensorList.forEach((item) => {
  412. const tuning = tensorAdvice[item.condition];
  413. if (!tuning) {
  414. item.tuningAdviceTitle = this.$t(`debugger.noAdvice`);
  415. } else {
  416. item.tuningAdviceTitle = tuning[1];
  417. item.tuningAdvice = tuning[2];
  418. }
  419. this.formateWatchpointParams(item.params);
  420. });
  421. } else {
  422. this.leftDataShow = false;
  423. }
  424. },
  425. (error) => {
  426. this.leftDataShow = false;
  427. this.$parent.showErrorMsg(error);
  428. },
  429. );
  430. },
  431. getFormateWatchPoint(item) {
  432. let param = '';
  433. if (item.params && item.params.length) {
  434. this.formateWatchpointParams(item.params);
  435. param = item.params.map((i) => i.content).join('; ');
  436. }
  437. return `${this.$parent.transCondition(item.condition)} (${param})`;
  438. },
  439. packageData() {
  440. let nodeStr = '';
  441. let edgeStr = '';
  442. const edges = [];
  443. Object.keys(this.tensorGraphData).forEach((key) => {
  444. const node = this.tensorGraphData[key];
  445. if (node.type === 'node') {
  446. nodeStr += `<${node.name}>[id="${node.name}";label="${node.name
  447. .split('/')
  448. .pop()}";shape="ellipse";class="operator"];`;
  449. }
  450. if (node.slots && node.slots.length) {
  451. nodeStr += this.packageSubGraph(node);
  452. }
  453. if (node.input) {
  454. Object.keys(node.input).forEach((key) => {
  455. const list = node.input[key].slot_mapping;
  456. if (list && list.length) {
  457. list.forEach((map) => {
  458. if (map && map.length) {
  459. edges.push({
  460. source: `${key}:${map[0]}`,
  461. target: `outputOf${key}_slots`,
  462. count: 1,
  463. });
  464. edges.push({
  465. source: `outputOf${key}_slots`,
  466. target: `${node.name}`,
  467. count: 1,
  468. });
  469. }
  470. });
  471. }
  472. });
  473. }
  474. });
  475. this.$parent.uniqueEdges(edges);
  476. edges.forEach((edge) => {
  477. edgeStr +=
  478. `<${edge.source}>-><${edge.target}>[id="${edge.source}->${edge.target}";` +
  479. `label="${edge.count > 1 ? edge.count + 'tensor' : ''}"]`;
  480. });
  481. const initSetting = 'node[style="filled";fontsize="10px"];edge[fontsize="6px";];';
  482. return `digraph {compound=true;rankdir=TB;${initSetting}${nodeStr}${edgeStr}}`;
  483. },
  484. /**
  485. * Encapsulates the data of a subgraph.
  486. * @param {Array} node Node data.
  487. * @return {String} Dot string
  488. */
  489. packageSubGraph(node) {
  490. const slots = node.slots;
  491. const name = node.name;
  492. const subGraphInput = `inputOf${node.name}_slots`;
  493. const subGraphOutput = `outputOf${node.name}_slots`;
  494. let strTemp = '';
  495. let nodeStr = '';
  496. let edgeStr = '';
  497. const clusterName = `cluster_${name}_slots`;
  498. nodeStr +=
  499. `{rank=min;<${subGraphInput}>[shape="circle";` +
  500. `id="${subGraphInput}";width=0.02;fixedsize=true;` +
  501. `label=""]};`;
  502. edgeStr += `<${name}>-><${subGraphInput}>[id="${name}->${subGraphInput}";label="${slots.length}tensor"]`;
  503. const outputKeys = Object.keys(node.output || {});
  504. if (outputKeys.length) {
  505. nodeStr +=
  506. `{rank=max;<${subGraphOutput}>[shape="circle";` +
  507. `id="${subGraphOutput}";width=0.02;fixedsize=true;` +
  508. `label=""]};`;
  509. }
  510. slots.forEach((slot) => {
  511. const slotName = `${name}:${slot.slot}`;
  512. nodeStr +=
  513. `<${slotName}>[id="${slotName}";label="slot:${slot.slot}${this.getSlotWatchPointsAbbr(slot)}";` +
  514. `shape="polygon";class="slot${
  515. slotName === this.curRowObj.name ? ' current selected' : ''
  516. }";fillcolor="#c5e0b3"];`;
  517. edgeStr += `<${subGraphInput}>-><${slotName}>[id="${subGraphInput}->${slotName}"];`;
  518. });
  519. strTemp =
  520. `subgraph <${clusterName}>{style="filled";id="${name}_slots";` +
  521. `label="";fillcolor="#ffffff";${nodeStr}};${edgeStr}`;
  522. return strTemp;
  523. },
  524. getSlotWatchPointsAbbr(slot) {
  525. let abbrStr = '';
  526. if (slot && slot.watch_points && slot.watch_points.length) {
  527. let list = [];
  528. slot.watch_points.forEach((hit) => {
  529. if (hit.watch_condition && hit.watch_condition.abbr) {
  530. list.push(hit.watch_condition.abbr);
  531. }
  532. });
  533. list = Array.from(new Set(list));
  534. abbrStr = `[${list.join()}]`;
  535. }
  536. return abbrStr;
  537. },
  538. /**
  539. * Initializing the dataset graph
  540. * @param {String} dot Dot statement encapsulated in graph data
  541. */
  542. initGraph(dot) {
  543. try {
  544. this.tensorGraphviz = d3
  545. .select('#tensor-graph')
  546. .graphviz({useWorker: false})
  547. .dot(dot)
  548. .attributer(this.$parent.attributer)
  549. .render(this.startApp);
  550. } catch (error) {
  551. const svg = document.querySelector('#tensor-graph svg');
  552. if (svg) {
  553. svg.remove();
  554. }
  555. this.initGraph(dot);
  556. }
  557. },
  558. startApp() {
  559. setTimeout(() => {
  560. if (this.tensorGraphviz) {
  561. this.tensorGraphviz._data = null;
  562. this.tensorGraphviz._dictionary = null;
  563. this.tensorGraphviz = null;
  564. }
  565. }, 100);
  566. const graphDom = d3.select('#tensor-graph');
  567. graphDom.selectAll('title').remove();
  568. this.initZooming();
  569. const nodes = graphDom.selectAll('.node');
  570. nodes.on('click', (target, index, nodesList) => {
  571. const event = currentEvent;
  572. event.stopPropagation();
  573. event.preventDefault();
  574. this.selectedNode.name = nodesList[index].id;
  575. this.setNodeData();
  576. });
  577. const slots = graphDom.selectAll('.node.slot');
  578. slots.on('dblclick', (target, index, nodesList) => {
  579. const event = currentEvent;
  580. event.stopPropagation();
  581. event.preventDefault();
  582. const selectedNode = nodesList[index];
  583. if (selectedNode.id !== this.curRowObj.name) {
  584. const data = this.tensorGraphData[selectedNode.id];
  585. this.curRowObj.name = data.name;
  586. this.curRowObj.full_name = data.full_name;
  587. this.curRowObj.graph_name = data.graph_name;
  588. this.curRowObj.has_prev_step = data.has_prev_step;
  589. this.curRowObj.type = 'value';
  590. this.curRowObj.shape = JSON.stringify(data.shape || []);
  591. nodes.on('click', null);
  592. nodes.on('dblclick', null);
  593. this.resetTensor();
  594. }
  595. });
  596. if (this.selectedNode.name) {
  597. this.setNodeData();
  598. }
  599. },
  600. /**
  601. * Initializing the Zoom Function of a Graph
  602. */
  603. initZooming() {
  604. const svgDom = document.querySelector('#tensor-graph svg');
  605. const svgRect = svgDom.getBoundingClientRect();
  606. const graphDom = document.querySelector('#tensor-graph #graph0');
  607. const graphBox = graphDom.getBBox();
  608. const graphRect = graphDom.getBoundingClientRect();
  609. let graphTransform = {};
  610. const minScale = Math.min(svgRect.width / 2 / graphRect.width, svgRect.height / 2 / graphRect.height);
  611. const padding = 4;
  612. const minDistance = 50;
  613. const pointer = {start: {x: 0, y: 0}, end: {x: 0, y: 0}};
  614. const zoom = d3
  615. .zoom()
  616. .on('start', () => {
  617. const event = currentEvent.sourceEvent;
  618. if (!event) {
  619. return;
  620. }
  621. pointer.start.x = event.x;
  622. pointer.start.y = event.y;
  623. })
  624. .on('zoom', () => {
  625. const event = currentEvent.sourceEvent;
  626. if (!event) {
  627. return;
  628. }
  629. const transformData = this.$parent.getTransformData(graphDom);
  630. if (!Object.keys(graphTransform).length) {
  631. graphTransform = {
  632. x: transformData.translate[0],
  633. y: transformData.translate[1],
  634. k: transformData.scale[0],
  635. };
  636. }
  637. let tempStr = '';
  638. let change = {};
  639. let scale = transformData.scale[0];
  640. const graphRect = graphDom.getBoundingClientRect();
  641. const transRate = graphBox.width / graphRect.width;
  642. if (event.type === 'mousemove') {
  643. pointer.end.x = event.x;
  644. pointer.end.y = event.y;
  645. let tempX = pointer.end.x - pointer.start.x;
  646. let tempY = pointer.end.y - pointer.start.y;
  647. const paddingTrans = Math.max((padding / transRate) * scale, minDistance);
  648. if (graphRect.left + paddingTrans + tempX >= svgRect.left + svgRect.width) {
  649. tempX = Math.min(tempX, 0);
  650. }
  651. if (graphRect.left + graphRect.width - paddingTrans + tempX <= svgRect.left) {
  652. tempX = Math.max(tempX, 0);
  653. }
  654. if (graphRect.top + paddingTrans + tempY >= svgRect.top + svgRect.height) {
  655. tempY = Math.min(tempY, 0);
  656. }
  657. if (graphRect.top + graphRect.height - paddingTrans + tempY <= svgRect.top) {
  658. tempY = Math.max(tempY, 0);
  659. }
  660. change = {
  661. x: tempX * transRate * scale,
  662. y: tempY * transRate * scale,
  663. };
  664. pointer.start.x = pointer.end.x;
  665. pointer.start.y = pointer.end.y;
  666. } else if (event.type === 'wheel') {
  667. const wheelDelta = -event.deltaY;
  668. const rate = 1.2;
  669. scale = wheelDelta > 0 ? transformData.scale[0] * rate : transformData.scale[0] / rate;
  670. scale = Math.max(this.$parent.scaleRange[0], scale, minScale);
  671. scale = Math.min(this.$parent.scaleRange[1], scale);
  672. change = {
  673. x: (graphRect.x + padding / transRate - event.x) * transRate * (scale - transformData.scale[0]),
  674. y: (graphRect.bottom - padding / transRate - event.y) * transRate * (scale - transformData.scale[0]),
  675. };
  676. }
  677. graphTransform = {
  678. x: transformData.translate[0] + change.x,
  679. y: transformData.translate[1] + change.y,
  680. k: scale,
  681. };
  682. tempStr = `translate(${graphTransform.x},${graphTransform.y}) scale(${graphTransform.k})`;
  683. graphDom.setAttribute('transform', tempStr);
  684. event.stopPropagation();
  685. event.preventDefault();
  686. });
  687. const svg = d3.select('#tensor-graph svg');
  688. svg.on('.zoom', null);
  689. svg.call(zoom);
  690. svg.on('dblclick.zoom', null);
  691. svg.on('wheel.zoom', null);
  692. const graph0 = d3.select('#tensor-graph #graph0');
  693. graph0.on('.zoom', null);
  694. graph0.call(zoom);
  695. },
  696. setNodeData() {
  697. window.getSelection().removeAllRanges();
  698. const selectedNode = document.querySelector(`#tensor-graph g[id="${this.selectedNode.name}"]`);
  699. d3.selectAll('#tensor-graph .node').classed('selected', false);
  700. selectedNode.classList.add('selected');
  701. d3.selectAll('#tensor-graph .edge').classed('selected', false);
  702. this.selectedNode = JSON.parse(JSON.stringify(this.tensorGraphData[this.selectedNode.name]));
  703. if (this.selectedNode.type === 'slot') {
  704. if (!(this.selectedNode.statistics && Object.keys(this.selectedNode.statistics).length)) {
  705. this.statisticsKeys.forEach((key) => {
  706. this.statistics[key] = '--';
  707. });
  708. } else {
  709. this.statistics = JSON.parse(JSON.stringify(this.selectedNode.statistics));
  710. }
  711. this.statistics.name = JSON.parse(JSON.stringify(this.selectedNode.name));
  712. if (this.selectedNode.watch_points && this.selectedNode.watch_points.length) {
  713. this.watchPoints = this.selectedNode.watch_points.map((val) => {
  714. return {
  715. id: val.id,
  716. condition: val.watch_condition.id,
  717. params: val.watch_condition.params || [],
  718. selected: false,
  719. };
  720. });
  721. this.rightDataShow = true;
  722. } else {
  723. this.rightDataShow = false;
  724. }
  725. } else {
  726. this.statisticsKeys.forEach((key) => {
  727. this.statistics[key] = '--';
  728. });
  729. this.rightDataShow = false;
  730. this.highLightEdges();
  731. }
  732. this.$forceUpdate();
  733. },
  734. highLightEdges() {
  735. const edges = [];
  736. const input = this.selectedNode.input || {};
  737. const inputKeys = Object.keys(input);
  738. if (inputKeys.length) {
  739. inputKeys.forEach((key) => {
  740. const mapping = input[key].slot_mapping;
  741. if (mapping && mapping.length) {
  742. mapping.forEach((map) => {
  743. if (map && map.length) {
  744. edges.push(`${key}:${map[0]}->outputOf${key}_slots`);
  745. edges.push(`outputOf${key}_slots->${this.selectedNode.name}`);
  746. }
  747. });
  748. }
  749. });
  750. }
  751. const slots = this.selectedNode.slots || [];
  752. if (slots.length) {
  753. edges.push(`${this.selectedNode.name}->inputOf${this.selectedNode.name}_slots`);
  754. slots.forEach((slot) => {
  755. edges.push(`inputOf${this.selectedNode.name}_slots->${this.selectedNode.name}:${slot.slot}`);
  756. });
  757. }
  758. edges.forEach((edge) => {
  759. d3.select(`#tensor-graph g[id="${edge}"]`).classed('selected', true);
  760. });
  761. },
  762. resetTensor() {
  763. const svg = document.querySelector('#tensor-graph svg');
  764. if (svg) {
  765. svg.remove();
  766. }
  767. const grideTable = this.$refs.tensorValue;
  768. if (grideTable) {
  769. grideTable.updateGridData(true, [], {}, '[0,0,:,:]');
  770. }
  771. this.tensorGraphData = {};
  772. this.init();
  773. },
  774. closeTensor() {
  775. this.$emit('close', this.selectedNode.name, this.curRowObj.graph_name);
  776. },
  777. /**
  778. * Collaspe btn click function
  779. */
  780. collapseBtnClick() {
  781. this.leftShow = !this.leftShow;
  782. setTimeout(() => {
  783. this.resizeCallback();
  784. }, 500);
  785. },
  786. /**
  787. * Resize callback function
  788. */
  789. resizeCallback() {
  790. this.initZooming();
  791. if (this.$refs.tensorValue) {
  792. this.$refs.tensorValue.resizeView();
  793. }
  794. },
  795. /**
  796. * Anti-shake
  797. * @param { Function } fn callback function
  798. * @param { Number } delay delay time
  799. * @return { Function }
  800. */
  801. debounce(fn, delay) {
  802. let timer = null;
  803. return function() {
  804. if (timer) {
  805. clearTimeout(timer);
  806. }
  807. timer = setTimeout(fn, delay);
  808. };
  809. },
  810. toleranceInputChange() {
  811. this.toleranceInput = this.tolerance;
  812. },
  813. toleranceValueChange(val) {
  814. val = val.replace(/[^0-9]+/g, '');
  815. if (Number(val) === 0) {
  816. this.toleranceInput = 0;
  817. this.tolerance = 0;
  818. }
  819. if (Number(val) < 0) {
  820. this.tolerance = 0;
  821. this.toleranceInput = 0;
  822. }
  823. if (Number(val) > 0) {
  824. if (Number(val) > 100) {
  825. this.tolerance = 100;
  826. this.toleranceInput = 100;
  827. } else {
  828. this.tolerance = Number(val);
  829. this.toleranceInput = Number(val);
  830. }
  831. }
  832. },
  833. formatTolenrance(value) {
  834. return `${value}%`;
  835. },
  836. /**
  837. * Tabs change
  838. * @param {String} gridType tab type
  839. */
  840. tabChange(gridType) {
  841. this.gridType = gridType;
  842. if (this.gridType === 'compare') {
  843. this.tensorComparisons(this.curRowObj, this.dims);
  844. } else {
  845. this.viewValueDetail(this.curRowObj, this.dims);
  846. }
  847. },
  848. /**
  849. * Query tensor Comparison data
  850. * @param { Object } row current clickd tensor value data
  851. * @param { Object } dims dims
  852. */
  853. tensorComparisons(row, dims) {
  854. const shape = dims
  855. ? dims
  856. : JSON.stringify(
  857. JSON.parse(row.shape)
  858. .map((val, index) => {
  859. // The default parameter format of shape is that the last two digits are:. The front is all 0
  860. if (index < 2) {
  861. return ':';
  862. } else {
  863. return 0;
  864. }
  865. })
  866. .reverse(),
  867. ).replace(/"/g, '');
  868. const params = {
  869. name: row.name,
  870. detail: 'data',
  871. shape,
  872. tolerance: this.tolerance / 100,
  873. graph_name: row.graph_name,
  874. };
  875. const loadingInstance = this.$loading(this.loadingOption);
  876. RequestService.tensorComparisons(params).then(
  877. (res) => {
  878. loadingInstance.close();
  879. if (res && res.data && res.data.tensor_value) {
  880. if (row.shape === '[]') {
  881. this.showFilterInput = false;
  882. } else {
  883. this.showFilterInput = true;
  884. }
  885. const tensorValue = res.data.tensor_value;
  886. const statistics = tensorValue.statistics || {};
  887. this.statisticsArr = [
  888. tensorValue.curr_step_statistics || {},
  889. tensorValue.prev_step_statistics || {},
  890. tensorValue.statistics || {},
  891. ];
  892. if (tensorValue.diff === 'Too large to show.') {
  893. this.tensorValue = [];
  894. this.$nextTick(() => {
  895. this.$refs.tensorValue.showRequestErrorMessage(
  896. this.$t('debugger.largeDataTip'),
  897. JSON.parse(row.shape),
  898. shape,
  899. true,
  900. );
  901. });
  902. return;
  903. }
  904. this.tensorValue = tensorValue.diff;
  905. if (this.tensorValue && this.tensorValue instanceof Array && !(this.tensorValue[0] instanceof Array)) {
  906. this.tensorValue = [this.tensorValue];
  907. }
  908. this.$nextTick(() => {
  909. this.$refs.tensorValue.updateGridData(this.tensorValue, JSON.parse(row.shape), statistics, shape);
  910. });
  911. }
  912. },
  913. (err) => {
  914. loadingInstance.close();
  915. },
  916. );
  917. },
  918. /**
  919. * Query tensor value or tensor comparison
  920. * @param {Object} data tensor value data
  921. */
  922. tensorFilterChange(data) {
  923. this.dims = `[${data.toString()}]`;
  924. if (this.gridType === 'compare') {
  925. this.tensorComparisons(this.curRowObj, this.dims);
  926. } else {
  927. this.viewValueDetail(this.curRowObj, this.dims);
  928. }
  929. },
  930. /**
  931. * Query tensor value data
  932. * @param {Object} row current row data
  933. * @param { String } dims
  934. */
  935. viewValueDetail(row, dims) {
  936. const shape = dims
  937. ? dims
  938. : JSON.stringify(
  939. JSON.parse(row.shape)
  940. .map((val, index) => {
  941. // The default parameter format of shape is that the last two digits are:. The front is all 0
  942. if (index < 2) {
  943. return ':';
  944. } else {
  945. return 0;
  946. }
  947. })
  948. .reverse(),
  949. ).replace(/"/g, '');
  950. const params = {
  951. name: row.name,
  952. detail: 'data',
  953. shape,
  954. graph_name: row.graph_name,
  955. prev: this.gridType === 'preStep' ? true : false,
  956. };
  957. const loadingInstance = this.$loading(this.loadingOption);
  958. RequestService.tensors(params).then(
  959. (res) => {
  960. loadingInstance.close();
  961. if (row.shape === '[]') {
  962. this.showFilterInput = false;
  963. } else {
  964. this.showFilterInput = true;
  965. }
  966. if (res.data.tensor_value) {
  967. let value = res.data.tensor_value.value;
  968. const statistics = res.data.tensor_value.statistics || {};
  969. this.statisticsArr = [statistics];
  970. if (value === 'Too large to show.') {
  971. this.tensorValue = [];
  972. this.$nextTick(() => {
  973. this.$refs.tensorValue.showRequestErrorMessage(
  974. this.$t('debugger.largeDataTip'),
  975. JSON.parse(row.shape),
  976. shape,
  977. true,
  978. );
  979. });
  980. return;
  981. }
  982. if (value === null) {
  983. value = 'null';
  984. }
  985. this.tensorValue = value instanceof Array ? value : [value];
  986. this.$nextTick(() => {
  987. this.$refs.tensorValue.updateGridData(this.tensorValue, JSON.parse(row.shape), statistics, shape);
  988. });
  989. }
  990. },
  991. (err) => {
  992. loadingInstance.close();
  993. this.$parent.showErrorMsg(err);
  994. },
  995. );
  996. },
  997. },
  998. destroyed() {
  999. window.removeEventListener('resize', this.callbackFun);
  1000. },
  1001. };
  1002. </script>
  1003. <style lang="scss">
  1004. .deb-tensor-wrap {
  1005. height: 100%;
  1006. background-color: white;
  1007. position: relative;
  1008. overflow: hidden;
  1009. & > div {
  1010. float: left;
  1011. height: 100%;
  1012. }
  1013. .deb-tensor-left {
  1014. width: 400px;
  1015. padding-right: 25px;
  1016. height: 100%;
  1017. background-color: white;
  1018. position: relative;
  1019. transition: width 0.2s;
  1020. -moz-transition: width 0.2s; /* Firefox 4 */
  1021. -webkit-transition: width 0.2s; /* Safari and Chrome */
  1022. -o-transition: width 0.2s; /* Opera */
  1023. .left-content-title {
  1024. padding-left: 15px;
  1025. height: 50px;
  1026. line-height: 50px;
  1027. font-weight: bold;
  1028. }
  1029. .left-advice {
  1030. overflow-y: auto;
  1031. text-overflow: ellipsis;
  1032. height: calc(100% - 50px);
  1033. }
  1034. .left-content-list {
  1035. border-top: 1px solid #f2f2f2;
  1036. padding-bottom: 10px;
  1037. > div {
  1038. padding-left: 15px;
  1039. }
  1040. .detection-judgment {
  1041. height: 40px;
  1042. line-height: 40px;
  1043. font-weight: bold;
  1044. }
  1045. .hit-tip {
  1046. padding: 10px 15px 0 15px;
  1047. .el-icon-warning {
  1048. font-size: 14px;
  1049. color: #e6a23c;
  1050. padding-right: 4px;
  1051. }
  1052. }
  1053. .reason {
  1054. display: flex;
  1055. padding: 1px 15px;
  1056. width: 100%;
  1057. }
  1058. .tensor-icon {
  1059. width: 6px;
  1060. height: 6px;
  1061. border-radius: 3px;
  1062. }
  1063. .icon-secondary {
  1064. background-color: #00a5a7;
  1065. margin-top: 8px;
  1066. }
  1067. .tensor-content {
  1068. padding-left: 6px;
  1069. width: calc(100% - 12px);
  1070. }
  1071. .tensor-value {
  1072. padding: 5px 2px;
  1073. span {
  1074. padding-right: 5px;
  1075. }
  1076. }
  1077. .tensor-advice {
  1078. width: 344px;
  1079. background-color: #f5f7fa;
  1080. margin-left: 15px;
  1081. margin-top: 10px;
  1082. padding: 10px;
  1083. span {
  1084. font-weight: bold;
  1085. }
  1086. }
  1087. .advice-list-title {
  1088. padding: 0px;
  1089. padding-top: 10px;
  1090. padding-left: 10px;
  1091. .advice-list {
  1092. padding-top: 5px;
  1093. }
  1094. .advice-icon {
  1095. width: 6px;
  1096. height: 6px;
  1097. border-radius: 3px;
  1098. background-color: #00a5a7;
  1099. display: inline-block;
  1100. }
  1101. .advice-content {
  1102. display: inline-block;
  1103. padding: 0px 12px;
  1104. height: 25px;
  1105. line-height: 25px;
  1106. }
  1107. }
  1108. }
  1109. .leftNoData {
  1110. text-align: center;
  1111. border-top: 1px solid #f2f2f2;
  1112. padding-top: 15px;
  1113. }
  1114. .collapse-btn {
  1115. position: absolute;
  1116. right: 2px;
  1117. width: 31px;
  1118. height: 100px;
  1119. top: 50%;
  1120. margin-top: -50px;
  1121. cursor: pointer;
  1122. line-height: 86px;
  1123. z-index: 1;
  1124. text-align: center;
  1125. background-image: url('../assets/images/collapse-left.svg');
  1126. }
  1127. .collapse-btn.collapse {
  1128. background-image: url('../assets/images/collapse-right.svg');
  1129. }
  1130. .deb-tensor-left-content {
  1131. height: 100%;
  1132. border-right: 1px solid #ebeef5;
  1133. overflow: auto;
  1134. }
  1135. }
  1136. .deb-tensor-left.collapse {
  1137. width: 0px;
  1138. }
  1139. .deb-tensor-right {
  1140. width: calc(100% - 400px);
  1141. height: 100%;
  1142. transition: width 0.2s;
  1143. -moz-transition: width 0.2s; /* Firefox 4 */
  1144. -webkit-transition: width 0.2s; /* Safari and Chrome */
  1145. -o-transition: width 0.2s; /* Opera */
  1146. display: flex;
  1147. flex-direction: column;
  1148. .deb-con-title {
  1149. height: 40px;
  1150. line-height: 40px;
  1151. flex-shrink: 0;
  1152. position: relative;
  1153. .deb-con-title-left {
  1154. position: absolute;
  1155. left: 0;
  1156. font-weight: bold;
  1157. font-size: 16px;
  1158. width: calc(100% - 100px);
  1159. white-space: nowrap;
  1160. overflow: hidden;
  1161. text-overflow: ellipsis;
  1162. }
  1163. .deb-con-title-right {
  1164. position: absolute;
  1165. right: 32px;
  1166. .close-btn {
  1167. width: 20px;
  1168. height: 20px;
  1169. vertical-align: -3px;
  1170. cursor: pointer;
  1171. display: inline-block;
  1172. line-height: 20px;
  1173. margin-left: 32px;
  1174. }
  1175. }
  1176. }
  1177. .deb-compare-detail {
  1178. flex-shrink: 0;
  1179. padding-right: 32px;
  1180. span {
  1181. margin-right: 10px;
  1182. padding-left: 10px;
  1183. border-left: 1px solid #e4e7ec;
  1184. }
  1185. label {
  1186. display: inline-block;
  1187. min-width: 123px;
  1188. span {
  1189. border-left: none;
  1190. }
  1191. }
  1192. }
  1193. .deb-con-slide {
  1194. height: 40px;
  1195. line-height: 40px;
  1196. flex-shrink: 0;
  1197. position: relative;
  1198. margin: 5px 0;
  1199. .deb-con-slide-left {
  1200. float: left;
  1201. display: flex;
  1202. margin-left: 10px;
  1203. .deb-slide-title {
  1204. margin-right: 20px;
  1205. }
  1206. .deb-slide-width {
  1207. width: 160px;
  1208. }
  1209. .deb-slide-input {
  1210. width: 60px;
  1211. margin-left: 10px;
  1212. }
  1213. }
  1214. .deb-con-slide-right {
  1215. float: left;
  1216. .custom-btn {
  1217. border: 1px solid #00a5a7;
  1218. border-radius: 2px;
  1219. }
  1220. .green {
  1221. background-color: #00a5a7;
  1222. color: white;
  1223. }
  1224. .white {
  1225. background-color: white;
  1226. color: #00a5a7;
  1227. }
  1228. }
  1229. .deb-con-slide-middle {
  1230. position: absolute;
  1231. right: 32px;
  1232. width: 150px;
  1233. padding: 10px 0;
  1234. line-height: 15px;
  1235. .grident {
  1236. display: inline-block;
  1237. width: calc(100% - 70px);
  1238. background-image: linear-gradient(to right, rgba(227, 125, 41), #fff, rgba(0, 165, 167));
  1239. text-align: center;
  1240. color: transparent;
  1241. border-radius: 10px;
  1242. }
  1243. }
  1244. }
  1245. .deb-con-table {
  1246. flex: 1;
  1247. flex-grow: 1;
  1248. flex-shrink: 1;
  1249. padding-right: 32px;
  1250. flex-shrink: 0;
  1251. .deb-compare-wrap {
  1252. height: 100%;
  1253. }
  1254. }
  1255. .deb-graph-container {
  1256. flex: 1;
  1257. flex-grow: 1;
  1258. flex-shrink: 1;
  1259. padding: 10px 32px 10px 0px;
  1260. position: relative;
  1261. display: flex;
  1262. overflow: hidden;
  1263. .graph-title {
  1264. position: absolute;
  1265. font-weight: bold;
  1266. font-size: 14px;
  1267. .tip {
  1268. font-size: 16px;
  1269. margin-left: 10px;
  1270. cursor: pointer;
  1271. }
  1272. }
  1273. .nodata {
  1274. width: calc(100% - 375px);
  1275. text-align: center;
  1276. margin-top: 120px;
  1277. }
  1278. .deb-graph {
  1279. width: calc(100% - 375px);
  1280. .edge {
  1281. path {
  1282. stroke: rgb(120, 120, 120);
  1283. }
  1284. polygon {
  1285. stroke: rgb(120, 120, 120);
  1286. fill: rgb(120, 120, 120);
  1287. }
  1288. }
  1289. .node.operator > ellipse {
  1290. stroke: #e3aa00;
  1291. fill: #ffe794;
  1292. }
  1293. .node.slot {
  1294. & > polygon {
  1295. stroke: #4ea6e6;
  1296. fill: #c7f5f4;
  1297. }
  1298. &.current {
  1299. & > polygon {
  1300. stroke: #4ea6e6;
  1301. fill: #00a5a7;
  1302. }
  1303. text {
  1304. fill: white;
  1305. }
  1306. }
  1307. }
  1308. .node {
  1309. &:hover {
  1310. cursor: pointer;
  1311. & > polygon,
  1312. & > ellipse {
  1313. stroke-width: 2px;
  1314. }
  1315. }
  1316. }
  1317. .cluster > polygon {
  1318. stroke: #e4e7ed;
  1319. fill: #e9fcf9;
  1320. }
  1321. .node.selected {
  1322. polygon,
  1323. ellipse {
  1324. stroke: red !important;
  1325. stroke-width: 2px;
  1326. }
  1327. }
  1328. .edge.selected {
  1329. path {
  1330. stroke: red;
  1331. }
  1332. polygon {
  1333. stroke: red;
  1334. fill: red;
  1335. }
  1336. }
  1337. }
  1338. .deb-tensor-info {
  1339. width: 375px;
  1340. height: 100%;
  1341. border-left: solid 2px #e4e7ed;
  1342. padding-left: 20px;
  1343. .tensor {
  1344. .tensor-title {
  1345. font-size: 14px;
  1346. font-weight: bold;
  1347. padding-bottom: 8px;
  1348. }
  1349. .tensor-detail {
  1350. overflow: auto;
  1351. height: calc(100% - 30px);
  1352. span {
  1353. display: inline-block;
  1354. padding: 5px 0px;
  1355. min-width: 50%;
  1356. word-break: break-all;
  1357. }
  1358. ul {
  1359. li {
  1360. padding: 5px 10px;
  1361. & > div {
  1362. display: inline-block;
  1363. vertical-align: top;
  1364. word-break: break-all;
  1365. line-height: 16px;
  1366. }
  1367. .attr-key {
  1368. width: 30%;
  1369. }
  1370. .attr-value {
  1371. width: 70%;
  1372. padding-left: 10px;
  1373. }
  1374. &:hover {
  1375. background-color: #e9fcf9;
  1376. }
  1377. }
  1378. }
  1379. }
  1380. }
  1381. .tensor {
  1382. height: 50%;
  1383. overflow: auto;
  1384. }
  1385. .watch-point {
  1386. height: 50%;
  1387. .point-list {
  1388. height: calc(100% - 35px);
  1389. overflow: auto;
  1390. text-overflow: ellipsis;
  1391. }
  1392. .watchPoint-title {
  1393. padding: 8px 0;
  1394. font-size: 14px;
  1395. font-weight: bold;
  1396. }
  1397. .watch-judgment {
  1398. padding: 5px 0;
  1399. }
  1400. }
  1401. }
  1402. }
  1403. }
  1404. .deb-tensor-right.collapse {
  1405. width: calc(100% - 25px);
  1406. }
  1407. }
  1408. .legend-tip {
  1409. .legend {
  1410. margin-top: 10px;
  1411. .item {
  1412. display: inline-block;
  1413. width: 50%;
  1414. img {
  1415. vertical-align: sub;
  1416. height: 20px;
  1417. margin-left: 10px;
  1418. }
  1419. }
  1420. }
  1421. }
  1422. </style>