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 50 kB

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