diff --git a/frontend/app/components/framework_op_stats/framework_op_stats_adapter.ts b/frontend/app/components/framework_op_stats/framework_op_stats_adapter.ts index e9ec599c..b2239295 100644 --- a/frontend/app/components/framework_op_stats/framework_op_stats_adapter.ts +++ b/frontend/app/components/framework_op_stats/framework_op_stats_adapter.ts @@ -6,7 +6,7 @@ import {FrameworkOpStatsModule} from 'org_xprof/frontend/app/components/framewor import {DATA_SERVICE_INTERFACE_TOKEN, type DataServiceV2Interface} from 'org_xprof/frontend/app/services/data_service_v2/data_service_v2_interface'; import {setCurrentToolStateAction, setDataRequestStateAction} from 'org_xprof/frontend/app/store/actions'; import * as actions from 'org_xprof/frontend/app/store/framework_op_stats/actions'; -import {ReplaySubject} from 'rxjs'; +import {combineLatest, ReplaySubject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; /** An overview adapter component. */ @@ -31,13 +31,17 @@ export class FrameworkOpStatsAdapter implements OnDestroy { route: ActivatedRoute, private readonly store: Store<{}>, ) { - route.params.pipe(takeUntil(this.destroyed)).subscribe((params) => { - this.processQuery(params); - this.store.dispatch( - actions.setHasDiffAction({hasDiff: Boolean(this.diffBaseSessionId)}), - ); - this.update(); - }); + combineLatest([route.params, route.queryParams]) + .pipe(takeUntil(this.destroyed)) + .subscribe(([params, queryParams]) => { + this.sessionId = params['sessionId'] || this.sessionId; + this.processQueryParams(queryParams); + this.store.dispatch( + actions.setHasDiffAction( + {hasDiff: Boolean(this.diffBaseSessionId)}), + ); + this.update(); + }); this.store.dispatch( setCurrentToolStateAction({currentTool: 'framework_op_stats'}), ); @@ -50,7 +54,7 @@ export class FrameworkOpStatsAdapter implements OnDestroy { ); } - processQuery(params: Params) { + processQueryParams(params: Params) { this.sessionId = params['run'] || params['sessionId'] || this.sessionId; this.diffBaseSessionId = this.dataService.getSearchParams().get('diff_base') || ''; diff --git a/frontend/app/components/graph_viewer/graph_viewer.ts b/frontend/app/components/graph_viewer/graph_viewer.ts index 76370e1a..dbb9d065 100644 --- a/frontend/app/components/graph_viewer/graph_viewer.ts +++ b/frontend/app/components/graph_viewer/graph_viewer.ts @@ -100,6 +100,8 @@ export class GraphViewer implements OnDestroy { private readonly router: Router, private readonly snackBar: MatSnackBar, ) { + // TODO(xprof): combine the two subscriptions and mange the order of + // operations (see changes in other tools, eg. hlo_stats). this.route.params.pipe(takeUntil(this.destroyed)).subscribe((params) => { this.parseNavEvent(params); // init data that replis on the session id diff --git a/frontend/app/components/hlo_stats/hlo_stats.ts b/frontend/app/components/hlo_stats/hlo_stats.ts index e8391580..dfcb7e70 100644 --- a/frontend/app/components/hlo_stats/hlo_stats.ts +++ b/frontend/app/components/hlo_stats/hlo_stats.ts @@ -15,7 +15,7 @@ import {DefaultDataProvider, ReplicaGroupDataProvider} from 'org_xprof/frontend/ import {DATA_SERVICE_INTERFACE_TOKEN, DataServiceV2Interface} from 'org_xprof/frontend/app/services/data_service_v2/data_service_v2_interface'; import {SOURCE_CODE_SERVICE_INTERFACE_TOKEN} from 'org_xprof/frontend/app/services/source_code_service/source_code_service_interface'; import {setCurrentToolStateAction} from 'org_xprof/frontend/app/store/actions'; -import {ReplaySubject} from 'rxjs'; +import {combineLatest, ReplaySubject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; const AVG_TIME_ID = 'avg_time'; @@ -130,10 +130,13 @@ export class HloStats extends Dashboard implements OnDestroy { private readonly store: Store<{}>, ) { super(); - route.params.pipe(takeUntil(this.destroyed)).subscribe((params) => { - this.processQuery(params); - this.update(); - }); + combineLatest([route.params, route.queryParams]) + .pipe(takeUntil(this.destroyed)) + .subscribe(([params, queryParams]) => { + this.sessionId = params['sessionId'] || this.sessionId; + this.processQueryParams(queryParams); + this.update(); + }); this.store.dispatch(setCurrentToolStateAction({currentTool: this.tool})); this.tableColumnsControl.valueChanges.subscribe((newValue) => { this.updateTableColumns(newValue || []); @@ -151,7 +154,7 @@ export class HloStats extends Dashboard implements OnDestroy { } } - processQuery(params: Params) { + processQueryParams(params: Params) { this.sessionId = params['run'] || params['sessionId'] || this.sessionId; this.tool = params['tag'] || this.tool; this.host = params['host'] || this.host; diff --git a/frontend/app/components/inference_profile/inference_profile.ts b/frontend/app/components/inference_profile/inference_profile.ts index d01d5fd0..5370247b 100644 --- a/frontend/app/components/inference_profile/inference_profile.ts +++ b/frontend/app/components/inference_profile/inference_profile.ts @@ -1,13 +1,12 @@ import {Component, inject, OnDestroy} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; +import {ActivatedRoute, Params} from '@angular/router'; import {Store} from '@ngrx/store'; import {Throbber} from 'org_xprof/frontend/app/common/classes/throbber'; -import {InferenceProfileData, InferenceProfileDataProperty, InferenceProfileMetadata, InferenceProfileMetadataProperty, InferenceProfileTable,} from 'org_xprof/frontend/app/common/interfaces/data_table'; -import {NavigationEvent} from 'org_xprof/frontend/app/common/interfaces/navigation_event'; +import {InferenceProfileData, InferenceProfileDataProperty, InferenceProfileMetadata, InferenceProfileMetadataProperty, InferenceProfileTable, } from 'org_xprof/frontend/app/common/interfaces/data_table'; import {setLoadingState} from 'org_xprof/frontend/app/common/utils/utils'; import {DATA_SERVICE_INTERFACE_TOKEN} from 'org_xprof/frontend/app/services/data_service_v2/data_service_v2_interface'; import {setCurrentToolStateAction} from 'org_xprof/frontend/app/store/actions'; -import {ReplaySubject} from 'rxjs'; +import {combineLatest, ReplaySubject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; /** An inference profile component. */ @@ -27,8 +26,8 @@ export class InferenceProfile implements OnDestroy { private readonly dataService = inject(DATA_SERVICE_INTERFACE_TOKEN); // All the model IDs and data. - hasBatching: boolean = false; - hasTensorPattern: boolean = false; + hasBatching = false; + hasTensorPattern = false; allModelIds: string[] = []; allRequestTables: google.visualization.DataTable[] = []; allRequestProperties: InferenceProfileDataProperty[] = []; @@ -57,18 +56,23 @@ export class InferenceProfile implements OnDestroy { route: ActivatedRoute, private readonly store: Store<{}>, ) { - route.params.pipe(takeUntil(this.destroyed)).subscribe((params) => { - if (params as NavigationEvent) { - this.sessionId = (params as NavigationEvent).run || ''; - this.tool = (params as NavigationEvent).tag || 'inference_profile'; - this.host = (params as NavigationEvent).host || ''; - } - this.sessionId = (params || {})['sessionId'] || this.sessionId; - this.update(); - }); + combineLatest([route.params, route.queryParams]) + .pipe(takeUntil(this.destroyed)) + .subscribe(([params, queryParams]) => { + this.sessionId = params['sessionId'] || this.sessionId; + this.processQueryParams(queryParams); + this.update(); + }); this.store.dispatch(setCurrentToolStateAction({currentTool: this.tool})); } + processQueryParams(queryParams: Params) { + this.sessionId = + queryParams['run'] || queryParams['sessionId'] || this.sessionId; + this.tool = queryParams['tag'] || this.tool; + this.host = queryParams['host'] || this.host; + } + parseMetadata(metadataOrNull: InferenceProfileTable) { if (!metadataOrNull) return false; const metadata = (metadataOrNull as InferenceProfileMetadata).p as diff --git a/frontend/app/components/input_pipeline/input_pipeline.ts b/frontend/app/components/input_pipeline/input_pipeline.ts index fe676c43..34ffbe6c 100644 --- a/frontend/app/components/input_pipeline/input_pipeline.ts +++ b/frontend/app/components/input_pipeline/input_pipeline.ts @@ -7,7 +7,7 @@ import {InputPipelineDataTable, SimpleDataTable, } from 'org_xprof/frontend/app/ import {setLoadingState} from 'org_xprof/frontend/app/common/utils/utils'; import {DATA_SERVICE_INTERFACE_TOKEN, type DataServiceV2Interface} from 'org_xprof/frontend/app/services/data_service_v2/data_service_v2_interface'; import {setCurrentToolStateAction} from 'org_xprof/frontend/app/store/actions'; -import {ReplaySubject} from 'rxjs'; +import {combineLatest, ReplaySubject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; import {InputPipelineCommon} from './input_pipeline_common'; @@ -48,14 +48,17 @@ export class InputPipeline extends InputPipelineCommon implements OnDestroy { constructor(route: ActivatedRoute, private readonly store: Store<{}>) { super(); - route.params.pipe(takeUntil(this.destroyed)).subscribe((params) => { - this.processQuery(params); - this.update(); - }); + combineLatest([route.params, route.queryParams]) + .pipe(takeUntil(this.destroyed)) + .subscribe(([params, queryParams]) => { + this.sessionId = params['sessionId'] || this.sessionId; + this.processQueryParams(queryParams); + this.update(); + }); this.store.dispatch(setCurrentToolStateAction({currentTool: this.tool})); } - processQuery(params: Params) { + processQueryParams(params: Params) { this.tool = params['tag'] || this.tool; this.sessionId = params['run'] || params['sessionId'] || this.sessionId; this.host = params['host'] || this.host; diff --git a/frontend/app/components/megascale_stats/megascale_stats.ts b/frontend/app/components/megascale_stats/megascale_stats.ts index 9f0fef57..0adf8861 100644 --- a/frontend/app/components/megascale_stats/megascale_stats.ts +++ b/frontend/app/components/megascale_stats/megascale_stats.ts @@ -1,22 +1,19 @@ import {Component, inject, OnDestroy} from '@angular/core'; import {ActivatedRoute, Params, Router} from '@angular/router'; import {Store} from '@ngrx/store'; -import {HostMetadata} from 'org_xprof/frontend/app/common/interfaces/hosts'; import {Throbber} from 'org_xprof/frontend/app/common/classes/throbber'; import {ChartDataInfo} from 'org_xprof/frontend/app/common/interfaces/chart'; import {SimpleDataTable} from 'org_xprof/frontend/app/common/interfaces/data_table'; import {Diagnostics} from 'org_xprof/frontend/app/common/interfaces/diagnostics'; -import {parseDiagnosticsDataTable} from 'org_xprof/frontend/app/common/utils/utils'; +import {HostMetadata} from 'org_xprof/frontend/app/common/interfaces/hosts'; +import {parseDiagnosticsDataTable, setLoadingState} from 'org_xprof/frontend/app/common/utils/utils'; import {TABLE_OPTIONS} from 'org_xprof/frontend/app/components/chart/chart_options'; import {Dashboard} from 'org_xprof/frontend/app/components/chart/dashboard/dashboard'; import {DefaultDataProvider} from 'org_xprof/frontend/app/components/chart/default_data_provider'; import {DATA_SERVICE_INTERFACE_TOKEN, DataServiceV2Interface} from 'org_xprof/frontend/app/services/data_service_v2/data_service_v2_interface'; -import {setLoadingState} from 'org_xprof/frontend/app/common/utils/utils'; -import { - setCurrentToolStateAction, -} from 'org_xprof/frontend/app/store/actions'; +import {setCurrentToolStateAction, } from 'org_xprof/frontend/app/store/actions'; import {getHostsState} from 'org_xprof/frontend/app/store/selectors'; -import {ReplaySubject} from 'rxjs'; +import {combineLatest, ReplaySubject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; const MEGASCALE_STATS_INDEX = 0; @@ -59,10 +56,13 @@ export class MegascaleStats extends Dashboard implements OnDestroy { private readonly router: Router, ) { super(); - route.params.pipe(takeUntil(this.destroyed)).subscribe((params) => { - this.processQuery(params); - this.update(); - }); + combineLatest([route.params, route.queryParams]) + .pipe(takeUntil(this.destroyed)) + .subscribe(([params, queryParams]) => { + this.sessionId = params['sessionId'] || this.sessionId; + this.processQueryParams(queryParams); + this.update(); + }); this.store.dispatch(setCurrentToolStateAction({currentTool: this.tool})); this.store .select(getHostsState) @@ -81,7 +81,7 @@ export class MegascaleStats extends Dashboard implements OnDestroy { }); } - processQuery(params: Params) { + processQueryParams(params: Params) { this.sessionId = params['run'] || params['sessionId'] || this.sessionId; this.tool = params['tag'] || this.tool; this.host = params['host'] || this.host; diff --git a/frontend/app/components/memory_profile/memory_profile.ts b/frontend/app/components/memory_profile/memory_profile.ts index 81d5e1f6..fac2e848 100644 --- a/frontend/app/components/memory_profile/memory_profile.ts +++ b/frontend/app/components/memory_profile/memory_profile.ts @@ -1,13 +1,12 @@ import {Component, inject, OnDestroy} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; +import {ActivatedRoute, Params} from '@angular/router'; import {Store} from '@ngrx/store'; import {Throbber} from 'org_xprof/frontend/app/common/classes/throbber'; import {MemoryProfileProto} from 'org_xprof/frontend/app/common/interfaces/data_table'; -import {NavigationEvent} from 'org_xprof/frontend/app/common/interfaces/navigation_event'; import {MemoryProfileBase} from 'org_xprof/frontend/app/components/memory_profile/memory_profile_base'; import {DATA_SERVICE_INTERFACE_TOKEN} from 'org_xprof/frontend/app/services/data_service_v2/data_service_v2_interface'; import {setCurrentToolStateAction} from 'org_xprof/frontend/app/store/actions'; -import {ReplaySubject} from 'rxjs'; +import {combineLatest, ReplaySubject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; /** A Memory Profile component. */ @@ -36,21 +35,26 @@ export class MemoryProfile extends MemoryProfileBase implements OnDestroy { private readonly store: Store<{}>, ) { super(); - route.params.pipe(takeUntil(this.destroyed)).subscribe((params) => { - params = params || {}; - this.sessionId = params['sessionId'] || ''; - this.selectedHostId = params['host_id'] || 0; - this.update(params as NavigationEvent); - }); + combineLatest([route.params, route.queryParams]) + .pipe(takeUntil(this.destroyed)) + .subscribe(([params, queryParams]) => { + this.sessionId = params['sessionId'] || this.sessionId; + this.processQueryParams(queryParams); + this.update(); + }); this.store.dispatch( setCurrentToolStateAction({currentTool: 'memory_profile'}), ); } - update(event?: NavigationEvent) { - this.sessionId = event?.run || this.sessionId; - this.tool = event?.tag || this.tool; - this.host = event?.host || this.host; + processQueryParams(params: Params) { + this.sessionId = params['run'] || params['sessionId'] || this.sessionId; + this.tool = params['tag'] || this.tool; + this.host = params['host'] || this.host; + this.selectedHostId = params['host_id'] || this.selectedHostId; + } + + update() { this.loading = true; this.throbber.start(); diff --git a/frontend/app/components/op_profile/op_profile.ts b/frontend/app/components/op_profile/op_profile.ts index d3556734..0508bf91 100644 --- a/frontend/app/components/op_profile/op_profile.ts +++ b/frontend/app/components/op_profile/op_profile.ts @@ -6,7 +6,7 @@ import {OpProfileProto} from 'org_xprof/frontend/app/common/interfaces/data_tabl import {setLoadingState} from 'org_xprof/frontend/app/common/utils/utils'; import {DATA_SERVICE_INTERFACE_TOKEN, DataServiceV2Interface} from 'org_xprof/frontend/app/services/data_service_v2/data_service_v2_interface'; import {setProfilingDeviceTypeAction} from 'org_xprof/frontend/app/store/actions'; -import {Observable, of, ReplaySubject} from 'rxjs'; +import {combineLatest, Observable, of, ReplaySubject} from 'rxjs'; import {combineLatestWith, map, takeUntil} from 'rxjs/operators'; const GROUP_BY_RULES = ['program', 'category', 'provenance']; @@ -37,15 +37,18 @@ export class OpProfile implements OnDestroy { route: ActivatedRoute, private readonly store: Store<{}>, ) { - route.params.pipe(takeUntil(this.destroyed)).subscribe((params) => { - this.processQuery(params); - this.update(); - }); + combineLatest([route.params, route.queryParams]) + .pipe(takeUntil(this.destroyed)) + .subscribe(([params, queryParams]) => { + this.sessionId = params['sessionId'] || this.sessionId; + this.processQueryParams(queryParams); + this.update(); + }); } - processQuery(params: Params) { + processQueryParams(params: Params) { this.sessionId = params['run'] || params['sessionId'] || this.sessionId; - this.tool = params['tag'] || params['tool'] || this.tool; + this.tool = params['tag'] || this.tool; this.host = params['host'] || this.host; } @@ -77,6 +80,9 @@ export class OpProfile implements OnDestroy { } update() { + if (!this.sessionId || !this.tool) { + return; + } const $data = this.fetchData(this.groupBy); const $moduleList = this.dataService.getModuleList( this.sessionId, diff --git a/frontend/app/components/overview_page/overview_page_module.ts b/frontend/app/components/overview_page/overview_page_module.ts index f4a44a15..be64b011 100644 --- a/frontend/app/components/overview_page/overview_page_module.ts +++ b/frontend/app/components/overview_page/overview_page_module.ts @@ -10,10 +10,10 @@ import {InferenceLatencyChartModule} from 'org_xprof/frontend/app/components/ove import {PerformanceSummaryModule} from 'org_xprof/frontend/app/components/overview_page/performance_summary/performance_summary_module'; import {RunEnvironmentViewModule} from 'org_xprof/frontend/app/components/overview_page/run_environment_view/run_environment_view_module'; import {StepTimeGraphModule} from 'org_xprof/frontend/app/components/overview_page/step_time_graph/step_time_graph_module'; +import {SmartSuggestionView} from 'org_xprof/frontend/app/components/smart_suggestion/smart_suggestion_view'; import {DATA_SERVICE_INTERFACE_TOKEN, type DataServiceV2Interface} from 'org_xprof/frontend/app/services/data_service_v2/data_service_v2_interface'; -import {ReplaySubject} from 'rxjs'; +import {combineLatest, ReplaySubject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; -import {SmartSuggestionView} from 'org_xprof/frontend/app/components/smart_suggestion/smart_suggestion_view'; const GENERAL_ANALYSIS_INDEX = 0; const INPUT_PIPELINE_ANALYSIS_INDEX = 1; @@ -51,9 +51,11 @@ export class OverviewPage implements OnDestroy { private readonly store: Store = inject(Store); constructor() { - this.route.params.pipe(takeUntil(this.destroyed)) - .subscribe((params: Params) => { - this.processQuery(params); + combineLatest([this.route.params, this.route.queryParams]) + .pipe(takeUntil(this.destroyed)) + .subscribe(([params, queryParams]) => { + this.sessionId = params['sessionId'] || this.sessionId; + this.processQueryParams(queryParams); this.update(); }); } @@ -74,9 +76,9 @@ export class OverviewPage implements OnDestroy { return !this.isInference; } - processQuery(params: Params) { + processQueryParams(params: Params) { this.host = params['host'] || this.host || ''; - this.sessionId = params['run'] || params['sessionId'] || ''; + this.sessionId = params['run'] || params['sessionId'] || this.sessionId; this.tool = params['tag'] || 'overview_page'; } diff --git a/frontend/app/components/perf_counters/perf_counters.ts b/frontend/app/components/perf_counters/perf_counters.ts index a090a555..acf70c39 100644 --- a/frontend/app/components/perf_counters/perf_counters.ts +++ b/frontend/app/components/perf_counters/perf_counters.ts @@ -1,5 +1,5 @@ import {Component, inject, OnDestroy} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; +import {ActivatedRoute, Params} from '@angular/router'; import {Store} from '@ngrx/store'; import {Throbber} from 'org_xprof/frontend/app/common/classes/throbber'; import {SimpleDataTable} from 'org_xprof/frontend/app/common/interfaces/data_table'; @@ -7,7 +7,7 @@ import {setLoadingState} from 'org_xprof/frontend/app/common/utils/utils'; import {Dashboard} from 'org_xprof/frontend/app/components/chart/dashboard/dashboard'; import {DATA_SERVICE_INTERFACE_TOKEN, DataServiceV2Interface} from 'org_xprof/frontend/app/services/data_service_v2/data_service_v2_interface'; import {setCurrentToolStateAction} from 'org_xprof/frontend/app/store/actions'; -import {ReplaySubject} from 'rxjs'; +import {combineLatest, ReplaySubject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; /** A perf counters component. */ @@ -18,7 +18,8 @@ import {takeUntil} from 'rxjs/operators'; styleUrls: ['./perf_counters.scss'], }) export class PerfCounters extends Dashboard implements OnDestroy { - readonly tool = 'perf_counters'; + tool = 'perf_counters'; + host = ''; /** Handles on-destroy Subject, used to unsubscribe. */ private readonly destroyed = new ReplaySubject(1); readonly pageSizeOptions = [30, 50, 100, 200]; @@ -34,13 +35,22 @@ export class PerfCounters extends Dashboard implements OnDestroy { private readonly store: Store<{}>, ) { super(); - route.params.pipe(takeUntil(this.destroyed)).subscribe((params) => { - this.sessionId = (params || {})['sessionId'] || ''; - this.update(); - }); + combineLatest([route.params, route.queryParams]) + .pipe(takeUntil(this.destroyed)) + .subscribe(([params, queryParams]) => { + this.sessionId = params['sessionId'] || this.sessionId; + this.processQueryParams(queryParams); + this.update(); + }); this.store.dispatch(setCurrentToolStateAction({currentTool: this.tool})); } + processQueryParams(params: Params) { + this.sessionId = params['run'] || params['sessionId'] || this.sessionId; + this.tool = params['tag'] || this.tool; + this.host = params['host'] || this.host; + } + update() { setLoadingState(true, this.store, 'Loading perf counters data'); this.throbber.start(); diff --git a/frontend/app/components/roofline_model/roofline_model.ts b/frontend/app/components/roofline_model/roofline_model.ts index 94128571..7e865ac3 100644 --- a/frontend/app/components/roofline_model/roofline_model.ts +++ b/frontend/app/components/roofline_model/roofline_model.ts @@ -7,7 +7,7 @@ import {RooflineModelData} from 'org_xprof/frontend/app/common/interfaces/roofli import {getGigaflopsReadableString, setLoadingState} from 'org_xprof/frontend/app/common/utils/utils'; import {DATA_SERVICE_INTERFACE_TOKEN, DataServiceV2Interface} from 'org_xprof/frontend/app/services/data_service_v2/data_service_v2_interface'; import {setCurrentToolStateAction} from 'org_xprof/frontend/app/store/actions'; -import {ReplaySubject} from 'rxjs'; +import {combineLatest, ReplaySubject} from 'rxjs'; import {take, takeUntil} from 'rxjs/operators'; import {OperationLevelAnalysis} from './operation_level_analysis/operation_level_analysis'; @@ -117,10 +117,13 @@ export class RooflineModel implements OnDestroy { route: ActivatedRoute, private readonly store: Store<{}>, ) { - route.params.pipe(takeUntil(this.destroyed)).subscribe((params) => { - this.processQuery(params); - this.update(); - }); + combineLatest([route.params, route.queryParams]) + .pipe(takeUntil(this.destroyed)) + .subscribe(([params, queryParams]) => { + this.sessionId = params['sessionId'] || this.sessionId; + this.processQueryParams(queryParams); + this.update(); + }); this.store.dispatch(setCurrentToolStateAction({currentTool: this.tool})); } @@ -158,13 +161,16 @@ export class RooflineModel implements OnDestroy { this.opLevelAnalysis?.resetDashboard(); } - processQuery(params: Params) { + processQueryParams(params: Params) { this.sessionId = params['run'] || params['sessionId'] || this.sessionId; - this.tool = params['tag'] || params['tool'] || this.tool; + this.tool = params['tag'] || this.tool; this.host = params['host'] || this.host; } update() { + if (!this.sessionId || !this.tool) { + return; + } setLoadingState(true, this.store, 'Loading roofline model data'); this.throbber.start(); this.refreshDashboards(); diff --git a/frontend/app/components/sidenav/sidenav.ts b/frontend/app/components/sidenav/sidenav.ts index 6bff0a7a..7812b0f1 100644 --- a/frontend/app/components/sidenav/sidenav.ts +++ b/frontend/app/components/sidenav/sidenav.ts @@ -433,13 +433,13 @@ export class SideNav implements OnInit, OnDestroy { // This router.navigate call remains, as it's responsible for Angular // routing + // TODO - b/401596855: Deprecate the navigationEvent in route.params as we + // are subscribing to the queryParams in the components. this.router.navigate( [ this.selectedTag || 'empty', navigationEvent, ], - // TODO - b/401596855: Clean up query processing in tools component with - // addition of the query params in navigation. { queryParams: navigationEvent, }); diff --git a/frontend/app/components/stack_trace_page/stack_trace_page.ts b/frontend/app/components/stack_trace_page/stack_trace_page.ts index c2fd7c9a..b47faea3 100644 --- a/frontend/app/components/stack_trace_page/stack_trace_page.ts +++ b/frontend/app/components/stack_trace_page/stack_trace_page.ts @@ -1,7 +1,7 @@ import {Component, inject, Injector, OnDestroy} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; +import {ActivatedRoute, Params} from '@angular/router'; import {SOURCE_CODE_SERVICE_INTERFACE_TOKEN} from 'org_xprof/frontend/app/services/source_code_service/source_code_service_interface'; -import {ReplaySubject} from 'rxjs'; +import {combineLatest, ReplaySubject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; /** @@ -52,22 +52,24 @@ export class StackTracePage implements OnDestroy { ); this.sourceCodeServiceIsAvailable = sourceCodeService?.isAvailable() === true; - - this.route.queryParams.pipe(takeUntil(this.destroyed)) - .subscribe((params) => { - this.hloModule = params[this.hloModuleKey] || ''; - this.hloOp = params[this.hloOpKey] || ''; - this.sourceFileAndLineNumber = params[this.sourceKey] || ''; - this.stackTrace = params[this.stackTraceKey] || ''; - const regex = /\((.*?)\)/; - const programIdMatch = this.hloModule.match(regex); - this.programId = programIdMatch ? programIdMatch[1] : ''; - this.sessionId = params[this.sessionIdKey] || params['run'] || ''; - this.opCategory = params[this.opCategoryKey] || ''; + combineLatest([this.route.params, this.route.queryParams]) + .pipe(takeUntil(this.destroyed)) + .subscribe(([params, queryParams]) => { + this.sessionId = params['sessionId'] || this.sessionId; + this.processQueryParams(queryParams); }); - this.route.params.pipe(takeUntil(this.destroyed)).subscribe((params) => { - this.sessionId = params['sessionId'] || this.sessionId; - }); + } + + processQueryParams(params: Params) { + this.hloModule = params[this.hloModuleKey] || ''; + this.hloOp = params[this.hloOpKey] || ''; + this.sourceFileAndLineNumber = params[this.sourceKey] || ''; + this.stackTrace = params[this.stackTraceKey] || ''; + const regex = /\((.*?)\)/; + const programIdMatch = this.hloModule.match(regex); + this.programId = programIdMatch ? programIdMatch[1] : ''; + this.sessionId = params[this.sessionIdKey] || params['run'] || ''; + this.opCategory = params[this.opCategoryKey] || ''; } ngOnDestroy(): void { diff --git a/frontend/app/components/trace_viewer/trace_viewer.ts b/frontend/app/components/trace_viewer/trace_viewer.ts index c3e73432..ffe9321a 100644 --- a/frontend/app/components/trace_viewer/trace_viewer.ts +++ b/frontend/app/components/trace_viewer/trace_viewer.ts @@ -1,10 +1,9 @@ import {PlatformLocation} from '@angular/common'; import {Component, inject, Injector, OnDestroy} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; +import {ActivatedRoute, Params} from '@angular/router'; import {API_PREFIX, DATA_API, PLUGIN_NAME} from 'org_xprof/frontend/app/common/constants/constants'; -import {NavigationEvent} from 'org_xprof/frontend/app/common/interfaces/navigation_event'; import {SOURCE_CODE_SERVICE_INTERFACE_TOKEN} from 'org_xprof/frontend/app/services/source_code_service/source_code_service_interface'; -import {ReplaySubject} from 'rxjs'; +import {combineLatest, ReplaySubject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; /** A trace viewer component. */ @@ -21,6 +20,12 @@ export class TraceViewer implements OnDestroy { url = ''; pathPrefix = ''; + sessionId = ''; + host = ''; + hosts = ''; // Comma-separated list of hosts, to support multi-host sessions. + tool = 'trace_viewer'; + runPath = ''; + sessionPath = ''; constructor( platformLocation: PlatformLocation, @@ -30,30 +35,39 @@ export class TraceViewer implements OnDestroy { this.pathPrefix = String(platformLocation.pathname).split(API_PREFIX + PLUGIN_NAME)[0]; } - route.params.pipe(takeUntil(this.destroyed)).subscribe((params) => { - this.update(params as NavigationEvent); - }); + combineLatest([route.params, route.queryParams]) + .pipe(takeUntil(this.destroyed)) + .subscribe(([params, queryParams]) => { + this.sessionId = params['sessionId'] || this.sessionId; + this.processQueryParams(queryParams); + this.update(); + }); } - update(event: NavigationEvent) { - const isStreaming = (event.tag === 'trace_viewer@'); - const run = event.run || ''; - const tag = event.tag || ''; - const runPath = event.run_path || ''; - const sessionPath = event.session_path || ''; - let queryString = `run=${run}&tag=${tag}`; + processQueryParams(params: Params) { + this.sessionId = params['run'] || params['sessionId'] || this.sessionId; + this.tool = params['tag'] || this.tool; + this.host = params['host'] || this.host; + this.hosts = params['hosts'] || this.hosts; + this.runPath = params['run_path'] || this.runPath; + this.sessionPath = params['session_path'] || this.sessionPath; + } + + update() { + const isStreaming = (this.tool === 'trace_viewer@'); + let queryString = `run=${this.sessionId}&tag=${this.tool}`; - if (sessionPath) { - queryString += `&session_path=${sessionPath}`; - } else if (runPath) { - queryString += `&run_path=${runPath}`; + if (this.sessionPath) { + queryString += `&session_path=${this.sessionPath}`; + } else if (this.runPath) { + queryString += `&run_path=${this.runPath}`; } - if (event.hosts && typeof event.hosts === 'string') { + if (this.hosts && typeof this.hosts === 'string') { // Since event.hosts is a comma-separated string, we can use it directly. - queryString += `&hosts=${event.hosts}`; - } else if (event.host) { - queryString += `&host=${event.host}`; + queryString += `&hosts=${this.hosts}`; + } else if (this.host) { + queryString += `&host=${this.host}`; } const traceDataUrl = `${this.pathPrefix}${DATA_API}?${queryString}`; diff --git a/frontend/app/components/utilization_viewer/utilization_viewer.ts b/frontend/app/components/utilization_viewer/utilization_viewer.ts index 71fd1eae..db6d99c2 100644 --- a/frontend/app/components/utilization_viewer/utilization_viewer.ts +++ b/frontend/app/components/utilization_viewer/utilization_viewer.ts @@ -1,20 +1,17 @@ import {Component, inject, OnDestroy} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; +import {ActivatedRoute, Params} from '@angular/router'; import {Store} from '@ngrx/store'; import {Throbber} from 'org_xprof/frontend/app/common/classes/throbber'; import {ChartDataInfo, ChartType} from 'org_xprof/frontend/app/common/interfaces/chart'; import {SimpleDataTable} from 'org_xprof/frontend/app/common/interfaces/data_table'; import {setLoadingState} from 'org_xprof/frontend/app/common/utils/utils'; -import { - BAR_CHART_OPTIONS, - PIE_CHART_OPTIONS, -} from 'org_xprof/frontend/app/components/chart/chart_options'; +import {BAR_CHART_OPTIONS, PIE_CHART_OPTIONS, } from 'org_xprof/frontend/app/components/chart/chart_options'; import {Dashboard} from 'org_xprof/frontend/app/components/chart/dashboard/dashboard'; import {DefaultDataProvider} from 'org_xprof/frontend/app/components/chart/default_data_provider'; import {FilterDataProcessor} from 'org_xprof/frontend/app/components/chart/filter_data_processor'; import {DATA_SERVICE_INTERFACE_TOKEN, DataServiceV2Interface} from 'org_xprof/frontend/app/services/data_service_v2/data_service_v2_interface'; import {setCurrentToolStateAction} from 'org_xprof/frontend/app/store/actions'; -import {ReplaySubject} from 'rxjs'; +import {combineLatest, ReplaySubject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; const UNIT_CHART_OPTIONS: google.visualization.BarChartOptions = { @@ -74,6 +71,7 @@ export class UtilizationViewer extends Dashboard implements OnDestroy { private readonly throbber = new Throbber(this.tool); sessionId = ''; + host = ''; dataService: DataServiceV2Interface = inject(DATA_SERVICE_INTERFACE_TOKEN); dataProvider = new DefaultDataProvider(); dataInfoTensorNodesUnit: Partial = {}; @@ -94,8 +92,21 @@ export class UtilizationViewer extends Dashboard implements OnDestroy { this.sessionId = (params || {})['sessionId'] || ''; this.update(); }); + combineLatest([route.params, route.queryParams]) + .pipe(takeUntil(this.destroyed)) + .subscribe(([params, queryParams]) => { + this.sessionId = params['sessionId'] || this.sessionId; + this.processQueryParams(queryParams); + this.update(); + }); this.store.dispatch(setCurrentToolStateAction({currentTool: this.tool})); } + + processQueryParams(params: Params) { + this.sessionId = params['run'] || params['sessionId'] || this.sessionId; + this.host = params['host'] || this.host; + } + update() { setLoadingState(true, this.store, 'Loading utilization viewer data'); this.throbber.start();