Skip to content

Commit 6103a8a

Browse files
Profiler Teamcopybara-github
authored andcommitted
This helps work with logdirs that contains a large numbers of profile traces.
PiperOrigin-RevId: 833948649
1 parent 37f884a commit 6103a8a

File tree

12 files changed

+124
-9
lines changed

12 files changed

+124
-9
lines changed

frontend/app/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ xprof_ng_module(
1515
],
1616
deps = [
1717
"@npm//@angular/core",
18+
"@npm//@angular/forms",
1819
"@npm//@angular/platform-browser",
1920
"@npm//@ngrx/store",
2021
"@npm//rxjs",

frontend/app/app.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,31 @@ export class App implements OnInit {
4040
this.loading = false;
4141
return;
4242
}
43+
44+
let filteredRuns = runs;
45+
46+
const config = await firstValueFrom(this.dataService.getConfig());
47+
if (config?.filterSessions) {
48+
try {
49+
const regex = new RegExp(config.filterSessions, 'i');
50+
filteredRuns = runs.filter(run => regex.test(run));
51+
} catch (e) {
52+
console.error('Invalid regex for session filter:', e);
53+
// fallback to no filtering if regex is invalid
54+
filteredRuns = runs;
55+
}
56+
57+
// fallback to no filtering if regex finds nothing
58+
if (filteredRuns.length === 0) {
59+
filteredRuns = runs;
60+
}
61+
}
62+
4363
this.dataFound = true;
44-
this.store.dispatch(actions.setCurrentRunAction({currentRun: runs[0]}));
64+
this.store.dispatch(actions.setCurrentRunAction({currentRun: filteredRuns[0]}));
4565
const tools =
46-
await firstValueFrom(this.dataService.getRunTools(runs[0])) as string[];
47-
const runToolsMap: RunToolsMap = {[runs[0]]: tools};
66+
await firstValueFrom(this.dataService.getRunTools(filteredRuns[0])) as string[];
67+
const runToolsMap: RunToolsMap = {[filteredRuns[0]]: tools};
4868
for (let i = 1; i < runs.length; i++) {
4969
runToolsMap[runs[i]] = [];
5070
}

frontend/app/app_module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {HttpClientModule} from '@angular/common/http';
22
import {NgModule} from '@angular/core';
3+
import {FormsModule} from '@angular/forms';
34
import {MatProgressBarModule} from '@angular/material/progress-bar';
45
import {BrowserModule} from '@angular/platform-browser';
56
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
@@ -21,6 +22,7 @@ import {App} from './app';
2122
imports: [
2223
BrowserModule,
2324
HttpClientModule,
25+
FormsModule,
2426
MatProgressBarModule,
2527
EmptyPageModule,
2628
MainPageModule,

frontend/app/components/controls/view_architecture/view_architecture.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export class ViewArchitecture implements OnInit, OnDestroy {
2020
private readonly dataService: DataServiceV2Interface =
2121
inject(DATA_SERVICE_INTERFACE_TOKEN);
2222
hideViewArchitectureButton = true;
23+
filterSessions = '';
2324
private readonly destroyed = new ReplaySubject<void>(1);
2425

2526
ngOnInit() {
@@ -28,6 +29,7 @@ export class ViewArchitecture implements OnInit, OnDestroy {
2829
.subscribe((config) => {
2930
this.hideViewArchitectureButton =
3031
config?.hideCaptureProfileButton || false;
32+
this.filterSessions = config?.filterSessions || '';
3133
});
3234
}
3335

frontend/app/components/sidenav/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,18 @@ xprof_ng_module(
1515
],
1616
deps = [
1717
"@npm//@angular/core",
18+
"@npm//@angular/forms",
1819
"@npm//@angular/router",
1920
"@npm//@ngrx/store",
2021
"@npm//rxjs",
2122
"@org_xprof//frontend/app/common/angular:angular_material_button",
2223
"@org_xprof//frontend/app/common/angular:angular_material_checkbox",
2324
"@org_xprof//frontend/app/common/angular:angular_material_core",
2425
"@org_xprof//frontend/app/common/angular:angular_material_form_field",
26+
"@org_xprof//frontend/app/common/angular:angular_material_icon",
27+
"@org_xprof//frontend/app/common/angular:angular_material_input",
2528
"@org_xprof//frontend/app/common/angular:angular_material_select",
29+
"@org_xprof//frontend/app/common/angular:angular_material_tooltip",
2630
"@org_xprof//frontend/app/common/constants",
2731
"@org_xprof//frontend/app/common/interfaces",
2832
"@org_xprof//frontend/app/components/capture_profile",

frontend/app/components/sidenav/sidenav.ng.html

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,40 @@
33
</div>
44

55
<!-- TODO(bhupendradubey): Rename internal variables and function names (e.g., `runs`, `selectedRun`, `onRunSelectionChange`) to use `session` instead of `run` for consistency. -->
6+
<div class="item-container" *ngIf="runs.length > 1">
7+
<div [ngClass]="{'mat-subheading-2': true}">
8+
Filter Sessions
9+
<mat-icon
10+
class="tooltip-icon"
11+
matTooltip=
12+
"Input a regex to filter the sessions. Press 'Enter' to select the first filtered
13+
session or select the session you want from the dropdown."
14+
matTooltipPosition="right">
15+
info
16+
</mat-icon>
17+
</div>
18+
19+
<mat-form-field class="full-width" appearance="outline">
20+
<mat-icon matPrefix>search</mat-icon>
21+
<input
22+
matInput
23+
placeholder="Filter sessions"
24+
aria-label="Filter sessions"
25+
[(ngModel)]="filterSessions"
26+
(keyup)="filterRuns()"
27+
(keyup.enter)="applyFilterAndSelectFirst()"
28+
/>
29+
</mat-form-field>
30+
</div>
31+
632
<div class="item-container">
733
<div [ngClass]="{'mat-subheading-2': true, 'disabled': !runs.length}">
8-
Sessions ({{runs.length}})
34+
Sessions ({{filteredRuns.length}}/{{runs.length}})
935
</div>
1036

1137
<mat-form-field class="full-width" appearance="outline">
1238
<mat-select panelClass="panel-override" [value]="selectedRun" [disabled]="!runs.length" (selectionChange)="onRunSelectionChange($event.value)">
13-
<mat-option *ngFor="let run of runs" [value]="run">
39+
<mat-option *ngFor="let run of filteredRuns" [value]="run">
1440
{{run}}
1541
</mat-option>
1642
</mat-select>

frontend/app/components/sidenav/sidenav.scss

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@
1010
padding: 20px 20px 0 20px;
1111
}
1212

13+
.tooltip-icon {
14+
color: #e8710a;
15+
font-size: 25px;
16+
vertical-align: bottom;
17+
cursor: pointer;
18+
}
19+
20+
.mat-form-field {
21+
margin-bottom: 10px;
22+
}
23+
1324
.mat-subheading-2 {
1425
margin-bottom: 0;
1526
}
@@ -21,7 +32,6 @@
2132

2233
// Target the custom panel class defined in sidenav.ng.html
2334
.multi-host-select-panel {
24-
2535
.full-width {
2636
width: 100%;
2737
}

frontend/app/components/sidenav/sidenav.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export class SideNav implements OnInit, OnDestroy {
2727

2828
runToolsMap: RunToolsMap = {};
2929
runs: string[] = [];
30+
filteredRuns: string[] = [];
3031
tags: string[] = [];
3132
hosts: string[] = [];
3233
moduleList: string[] = [];
@@ -41,6 +42,7 @@ export class SideNav implements OnInit, OnDestroy {
4142
allHostsSelected = false;
4243

4344
hideCaptureProfileButton = false;
45+
filterSessions = '';
4446

4547
constructor(
4648
private readonly router: Router,
@@ -58,6 +60,7 @@ export class SideNav implements OnInit, OnDestroy {
5860
this.runToolsMap$.subscribe((runTools: RunToolsMap) => {
5961
this.runToolsMap = runTools;
6062
this.runs = Object.keys(this.runToolsMap);
63+
this.filterRuns();
6164
});
6265
this.currentRun$.subscribe(run => {
6366
if (run && !this.selectedRunInternal) {
@@ -66,6 +69,21 @@ export class SideNav implements OnInit, OnDestroy {
6669
});
6770
}
6871

72+
filterRuns(): void {
73+
if (!this.filterSessions) {
74+
this.filteredRuns = this.runs;
75+
return;
76+
}
77+
try {
78+
const regex = new RegExp(this.filterSessions, 'i');
79+
this.filteredRuns = this.runs.filter(run => regex.test(run));
80+
} catch (e) {
81+
console.error('Invalid regex for session filter:', e);
82+
// fallback to no filtering or previous state if regex is invalid
83+
this.filteredRuns = this.runs;
84+
}
85+
}
86+
6987
get is_hlo_tool() {
7088
return HLO_TOOLS.includes(this.selectedTag);
7189
}
@@ -77,8 +95,9 @@ export class SideNav implements OnInit, OnDestroy {
7795

7896
// Getter for valid run given url router or user selection.
7997
get selectedRun() {
80-
return this.runs.find(validRun => validRun === this.selectedRunInternal) ||
81-
this.runs[0] || '';
98+
return this.filteredRuns.find(
99+
validRun => validRun === this.selectedRunInternal) ||
100+
this.filteredRuns[0] || '';
82101
}
83102

84103
// Getter for valid tag given url router or user selection.
@@ -165,7 +184,8 @@ export class SideNav implements OnInit, OnDestroy {
165184
const config = await firstValueFrom(
166185
this.dataService.getConfig().pipe(takeUntil(this.destroyed)));
167186
if (config) {
168-
this.hideCaptureProfileButton = config.hideCaptureProfileButton;
187+
this.filterSessions = config.filterSessions;
188+
this.filterRuns();
169189
}
170190
}
171191

@@ -246,6 +266,12 @@ export class SideNav implements OnInit, OnDestroy {
246266
return response.split(',');
247267
}
248268

269+
applyFilterAndSelectFirst() {
270+
if (this.filteredRuns.length > 0) {
271+
this.onRunSelectionChange(this.filteredRuns[0]);
272+
}
273+
}
274+
249275
onRunSelectionChange(run: string) {
250276
this.selectedRunInternal = run;
251277
this.afterUpdateRun();

frontend/app/components/sidenav/sidenav_module.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import {CommonModule} from '@angular/common';
22
import {NgModule} from '@angular/core';
3+
import {FormsModule} from '@angular/forms';
34
import {MatButtonModule} from '@angular/material/button';
45
import {MatCheckboxModule} from '@angular/material/checkbox';
56
import {MatOptionModule} from '@angular/material/core';
67
import {MatFormFieldModule} from '@angular/material/form-field';
8+
import {MatIconModule} from '@angular/material/icon';
9+
import {MatInputModule} from '@angular/material/input';
710
import {MatSelectModule} from '@angular/material/select';
11+
import {MatTooltipModule} from '@angular/material/tooltip';
812
import {CaptureProfileModule} from 'org_xprof/frontend/app/components/capture_profile/capture_profile_module';
913
import {BufferDetailsModule} from 'org_xprof/frontend/app/components/memory_viewer/buffer_details/buffer_details_module';
1014
import {OpDetailsModule} from 'org_xprof/frontend/app/components/op_profile/op_details/op_details_module';
@@ -18,10 +22,14 @@ import {SideNav} from './sidenav';
1822
imports: [
1923
CommonModule,
2024
MatButtonModule,
25+
FormsModule,
2126
MatCheckboxModule,
2227
MatFormFieldModule,
28+
MatIconModule,
29+
MatInputModule,
2330
MatSelectModule,
2431
MatOptionModule,
32+
MatTooltipModule,
2533
BufferDetailsModule,
2634
CaptureProfileModule,
2735
OpDetailsModule,

frontend/app/services/data_service_v2/data_service_v2_interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {type SmartSuggestionReport} from 'org_xprof/frontend/app/common/interfac
1414
/** A serializable object with profiler configuration details. */
1515
export interface ProfilerConfig {
1616
hideCaptureProfileButton: boolean;
17+
filterSessions: string;
1718
}
1819

1920
/** The data service class that calls API and return response. */

0 commit comments

Comments
 (0)