From 7b5264ed29a92d55bd972a4429a134a0120c23f1 Mon Sep 17 00:00:00 2001 From: Shanqing Cai Date: Sun, 12 Apr 2020 13:02:31 -0400 Subject: [PATCH 1/4] [DebuggerV2] Add basic store support and component for graph execution --- .../debugger_v2/tf_debugger_v2_plugin/BUILD | 2 + .../actions/debugger_actions.ts | 18 ++- .../data_source/tfdbg2_data_source.ts | 104 ++++++++++++++ .../debugger_component.css | 17 ++- .../debugger_component.ng.html | 3 +- .../debugger_container_test.ts | 2 + .../tf_debugger_v2_plugin/debugger_module.ts | 2 + .../store/debugger_reducers.ts | 127 +++++++++++++++--- .../store/debugger_reducers_test.ts | 45 ++++++- .../store/debugger_selectors.ts | 22 +++ .../store/debugger_selectors_test.ts | 67 +++++++++ .../store/debugger_types.ts | 76 ++++++++++- .../tf_debugger_v2_plugin/testing/BUILD | 1 + .../tf_debugger_v2_plugin/testing/index.ts | 32 ++--- .../tf_debugger_v2_plugin/views/alerts/BUILD | 1 + .../views/alerts/alerts_container_test.ts | 2 + .../views/graph_executions/BUILD | 28 ++++ .../graph_executions_component.css | 24 ++++ .../graph_executions_component.ng.html | 22 +++ .../graph_executions_component.ts | 28 ++++ .../graph_executions_container.ts | 35 +++++ .../graph_executions_module.ts | 27 ++++ .../views/source_files/BUILD | 1 + .../source_files_container_test.ts | 2 + .../stack_trace/stack_trace_component.css | 3 +- 25 files changed, 636 insertions(+), 55 deletions(-) create mode 100644 tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/BUILD create mode 100644 tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.css create mode 100644 tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ng.html create mode 100644 tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ts create mode 100644 tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_container.ts create mode 100644 tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_module.ts diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/BUILD index 98f679c7be..4c429e9799 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/BUILD +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/BUILD @@ -26,6 +26,7 @@ ng_module( "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store:types", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/inactive", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace", @@ -54,6 +55,7 @@ tf_ts_library( "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/inactive", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace", diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/actions/debugger_actions.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/actions/debugger_actions.ts index a460900baa..0e04b595cc 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/actions/debugger_actions.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/actions/debugger_actions.ts @@ -89,14 +89,14 @@ export const alertTypeFocusToggled = createAction( ); /** - * Actions for the Timeline Component. + * Actions related to top-level (eager) execution */ export const numExecutionsRequested = createAction( - '[Debugger] Number of Executions Requested' + '[Debugger] Number of Top-Level Executions Requested' ); export const numExecutionsLoaded = createAction( - '[Debugger] Number of Executions Loaded', + '[Debugger] Number of Top-Level Executions Loaded', props<{numExecutions: number}>() ); @@ -132,6 +132,18 @@ export const executionDataLoaded = createAction( props() ); +/** + * Actions related to intra-graph execution + */ +export const numGraphExecutionsRequested = createAction( + '[Debugger] Number of Intra-Graph Executions Requested' +); + +export const numGraphExecutionsLoaded = createAction( + '[Debugger] Number of Intra-Graph Executions Loaded', + props<{numGraphExecutions: number}>() +); + export const sourceFileListRequested = createAction( '[Debugger] Source File List Requested.' ); diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/data_source/tfdbg2_data_source.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/data_source/tfdbg2_data_source.ts index 54c06a26d1..e76b443f69 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/data_source/tfdbg2_data_source.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/data_source/tfdbg2_data_source.ts @@ -19,6 +19,8 @@ import { DebuggerRunListing, Execution, ExecutionDigest, + GraphExecution, + GraphExecutionDigest, SourceFileSpec, StackFrame, } from '../store/debugger_types'; @@ -39,6 +41,10 @@ export interface StackFramesResponse { stack_frames: StackFrame[]; } +/** + * Response types related to top-level (eager) execution. + */ + export interface ExecutionDigestsResponse { begin: number; @@ -57,6 +63,32 @@ export interface ExecutionDataResponse { executions: Execution[]; } +/** + * Response types related to intra-graph execution. + */ + +export interface GraphExecutionDigestsResponse { + begin: number; + + end: number; + + num_digests: number; + + graph_execution_digests: GraphExecutionDigest[]; +} + +export interface GraphExecutionDataResponse { + begin: number; + + end: number; + + graph_executions: GraphExecution[]; +} + +/** + * Response types related to alerts. + */ + export interface AlertsResponse { begin: number; @@ -76,18 +108,44 @@ export interface AlertsResponse { export abstract class Tfdbg2DataSource { abstract fetchRuns(): Observable; + /** + * Fetch the digest objects for top-level executions. + */ abstract fetchExecutionDigests( run: string, begin: number, end: number ): Observable; + /** + * Fetch the detailed data objects for top-level executions. + */ abstract fetchExecutionData( run: string, begin: number, end: number ): Observable; + /** + * Fetch the digest objects for intra-graph executions. + */ + abstract fetchGraphExecutionDigests( + run: string, + begin: number, + end: number, + trace_id?: string + ): Observable; + + /** + * Fetch the detailed data objects for top-level executions. + */ + abstract fetchGraphExecutionData( + run: string, + begin: number, + end: number, + trace_id?: string + ): Observable; + /** * Fetch the list of source-code files that the debugged program involves. * @@ -171,6 +229,52 @@ export class Tfdbg2HttpServerDataSource implements Tfdbg2DataSource { ); } + fetchGraphExecutionDigests( + run: string, + begin: number, + end: number, + trace_id?: string + ) { + if (trace_id !== undefined) { + throw new Error( + 'trace_id is not implemented for fetchGraphExecutionDigests() yet' + ); + } + return this.http.get( + this.httpPathPrefix + '/graph_execution/digests', + { + params: { + run, + begin: String(begin), + end: String(end), + }, + } + ); + } + + fetchGraphExecutionData( + run: string, + begin: number, + end: number, + trace_id?: string + ) { + if (trace_id !== undefined) { + throw new Error( + 'trace_id is not implemented for fetchGraphExecutionData() yet' + ); + } + return this.http.get( + this.httpPathPrefix + '/graph_execution/data', + { + params: { + run, + begin: String(begin), + end: String(end), + }, + } + ); + } + fetchSourceFileList(run: string): Observable { return this.http.get( this.httpPathPrefix + '/source_files/list', diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_component.css b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_component.css index 87021399bf..294d74fa4c 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_component.css +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_component.css @@ -21,14 +21,23 @@ limitations under the License. } .top-section { + height: 360px; + padding: 6px 0; width: 100%; } tf-debugger-v2-alerts { display: inline-block; - height: 360px; + height: 100%; vertical-align: top; - width: 200px; + width: 15%; +} + +tf-debugger-v2-graph-executions { + display: inline-block; + height: 100%; + vertical-align: top; + width: 30%; } tf-debugger-v2-source-files { @@ -45,7 +54,7 @@ tf-debugger-v2-stack-trace { tf-debugger-v2-timeline { display: inline-block; - height: 360px; + height: 100%; vertical-align: top; - width: 800px; + width: 55%; } diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_component.ng.html b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_component.ng.html index 08f1a79c0a..922caabc46 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_component.ng.html +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_component.ng.html @@ -23,12 +23,13 @@
+
- + diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_container_test.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_container_test.ts index eb9c49cdec..51949f4e50 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_container_test.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_container_test.ts @@ -49,6 +49,7 @@ import { import {AlertsModule} from './views/alerts/alerts_module'; import {ExecutionDataContainer} from './views/execution_data/execution_data_container'; import {ExecutionDataModule} from './views/execution_data/execution_data_module'; +import {GraphExecutionsModule} from './views/graph_executions/graph_executions_module'; import {InactiveModule} from './views/inactive/inactive_module'; import {TimelineContainer} from './views/timeline/timeline_container'; import {SourceFilesModule} from './views/source_files/source_files_module'; @@ -69,6 +70,7 @@ describe('Debugger Container', () => { AlertsModule, CommonModule, ExecutionDataModule, + GraphExecutionsModule, InactiveModule, SourceFilesModule, StackTraceModule, diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_module.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_module.ts index fa7881984c..604639a981 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_module.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_module.ts @@ -25,6 +25,7 @@ import {DebuggerEffects} from './effects'; import {reducers} from './store/debugger_reducers'; import {DEBUGGER_FEATURE_KEY} from './store/debugger_types'; import {AlertsModule} from './views/alerts/alerts_module'; +import {GraphExecutionsModule} from './views/graph_executions/graph_executions_module'; import {InactiveModule} from './views/inactive/inactive_module'; import {SourceFilesModule} from './views/source_files/source_files_module'; import {StackTraceModule} from './views/stack_trace/stack_trace_module'; @@ -36,6 +37,7 @@ import {PluginRegistryModule} from '../../../webapp/plugins/plugin_registry_modu imports: [ AlertsModule, CommonModule, + GraphExecutionsModule, InactiveModule, SourceFilesModule, StackTraceModule, diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_reducers.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_reducers.ts index d01d32dbe9..913c9eabe4 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_reducers.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_reducers.ts @@ -18,6 +18,7 @@ import * as actions from '../actions'; import { ExecutionDataResponse, ExecutionDigestsResponse, + GraphExecutionDigestsResponse, SourceFileResponse, } from '../data_source/tfdbg2_data_source'; import {findFileIndex} from './debugger_store_utils'; @@ -26,10 +27,11 @@ import { AlertType, DataLoadState, DebuggerState, + Executions, + GraphExecutions, InfNanAlert, StackFramesById, SourceFileSpec, - SourceLineSpec, } from './debugger_types'; // HACK: These imports are for type inference. @@ -37,6 +39,53 @@ import { /** @typehack */ import * as _typeHackStore from '@ngrx/store/store'; const DEFAULT_EXECUTION_PAGE_SIZE = 100; +const DEFAULT_GRAPH_EXECUTION_PAGE_SIZE = 100; + +export function createInitialExecutionsState(): Executions { + return { + numExecutionsLoaded: { + state: DataLoadState.NOT_LOADED, + lastLoadedTimeInMs: null, + }, + executionDigestsLoaded: { + state: DataLoadState.NOT_LOADED, + lastLoadedTimeInMs: null, + numExecutions: 0, + pageLoadedSizes: {}, + }, + // TODO(cais) Remove the hardcoding of this, which is coupled with css width + // properties. + displayCount: 50, + pageSize: DEFAULT_EXECUTION_PAGE_SIZE, + scrollBeginIndex: 0, + focusIndex: null, + executionDigests: {}, + executionData: {}, + }; +} + +export function createInitialGraphExecutionsState(): GraphExecutions { + return { + numExecutionsLoaded: { + state: DataLoadState.NOT_LOADED, + lastLoadedTimeInMs: null, + }, + executionDigestsLoaded: { + state: DataLoadState.NOT_LOADED, + lastLoadedTimeInMs: null, + numExecutions: 0, + pageLoadedSizes: {}, + }, + // TODO(cais) Remove the hardcoding of this, which is coupled with css width + // properties. + displayCount: 50, + pageSize: DEFAULT_GRAPH_EXECUTION_PAGE_SIZE, + scrollBeginIndex: 0, + focusIndex: null, + graphExecutionDigests: {}, + graphExecutionData: {}, + }; +} const initialState: DebuggerState = { runs: {}, @@ -56,26 +105,8 @@ const initialState: DebuggerState = { executionIndices: {}, focusType: null, }, - executions: { - numExecutionsLoaded: { - state: DataLoadState.NOT_LOADED, - lastLoadedTimeInMs: null, - }, - executionDigestsLoaded: { - numExecutions: 0, - pageLoadedSizes: {}, - state: DataLoadState.NOT_LOADED, - lastLoadedTimeInMs: null, - }, - scrollBeginIndex: 0, - focusIndex: null, - pageSize: DEFAULT_EXECUTION_PAGE_SIZE, - // TODO(cais) Remove the hardcoding of this, which is coupled with css width - // properties. - displayCount: 50, - executionDigests: {}, - executionData: {}, - }, + executions: createInitialExecutionsState(), + graphExecutions: createInitialGraphExecutionsState(), stackFrames: {}, sourceCode: { sourceFileListLoaded: { @@ -272,6 +303,9 @@ const reducer = createReducer( return newState; } ), + ////////////////////////////////////////////// + // Reducers related to top-level execution. // + ////////////////////////////////////////////// on( actions.numExecutionsRequested, (state: DebuggerState): DebuggerState => { @@ -482,6 +516,57 @@ const reducer = createReducer( return newState; } ), + //////////////////////////////////////////////// + // Reducers related to intra-graph execution. // + //////////////////////////////////////////////// + on( + actions.numGraphExecutionsRequested, + (state: DebuggerState): DebuggerState => { + if (state.activeRunId === null) { + return state; + } + return { + ...state, + graphExecutions: { + ...state.graphExecutions, + numExecutionsLoaded: { + ...state.graphExecutions.numExecutionsLoaded, + state: DataLoadState.LOADING, + }, + }, + }; + } + ), + on( + actions.numGraphExecutionsLoaded, + (state: DebuggerState, {numGraphExecutions}): DebuggerState => { + if (state.activeRunId === null) { + return state; + } + const newState = { + ...state, + graphExecutions: { + ...state.graphExecutions, + numExecutionsLoaded: { + ...state.graphExecutions.numExecutionsLoaded, + state: DataLoadState.LOADED, + lastLoadedTimeInMs: Date.now(), + }, + executionDigestsLoaded: { + ...state.graphExecutions.executionDigestsLoaded, + numExecutions: numGraphExecutions, + }, + }, + }; + if (numGraphExecutions > 0 && state.graphExecutions.focusIndex === null) { + newState.graphExecutions.focusIndex = 0; + } + return newState; + } + ), + //////////////////////////////////////////////////////// + // Reducers related to source files and stack traces. // + //////////////////////////////////////////////////////// on( actions.sourceFileListRequested, (state: DebuggerState): DebuggerState => { diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_reducers_test.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_reducers_test.ts index c5ec5ad438..476cd196ab 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_reducers_test.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_reducers_test.ts @@ -25,6 +25,7 @@ import { import { createAlertsState, createDebuggerExecutionsState, + createDebuggerGraphExecutionsState, createDebuggerSourceCodeState, createDebuggerState, createDebuggerStateWithLoadedExecutionDigests, @@ -892,7 +893,7 @@ describe('Debugger reducers', () => { for (const scrollIndex of [-1, 0.5, 51, 100]) { it( - `Invalid executionScrollToIndex (${scrollIndex}) does not change scrollBeginIdnex:` + + `Invalid executionScrollToIndex (${scrollIndex}) does not change scrollBeginIndex:` + `displayCount < numExecutions`, () => { const originalScrollBeginIndex = 3; @@ -915,7 +916,7 @@ describe('Debugger reducers', () => { // In these tests, `displayCount` is 50 and there are only 20 execution digests // (< 50). Hence, the only valid scrolling begin index is 0. it( - `Invalid executionScrollToIndex (${scrollIndex}) does not change scrollBeginIdnex:` + + `Invalid executionScrollToIndex (${scrollIndex}) does not change scrollBeginIndex:` + `displayCount >= numExecutions`, () => { const originalScrollBeginIndex = 3; @@ -1323,4 +1324,44 @@ describe('Debugger reducers', () => { }, ]); }); + + describe('numGraphExecutionsRequested', () => { + it('updates load state', () => { + const state = createDebuggerState({ + activeRunId: '__default_debugger_run__', + }); + const nextState = reducers(state, actions.numGraphExecutionsRequested()); + expect(nextState.graphExecutions.numExecutionsLoaded.state).toBe( + DataLoadState.LOADING + ); + }); + }); + + describe('numGraphExecutionsLoaded', () => { + it('updates load state', () => { + const state = createDebuggerState({ + activeRunId: '__default_debugger_run__', + graphExecutions: createDebuggerGraphExecutionsState({ + numExecutionsLoaded: { + state: DataLoadState.LOADING, + lastLoadedTimeInMs: null, + }, + }), + }); + const t0 = Date.now(); + const nextState = reducers( + state, + actions.numGraphExecutionsLoaded({numGraphExecutions: 12345}) + ); + expect(nextState.graphExecutions.numExecutionsLoaded.state).toBe( + DataLoadState.LOADED + ); + expect( + nextState.graphExecutions.numExecutionsLoaded.lastLoadedTimeInMs + ).toBeGreaterThanOrEqual(t0); + expect( + nextState.graphExecutions.executionDigestsLoaded.numExecutions + ).toEqual(12345); + }); + }); }); diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_selectors.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_selectors.ts index 182d66b9b8..669f59656b 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_selectors.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_selectors.ts @@ -124,6 +124,10 @@ export const getAlertsBreakdown = createSelector( } ); +/** + * Selectors related to top-level (eager) execution. + */ + export const getNumExecutionsLoaded = createSelector( selectDebuggerState, (state: DebuggerState): LoadState => { @@ -186,6 +190,24 @@ export const getVisibleExecutionDigests = createSelector( } ); +/** + * Selectors related to intra-graph execution. + */ + +export const getNumGraphExecutionsLoaded = createSelector( + selectDebuggerState, + (state: DebuggerState): LoadState => { + return state.graphExecutions.numExecutionsLoaded; + } +); + +export const getNumGraphExecutions = createSelector( + selectDebuggerState, + (state: DebuggerState): number => { + return state.graphExecutions.executionDigestsLoaded.numExecutions; + } +); + /** * Get the focused alert types (if any) of the execution digests current being * displayed. For each displayed execution digest, there are two possibilities: diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_selectors_test.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_selectors_test.ts index 573defa491..5d373bce0f 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_selectors_test.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_selectors_test.ts @@ -25,6 +25,8 @@ import { getLoadedAlertsOfFocusedType, getNumAlerts, getNumAlertsOfFocusedType, + getNumGraphExecutions, + getNumGraphExecutionsLoaded, getFocusAlertTypesOfVisibleExecutionDigests, getSourceFileList, getSourceFileListLoaded, @@ -37,6 +39,7 @@ import { } from './debugger_types'; import { createAlertsState, + createDebuggerGraphExecutionsState, createDebuggerSourceCodeState, createDebuggerState, createState, @@ -699,4 +702,68 @@ describe('debugger selectors', () => { }); }); }); + + describe('getNumGraphExecutionsLoaded', () => { + it('returns correct NOT_LOADED state', () => { + const state = createState(createDebuggerState()); + const loaded = getNumGraphExecutionsLoaded(state); + expect(loaded.state).toBe(DataLoadState.NOT_LOADED); + expect(loaded.lastLoadedTimeInMs).toBe(null); + }); + + it('returns correct LOADING state', () => { + const state = createState( + createDebuggerState({ + graphExecutions: createDebuggerGraphExecutionsState({ + numExecutionsLoaded: { + state: DataLoadState.LOADING, + lastLoadedTimeInMs: null, + }, + }), + }) + ); + const loaded = getNumGraphExecutionsLoaded(state); + expect(loaded.state).toBe(DataLoadState.LOADING); + expect(loaded.lastLoadedTimeInMs).toBe(null); + }); + + it('returns correct LOADED state', () => { + const state = createState( + createDebuggerState({ + graphExecutions: createDebuggerGraphExecutionsState({ + numExecutionsLoaded: { + state: DataLoadState.LOADED, + lastLoadedTimeInMs: 1234, + }, + }), + }) + ); + const loaded = getNumGraphExecutionsLoaded(state); + expect(loaded.state).toBe(DataLoadState.LOADED); + expect(loaded.lastLoadedTimeInMs).toBe(1234); + }); + }); + + describe('getNumGraphExecutions', () => { + it('returns correct initial zero state', () => { + const state = createState(createDebuggerState()); + expect(getNumGraphExecutions(state)).toBe(0); + }); + + it('returns correct non-zero state', () => { + const state = createState( + createDebuggerState({ + graphExecutions: createDebuggerGraphExecutionsState({ + executionDigestsLoaded: { + state: DataLoadState.LOADING, + lastLoadedTimeInMs: null, + pageLoadedSizes: {}, + numExecutions: 10, + }, + }), + }) + ); + expect(getNumGraphExecutions(state)).toBe(10); + }); + }); }); diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_types.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_types.ts index de4f1c75d4..d4a95fd740 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_types.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_types.ts @@ -84,6 +84,43 @@ export interface Execution extends ExecutionDigest { debug_tensor_values: Array | null; } +/** + * Digest for the execution of a Tensor inside a tf.Graph (e.g., tf.function). + * + * Mirrors data structure `class GraphExecutionTraceDigest` in + * https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/debug/lib/debug_events_reader.py + */ +export interface GraphExecutionDigest { + // Debugger-generated id for the inner-most (immediately-enclosing) tf.Graph. + graph_id: string; + + op_name: string; + + op_type: string; + + // Output slot of the tensor on the op that it belongs to. + output_slot: number; +} + +/** + * Non-digest, detaileddata object for the execution of a Tensor inside a + * tf.Graph (e.g., tf.function). + * + * Mirrors data structure `class GraphExecutionTrace` in + * https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/debug/lib/debug_events_reader.py + */ +export interface GraphExecution extends GraphExecutionDigest { + // The debugger-generated IDs of the graphs that enclose the + // executed op (tensor), ordered from the outermost to the innermost. + graph_ids: string[]; + + tensor_debug_mode: number; + + debug_tensor_value: number[] | null; + + device_name: string; +} + export enum AlertType { FUNCTION_RECOMPILE_ALERT = 'FunctionRecompilesAlert', INF_NAN_ALERT = 'InfNanAlert', @@ -125,7 +162,7 @@ export interface ExecutionDigestLoadState extends LoadState { pageLoadedSizes: {[page: number]: number}; // Number of top-level executions available at the data source (not - // necessarilty loaded by frontend yet.) + // necessarily loaded by frontend yet.) numExecutions: number; } @@ -165,14 +202,20 @@ export interface Alerts { focusType: AlertType | null; } -export interface Executions { - // Load state for the total number of top-level executions. +/** + * Base interface shared between top-level and intra-graph executions. + * + * Supports paged lazy loading of digess (i.e., concise data objects + * about the execution events.) + */ +export interface PagedExecutions { + // Load state for the total number of top-level or intra-graph executions. // numExecutionsLoaded load state can go from LOADED to LOADING, as // the backend may keep reading in new data and see an increase in // the number of execution events, which the frontend will in turn see. numExecutionsLoaded: LoadState; - // Load state for loading ExecutionDigests. + // Load state for loading `ExecutionDigest`s or `GraphExecutionDigest`s. // executionDigestsLoaded load state can go from LOADED to LOADING, as // the execution digests are loaded in pages. executionDigestsLoaded: ExecutionDigestLoadState; @@ -193,14 +236,30 @@ export interface Executions { // Index of focusing. `null` means no focus has been selected. focusIndex: number | null; +} - // Execution digests the frontend has loaded so far. +/** + * State of loading of top-level executions. + */ +export interface Executions extends PagedExecutions { + // Top-level (eager) execution digests the frontend has loaded so far. executionDigests: {[index: number]: ExecutionDigest}; - // Detailed data objects. + // Detailed data objects about top-level execution. executionData: {[index: number]: Execution}; } +/** + * State of loading of intra-graph executions. + */ +export interface GraphExecutions extends PagedExecutions { + // Intra-graph execution digests the frontend has loaded so far. + graphExecutionDigests: {[index: number]: GraphExecutionDigest}; + + // Detailed data objects about intra-graph execution. + graphExecutionData: {[index: number]: Execution}; +} + // The state of a loaded DebuggerV2 run. export interface RunState { executions: Executions; @@ -256,9 +315,12 @@ export interface DebuggerState { alerts: Alerts; - // Per-run detailed data. + // Per-run data for top-level (eager) executions. executions: Executions; + // Per-run data for intra-graph (eager) executions. + graphExecutions: GraphExecutions; + // Stack frames that have been loaded from data source so far, keyed by // stack-frame IDs. stackFrames: StackFramesById; diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing/BUILD index b8e65d5c0c..c1d3d193d0 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing/BUILD +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing/BUILD @@ -7,6 +7,7 @@ tf_ts_library( testonly = True, srcs = ["index.ts"], deps = [ + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store:types", "@npm//@angular/core", "@npm//@ngrx/store", diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing/index.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing/index.ts index 2402a18dee..4465d64b48 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing/index.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing/index.ts @@ -25,11 +25,16 @@ import { Execution, Executions, ExecutionDigest, + GraphExecutions, InfNanAlert, SourceCodeState, State, StackFrame, } from '../store/debugger_types'; +import { + createInitialExecutionsState, + createInitialGraphExecutionsState, +} from '../store/debugger_reducers'; export function createTestInfNanAlert( override?: Partial @@ -96,6 +101,7 @@ export function createDebuggerState( activeRunId: null, alerts: createAlertsState(), executions: createDebuggerExecutionsState(), + graphExecutions: createDebuggerGraphExecutionsState(), stackFrames: {}, sourceCode: { sourceFileListLoaded: { @@ -129,22 +135,16 @@ export function createDebuggerExecutionsState( override?: Partial ): Executions { return { - numExecutionsLoaded: { - state: DataLoadState.NOT_LOADED, - lastLoadedTimeInMs: null, - }, - executionDigestsLoaded: { - state: DataLoadState.NOT_LOADED, - lastLoadedTimeInMs: null, - numExecutions: 0, - pageLoadedSizes: {}, - }, - displayCount: 50, - pageSize: 1000, - scrollBeginIndex: 0, - focusIndex: null, - executionDigests: {}, - executionData: {}, + ...createInitialExecutionsState(), + ...override, + }; +} + +export function createDebuggerGraphExecutionsState( + override?: Partial +): GraphExecutions { + return { + ...createInitialGraphExecutionsState(), ...override, }; } diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts/BUILD index c984eebaa7..67b5660d9a 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts/BUILD +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts/BUILD @@ -41,6 +41,7 @@ tf_ts_library( "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store:types", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/inactive", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace", diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts/alerts_container_test.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts/alerts_container_test.ts index 80c473241c..6804bfe7d6 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts/alerts_container_test.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts/alerts_container_test.ts @@ -34,6 +34,7 @@ import { import {AlertsContainer} from './alerts_container'; import {AlertsModule} from './alerts_module'; import {ExecutionDataModule} from '../execution_data/execution_data_module'; +import {GraphExecutionsModule} from '../graph_executions/graph_executions_module'; import {InactiveModule} from '../inactive/inactive_module'; import {SourceFilesModule} from '../source_files/source_files_module'; import {StackTraceModule} from '../stack_trace/stack_trace_module'; @@ -52,6 +53,7 @@ describe('Alerts Container', () => { AlertsModule, CommonModule, ExecutionDataModule, + GraphExecutionsModule, InactiveModule, SourceFilesModule, StackTraceModule, diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/BUILD new file mode 100644 index 0000000000..9035c43d5b --- /dev/null +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/BUILD @@ -0,0 +1,28 @@ +package(default_visibility = ["//tensorboard:internal"]) + +load("@npm_angular_bazel//:index.bzl", "ng_module") + +licenses(["notice"]) # Apache 2.0 + +ng_module( + name = "graph_executions", + srcs = [ + "graph_executions_component.ts", + "graph_executions_container.ts", + "graph_executions_module.ts", + ], + assets = [ + "graph_executions_component.css", + "graph_executions_component.ng.html", + ], + deps = [ + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin:tf_types", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/actions", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store:types", + "@npm//@angular/common", + "@npm//@angular/core", + "@npm//@ngrx/store", + "@npm//rxjs", + ], +) diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.css b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.css new file mode 100644 index 0000000000..53977f840b --- /dev/null +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.css @@ -0,0 +1,24 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +.graph-executions-container { + border-left: 1px solid rgba(0, 0, 0, 0.12); + display: flex; + flex-direction: column; + height: 100%; + margin-left: 8px; + padding-left: 10px; +} + diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ng.html b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ng.html new file mode 100644 index 0000000000..fd3b18b859 --- /dev/null +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ng.html @@ -0,0 +1,22 @@ + + +
+
Graph Executions ({{numGraphExecutions}})
+ + +
diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ts new file mode 100644 index 0000000000..fbb77ce420 --- /dev/null +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ts @@ -0,0 +1,28 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +import {Component, Input} from '@angular/core'; + +import {GraphExecutionDigest} from '../../store/debugger_types'; + +@Component({ + selector: 'graph-executions-component', + templateUrl: './graph_executions_component.ng.html', + styleUrls: ['./graph_executions_component.css'], +}) +export class GraphExecutionsComponent { + @Input() + numGraphExecutions: number | null = null; +} diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_container.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_container.ts new file mode 100644 index 0000000000..9af09cf15c --- /dev/null +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_container.ts @@ -0,0 +1,35 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ +import {Component} from '@angular/core'; +import {select, Store} from '@ngrx/store'; + +import {getNumGraphExecutions} from '../../store'; +import {State} from '../../store/debugger_types'; + +/** @typehack */ import * as _typeHackRxjs from 'rxjs'; + +@Component({ + selector: 'tf-debugger-v2-graph-executions', + template: ` + + `, +}) +export class GraphExecutionsContainer { + readonly numGraphExecutions$ = this.store.pipe(select(getNumGraphExecutions)); + + constructor(private readonly store: Store) {} +} diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_module.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_module.ts new file mode 100644 index 0000000000..864a258ae4 --- /dev/null +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_module.ts @@ -0,0 +1,27 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +import {CommonModule} from '@angular/common'; +import {NgModule} from '@angular/core'; + +import {GraphExecutionsComponent} from './graph_executions_component'; +import {GraphExecutionsContainer} from './graph_executions_container'; + +@NgModule({ + declarations: [GraphExecutionsComponent, GraphExecutionsContainer], + imports: [CommonModule], + exports: [GraphExecutionsContainer], +}) +export class GraphExecutionsModule {} diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/BUILD index 2d926f3a89..01260818d1 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/BUILD +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/BUILD @@ -42,6 +42,7 @@ tf_ts_library( "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/inactive", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_code:load_monaco", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_code:testing", diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_container_test.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_container_test.ts index 0d114438c2..ba28d69497 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_container_test.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_container_test.ts @@ -28,6 +28,7 @@ import {DataLoadState, State} from '../../store/debugger_types'; import {createDebuggerState, createState} from '../../testing'; import {AlertsModule} from '../alerts/alerts_module'; import {ExecutionDataModule} from '../execution_data/execution_data_module'; +import {GraphExecutionsModule} from '../graph_executions/graph_executions_module'; import {InactiveModule} from '../inactive/inactive_module'; import {setUpMonacoFakes, tearDownMonacoFakes} from '../source_code/testing'; import {StackTraceModule} from '../stack_trace/stack_trace_module'; @@ -53,6 +54,7 @@ describe('Source Files Container', () => { AlertsModule, CommonModule, ExecutionDataModule, + GraphExecutionsModule, InactiveModule, SourceFilesModule, StackTraceModule, diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_component.css b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_component.css index e4214ba1b6..681f9bb652 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_component.css +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_component.css @@ -57,8 +57,9 @@ limitations under the License. height: 360px; margin-left: 8px; max-height: 360px; + overflow-x: hidden; padding-left: 8px; - width: 400px; + width: 100%; } .stack-trace-host-name { From eef22afa7bad356f606240a4575683225e8ce33f Mon Sep 17 00:00:00 2001 From: Shanqing Cai Date: Sun, 12 Apr 2020 13:19:54 -0400 Subject: [PATCH 2/4] Add effects for loading num of graph execs + unit tests --- .../effects/debugger_effects.ts | 55 +++++++++++++++++- .../effects/debugger_effects_test.ts | 57 ++++++++++++++++++- .../graph_executions_component.css | 1 - 3 files changed, 107 insertions(+), 6 deletions(-) diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects.ts index eae5fc3bb4..3da345612a 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects.ts @@ -41,6 +41,8 @@ import { numAlertsAndBreakdownRequested, numExecutionsLoaded, numExecutionsRequested, + numGraphExecutionsLoaded, + numGraphExecutionsRequested, sourceFileListLoaded, sourceFileListRequested, sourceLineFocused, @@ -65,11 +67,11 @@ import { getLoadedExecutionData, getLoadedStackFrames, getNumAlertsOfFocusedType, + getNumGraphExecutions, + getNumGraphExecutionsLoaded, getSourceFileListLoaded, - getSourceFileList, getFocusedSourceFileIndex, } from '../store/debugger_selectors'; -import {findFileIndex} from '../store/debugger_store_utils'; import { DataLoadState, DebuggerRunListing, @@ -189,7 +191,7 @@ export class DebuggerEffects { } /** - * When a debugger run exists, load number of executions. + * When a debugger run exists, load number of top-level executions. */ private createNumExecutionLoader(prevStream$: Observable) { return prevStream$.pipe( @@ -222,6 +224,46 @@ export class DebuggerEffects { ); } + /** + * When a debugger run exists, load number of intra-graph executions. + */ + private createNumGraphExecutionLoader(prevStream$: Observable) { + return prevStream$.pipe( + withLatestFrom( + this.store.select(getDebuggerRunListing), + this.store.select(getNumGraphExecutionsLoaded) + ), + filter(([, runs, loaded]) => { + return ( + Object.keys(runs).length > 0 && loaded.state !== DataLoadState.LOADING + ); + }), + tap(() => this.store.dispatch(numGraphExecutionsRequested())), + mergeMap(([, runs]) => { + const runId = Object.keys(runs)[0]; + const begin = 0; + const end = 0; + return this.dataSource + .fetchGraphExecutionDigests(runId, begin, end) + .pipe( + tap((digests) => { + console.log( + '200 fetchGraphExecutionDigests(): digests=', + digests + ); // DEBUG + this.store.dispatch( + numGraphExecutionsLoaded({ + numGraphExecutions: digests.num_digests, + }) + ); + }), + map(() => void null) + ); + // TODO(cais): Add catchError() to pipe. + }) + ); + } + /** * When a debugger run exists, load number of alerts and their breakdown. */ @@ -782,6 +824,12 @@ export class DebuggerEffects { ) ); + /////////////////////////////////////////////// + // Effects related to intra-graph execution. // + /////////////////////////////////////////////// + const onNumGraphExecutionLoaded$ = this.createNumGraphExecutionLoader( + onLoad$ + ); const onSourceFileFocused$ = this.onSourceFileFocused(); // ExecutionDigest and ExecutionData can be loaded in parallel. @@ -789,6 +837,7 @@ export class DebuggerEffects { onNumAlertsLoaded$, onExcutionDigestLoaded$, onExecutionDataLoaded$, + onNumGraphExecutionLoaded$, loadSourceFileList$, onSourceFileFocused$ ).pipe( diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects_test.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects_test.ts index e854360be4..18c8470ea4 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects_test.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects_test.ts @@ -34,6 +34,8 @@ import { numAlertsAndBreakdownLoaded, numExecutionsLoaded, numExecutionsRequested, + numGraphExecutionsLoaded, + numGraphExecutionsRequested, sourceFileListLoaded, sourceFileListRequested, stackFramesLoaded, @@ -45,6 +47,7 @@ import { AlertsResponse, ExecutionDataResponse, ExecutionDigestsResponse, + GraphExecutionDigestsResponse, SourceFileListResponse, SourceFileResponse, StackFramesResponse, @@ -305,6 +308,20 @@ describe('Debugger effects', () => { .and.returnValue(of(excutionDigestsResponse)); } + function createFetchGraphExecutionDigestsSpy( + runId: string, + begin: number, + end: number, + graphExcutionDigestsResponse: GraphExecutionDigestsResponse + ) { + return spyOn( + TestBed.get(Tfdbg2HttpServerDataSource), + 'fetchGraphExecutionDigests' + ) + .withArgs(runId, begin, end) + .and.returnValue(of(graphExcutionDigestsResponse)); + } + describe('loadData', () => { const runListingForTest: DebuggerRunListing = { __default_debugger_run__: { @@ -376,6 +393,9 @@ describe('Debugger effects', () => { end: 1, executions: [executionData1], }; + + const numGraphExecutions = 10; + const stackFrame0 = createTestStackFrame(); const stackFrame1 = createTestStackFrame(); @@ -412,12 +432,26 @@ describe('Debugger effects', () => { fetchExecutionDigests .withArgs(runId, 0, pageSize) .and.returnValue(of(executionDigestsPageResponse)); + // Spy for loading detailed execution data. const fetchExecutionData = createFetchExecutionDataSpy( runId, 0, 1, executionDataResponse ); + // Spy for loading number of graph executions. + const fetchGraphExecutionDigests = createFetchGraphExecutionDigestsSpy( + runId, + 0, + 0, + { + begin: 0, + end: 0, + num_digests: numGraphExecutions, + graph_execution_digests: [], + } + ); + // Spy for loading stack frames. const fetchStackFrames = createFetchStackFramesSpy({ stack_frames: [stackFrame0, stackFrame1], }); @@ -427,6 +461,7 @@ describe('Debugger effects', () => { fetchNumAlertsSpy, fetchExecutionDigests, fetchExecutionData, + fetchGraphExecutionDigests, fetchStackFrames, }; } @@ -467,6 +502,17 @@ describe('Debugger effects', () => { 0, numAlertsResponseForTest ); + const fetchNumGraphExecutionDigests = createFetchGraphExecutionDigestsSpy( + runId, + 0, + 0, + { + begin: 0, + end: 0, + num_digests: 0, + graph_execution_digests: [], + } + ); store.overrideSelector(getDebuggerRunListing, runListingForTest); store.overrideSelector(getNumExecutionsLoaded, { state: DataLoadState.NOT_LOADED, @@ -479,6 +525,7 @@ describe('Debugger effects', () => { expect(fetchRuns).toHaveBeenCalled(); expect(fetchNumExecutionDigests).toHaveBeenCalled(); expect(fetchNumAlerts).toHaveBeenCalled(); + expect(fetchNumGraphExecutionDigests).toHaveBeenCalled(); expect(dispatchedActions).toEqual([ debuggerRunsRequested(), debuggerRunsLoaded({runs: runListingForTest}), @@ -489,18 +536,21 @@ describe('Debugger effects', () => { }), numExecutionsRequested(), numExecutionsLoaded({numExecutions: 0}), + numGraphExecutionsRequested(), + numGraphExecutionsLoaded({numGraphExecutions: 0}), ]); }); it( - 'loads source-file list, execution digests, data & stack trace loading ' + - 'if numExecutions>0', + 'loads source-file list, top-level and intra-graph digests and data, ' + + 'and stack trace, if numExecutions>0', () => { const { fetchRuns, fetchSourceFileList, fetchExecutionDigests, fetchExecutionData, + fetchGraphExecutionDigests, fetchStackFrames, } = createFetchSpies(); store.overrideSelector(getDebuggerRunListing, runListingForTest); @@ -521,6 +571,7 @@ describe('Debugger effects', () => { expect(fetchExecutionDigests).toHaveBeenCalledTimes(2); expect(fetchExecutionData).toHaveBeenCalledTimes(1); expect(fetchStackFrames).toHaveBeenCalledTimes(1); + expect(fetchGraphExecutionDigests).toHaveBeenCalledTimes(1); expect(fetchSourceFileList).toHaveBeenCalledTimes(1); expect(dispatchedActions).toEqual([ debuggerRunsRequested(), @@ -536,6 +587,8 @@ describe('Debugger effects', () => { executionDigestsLoaded(executionDigestsPageResponse), executionDataLoaded(executionDataResponse), stackFramesLoaded({stackFrames: {aa: stackFrame0, bb: stackFrame1}}), + numGraphExecutionsRequested(), + numGraphExecutionsLoaded({numGraphExecutions}), sourceFileListRequested(), sourceFileListLoaded({ sourceFiles: twoSourceFilesForTest.map( diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.css b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.css index 53977f840b..a3d0e697c8 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.css +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.css @@ -21,4 +21,3 @@ limitations under the License. margin-left: 8px; padding-left: 10px; } - From f4129a9bf9a009f66481e166e088d03f51eeb0f8 Mon Sep 17 00:00:00 2001 From: Shanqing Cai Date: Sun, 12 Apr 2020 14:08:33 -0400 Subject: [PATCH 3/4] Add container test for graph executions --- .../debugger_v2/tf_debugger_v2_plugin/BUILD | 1 + .../effects/debugger_effects.ts | 13 ++-- .../views/graph_executions/BUILD | 32 ++++++++ .../graph_executions_component.ng.html | 4 +- .../graph_executions_container_test.ts | 77 +++++++++++++++++++ 5 files changed, 118 insertions(+), 9 deletions(-) create mode 100644 tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_container_test.ts diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/BUILD index 4c429e9799..15cb1ad18b 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/BUILD +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/BUILD @@ -78,6 +78,7 @@ tf_ng_web_test_suite( "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects:debugger_effects_test_lib", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store:debugger_store_test_lib", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts:alerts_container_test_lib", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions:graph_executions_container_test_lib", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_code:source_code_container_test_lib", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_code:source_code_test_lib", "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files:source_files_container_test_lib", diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects.ts index 3da345612a..7edf4234d8 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects.ts @@ -247,10 +247,6 @@ export class DebuggerEffects { .fetchGraphExecutionDigests(runId, begin, end) .pipe( tap((digests) => { - console.log( - '200 fetchGraphExecutionDigests(): digests=', - digests - ); // DEBUG this.store.dispatch( numGraphExecutionsLoaded({ numGraphExecutions: digests.num_digests, @@ -748,14 +744,15 @@ export class DebuggerEffects { /** * view load ---------> fetch source-file list * | - * +> fetch run +> fetch num exec + * +> fetch run +> fetch num of top-level (eager) executions + * | +> fetch num of intra-graph executions * | +> fetch num alerts * | + * | +> if init load and non-zero number of execs * | + - * | +>+-------------------+ - * | | | fetch exec digest | - * | on scroll +-------->+-------------------+<------------------+ + * | +>+-----------------------------+ + * | on top-level | | fetch top-level exec digest | + * | scroll -----------+>+-----------------------------+<--------+ * | | | * | +>+----------------------------------+ | * | | fetch exec data and stack frames | | diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/BUILD index 9035c43d5b..ae9a3e0b2b 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/BUILD +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/BUILD @@ -1,6 +1,7 @@ package(default_visibility = ["//tensorboard:internal"]) load("@npm_angular_bazel//:index.bzl", "ng_module") +load("//tensorboard/defs:defs.bzl", "tf_ts_library") licenses(["notice"]) # Apache 2.0 @@ -26,3 +27,34 @@ ng_module( "@npm//rxjs", ], ) + +tf_ts_library( + name = "graph_executions_container_test_lib", + testonly = True, + srcs = [ + "graph_executions_container_test.ts", + ], + tsconfig = "//:tsconfig-test", + deps = [ + ":graph_executions", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin:debugger_v2", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/actions", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store:types", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/inactive", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace", + "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/timeline", + "//tensorboard/webapp/angular:expect_angular_core_testing", + "//tensorboard/webapp/angular:expect_ngrx_store_testing", + "@npm//@angular/common", + "@npm//@angular/compiler", + "@npm//@angular/core", + "@npm//@angular/platform-browser", + "@npm//@ngrx/store", + "@npm//@types/jasmine", + ], +) diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ng.html b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ng.html index fd3b18b859..6b78f3fe71 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ng.html +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ng.html @@ -16,7 +16,9 @@ -->
-
Graph Executions ({{numGraphExecutions}})
+
+ Graph Executions ({{ numGraphExecutions }}) +
diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_container_test.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_container_test.ts new file mode 100644 index 0000000000..b01ff8e7fd --- /dev/null +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_container_test.ts @@ -0,0 +1,77 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ +/** + * Unit tests for the the intra-graph execution component and container. + */ +import {CommonModule} from '@angular/common'; +import {TestBed} from '@angular/core/testing'; +import {By} from '@angular/platform-browser'; + +import {Store} from '@ngrx/store'; +import {provideMockStore, MockStore} from '@ngrx/store/testing'; + +import {DebuggerComponent} from '../../debugger_component'; +import {DebuggerContainer} from '../../debugger_container'; +import {State} from '../../store/debugger_types'; +import {createDebuggerState, createState} from '../../testing'; +import {AlertsModule} from '../alerts/alerts_module'; +import {ExecutionDataModule} from '../execution_data/execution_data_module'; +import {InactiveModule} from '../inactive/inactive_module'; +import {SourceFilesModule} from '../source_files/source_files_module'; +import {StackTraceModule} from '../stack_trace/stack_trace_module'; +import {TimelineModule} from '../timeline/timeline_module'; +import {GraphExecutionsContainer} from './graph_executions_container'; +import {GraphExecutionsModule} from './graph_executions_module'; + +/** @typehack */ import * as _typeHackStore from '@ngrx/store'; +import {getNumGraphExecutions} from '../../store'; + +describe('Graph Executions Container', () => { + let store: MockStore; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [DebuggerComponent, DebuggerContainer], + imports: [ + AlertsModule, + CommonModule, + ExecutionDataModule, + GraphExecutionsModule, + InactiveModule, + SourceFilesModule, + StackTraceModule, + TimelineModule, + ], + providers: [ + provideMockStore({ + initialState: createState(createDebuggerState()), + }), + DebuggerContainer, + ], + }).compileComponents(); + store = TestBed.get(Store); + }); + + it('renders number of graph executions', () => { + const fixture = TestBed.createComponent(GraphExecutionsContainer); + store.overrideSelector(getNumGraphExecutions, 120); + fixture.detectChanges(); + + const titleElement = fixture.debugElement.query( + By.css('.graph-executions-title') + ); + expect(titleElement.nativeElement.innerText).toBe('Graph Executions (120)'); + }); +}); From 3b92b844973ff1140b18552b657aeb2fb6f1fc7e Mon Sep 17 00:00:00 2001 From: Shanqing Cai Date: Wed, 15 Apr 2020 17:02:57 -0400 Subject: [PATCH 4/4] Address comments; remove unused code --- .../tf_debugger_v2_plugin/effects/debugger_effects.ts | 4 +--- .../debugger_v2/tf_debugger_v2_plugin/store/debugger_types.ts | 4 ++-- .../views/graph_executions/graph_executions_component.ts | 2 -- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects.ts index 7edf4234d8..d6447a575d 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects.ts @@ -821,12 +821,10 @@ export class DebuggerEffects { ) ); - /////////////////////////////////////////////// - // Effects related to intra-graph execution. // - /////////////////////////////////////////////// const onNumGraphExecutionLoaded$ = this.createNumGraphExecutionLoader( onLoad$ ); + const onSourceFileFocused$ = this.onSourceFileFocused(); // ExecutionDigest and ExecutionData can be loaded in parallel. diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_types.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_types.ts index d4a95fd740..5e80e34702 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_types.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debugger_types.ts @@ -205,8 +205,8 @@ export interface Alerts { /** * Base interface shared between top-level and intra-graph executions. * - * Supports paged lazy loading of digess (i.e., concise data objects - * about the execution events.) + * Supports paged, lazy loading of digests (i.e., concise data objects + * about the top-level or intra-graph execution events.) */ export interface PagedExecutions { // Load state for the total number of top-level or intra-graph executions. diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ts index fbb77ce420..7cd3f43230 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_component.ts @@ -15,8 +15,6 @@ limitations under the License. import {Component, Input} from '@angular/core'; -import {GraphExecutionDigest} from '../../store/debugger_types'; - @Component({ selector: 'graph-executions-component', templateUrl: './graph_executions_component.ng.html',