Add transaction ids to viewer and a filter for them

Fixes: 284264724
Test: npm run test:all
Change-Id: I8e33f72f0ae35c232f3efc251c5371f895112345
This commit is contained in:
Pablo Gamito
2023-06-08 15:34:32 +00:00
parent 09a1c31019
commit 166b11bcb5
7 changed files with 101 additions and 28 deletions

View File

@@ -19,9 +19,10 @@ class Events {
static PidFilterChanged = 'ViewerTransactionsEvent_PidFilterChanged'; static PidFilterChanged = 'ViewerTransactionsEvent_PidFilterChanged';
static UidFilterChanged = 'ViewerTransactionsEvent_UidFilterChanged'; static UidFilterChanged = 'ViewerTransactionsEvent_UidFilterChanged';
static TypeFilterChanged = 'ViewerTransactionsEvent_TypeFilterChanged'; static TypeFilterChanged = 'ViewerTransactionsEvent_TypeFilterChanged';
static IdFilterChanged = 'ViewerTransactionsEvent_IdFilterChanged'; static LayerIdFilterChanged = 'ViewerTransactionsEvent_LayerIdFilterChanged';
static WhatSearchStringChanged = 'ViewerTransactionsEvent_WhatSearchStringChanged'; static WhatSearchStringChanged = 'ViewerTransactionsEvent_WhatSearchStringChanged';
static EntryClicked = 'ViewerTransactionsEvent_EntryClicked'; static EntryClicked = 'ViewerTransactionsEvent_EntryClicked';
static IdFilterChanges = 'ViewerTransactionsEvent_IdFilterChanged';
} }
export {Events}; export {Events};

View File

@@ -38,7 +38,8 @@ export class Presenter {
private pidFilter: string[] = []; private pidFilter: string[] = [];
private uidFilter: string[] = []; private uidFilter: string[] = [];
private typeFilter: string[] = []; private typeFilter: string[] = [];
private idFilter: string[] = []; private layerIdFilter: string[] = [];
private idFilter: string | undefined = undefined;
private whatSearchString = ''; private whatSearchString = '';
constructor(traces: Traces, notifyUiDataCallback: (data: UiData) => void) { constructor(traces: Traces, notifyUiDataCallback: (data: UiData) => void) {
@@ -88,8 +89,18 @@ export class Presenter {
this.notifyUiDataCallback(this.uiData); this.notifyUiDataCallback(this.uiData);
} }
onIdFilterChanged(ids: string[]) { onLayerIdFilterChanged(ids: string[]) {
this.idFilter = ids; this.layerIdFilter = ids;
this.computeUiData();
this.notifyUiDataCallback(this.uiData);
}
onIdFilterChanged(id: string) {
if (id === '') {
this.idFilter = undefined;
} else {
this.idFilter = id;
}
this.computeUiData(); this.computeUiData();
this.notifyUiDataCallback(this.uiData); this.notifyUiDataCallback(this.uiData);
} }
@@ -127,7 +138,14 @@ export class Presenter {
const allPids = this.getUniqueUiDataEntryValues(entries, (entry: UiDataEntry) => entry.pid); const allPids = this.getUniqueUiDataEntryValues(entries, (entry: UiDataEntry) => entry.pid);
const allUids = this.getUniqueUiDataEntryValues(entries, (entry: UiDataEntry) => entry.uid); const allUids = this.getUniqueUiDataEntryValues(entries, (entry: UiDataEntry) => entry.uid);
const allTypes = this.getUniqueUiDataEntryValues(entries, (entry: UiDataEntry) => entry.type); const allTypes = this.getUniqueUiDataEntryValues(entries, (entry: UiDataEntry) => entry.type);
const allIds = this.getUniqueUiDataEntryValues(entries, (entry: UiDataEntry) => entry.id); const allLayerAndDisplayIds = this.getUniqueUiDataEntryValues(
entries,
(entry: UiDataEntry) => entry.layerOrDisplayId
);
const allTransactionIds = this.getUniqueUiDataEntryValues(
entries,
(entry: UiDataEntry) => entry.transactionId
);
let filteredEntries = entries; let filteredEntries = entries;
@@ -149,8 +167,15 @@ export class Presenter {
filteredEntries = filteredEntries.filter((entry) => this.typeFilter.includes(entry.type)); filteredEntries = filteredEntries.filter((entry) => this.typeFilter.includes(entry.type));
} }
if (this.idFilter.length > 0) { if (this.layerIdFilter.length > 0) {
filteredEntries = filteredEntries.filter((entry) => this.idFilter.includes(entry.id)); filteredEntries = filteredEntries.filter((entry) =>
this.layerIdFilter.includes(entry.layerOrDisplayId)
);
}
if (this.idFilter !== undefined) {
filteredEntries = filteredEntries.filter(
(entry) => entry.transactionId.toString() === this.idFilter
);
} }
filteredEntries = filteredEntries.filter((entry) => entry.what.includes(this.whatSearchString)); filteredEntries = filteredEntries.filter((entry) => entry.what.includes(this.whatSearchString));
@@ -172,7 +197,8 @@ export class Presenter {
allPids, allPids,
allUids, allUids,
allTypes, allTypes,
allIds, allLayerAndDisplayIds,
allTransactionIds,
filteredEntries, filteredEntries,
currentEntryIndex, currentEntryIndex,
selectedEntryIndex, selectedEntryIndex,
@@ -234,6 +260,7 @@ export class Presenter {
transactionStateProto.uid.toString(), transactionStateProto.uid.toString(),
UiDataEntryType.LAYER_CHANGED, UiDataEntryType.LAYER_CHANGED,
layerStateProto.layerId.toString(), layerStateProto.layerId.toString(),
transactionStateProto.transactionId.toString(),
layerStateProto.what, layerStateProto.what,
treeGenerator.generate('LayerState', ObjectFormatter.format(layerStateProto)) treeGenerator.generate('LayerState', ObjectFormatter.format(layerStateProto))
) )
@@ -250,6 +277,7 @@ export class Presenter {
transactionStateProto.uid.toString(), transactionStateProto.uid.toString(),
UiDataEntryType.DISPLAY_CHANGED, UiDataEntryType.DISPLAY_CHANGED,
displayStateProto.id.toString(), displayStateProto.id.toString(),
transactionStateProto.transactionId.toString(),
displayStateProto.what, displayStateProto.what,
treeGenerator.generate('DisplayState', ObjectFormatter.format(displayStateProto)) treeGenerator.generate('DisplayState', ObjectFormatter.format(displayStateProto))
) )
@@ -268,6 +296,7 @@ export class Presenter {
UiDataEntryType.LAYER_ADDED, UiDataEntryType.LAYER_ADDED,
layerCreationArgsProto.layerId.toString(), layerCreationArgsProto.layerId.toString(),
'', '',
'',
treeGenerator.generate( treeGenerator.generate(
'LayerCreationArgs', 'LayerCreationArgs',
ObjectFormatter.format(layerCreationArgsProto) ObjectFormatter.format(layerCreationArgsProto)
@@ -287,6 +316,7 @@ export class Presenter {
UiDataEntryType.LAYER_DESTROYED, UiDataEntryType.LAYER_DESTROYED,
destroyedLayerId.toString(), destroyedLayerId.toString(),
'', '',
'',
treeGenerator.generate('DestroyedLayerId', ObjectFormatter.format(destroyedLayerId)) treeGenerator.generate('DestroyedLayerId', ObjectFormatter.format(destroyedLayerId))
) )
); );
@@ -302,6 +332,7 @@ export class Presenter {
Presenter.VALUE_NA, Presenter.VALUE_NA,
UiDataEntryType.DISPLAY_ADDED, UiDataEntryType.DISPLAY_ADDED,
displayStateProto.id.toString(), displayStateProto.id.toString(),
'',
displayStateProto.what, displayStateProto.what,
treeGenerator.generate('DisplayState', ObjectFormatter.format(displayStateProto)) treeGenerator.generate('DisplayState', ObjectFormatter.format(displayStateProto))
) )
@@ -319,6 +350,7 @@ export class Presenter {
UiDataEntryType.DISPLAY_REMOVED, UiDataEntryType.DISPLAY_REMOVED,
removedDisplayId.toString(), removedDisplayId.toString(),
'', '',
'',
treeGenerator.generate('RemovedDisplayId', ObjectFormatter.format(removedDisplayId)) treeGenerator.generate('RemovedDisplayId', ObjectFormatter.format(removedDisplayId))
) )
); );
@@ -335,6 +367,7 @@ export class Presenter {
UiDataEntryType.LAYER_HANDLE_DESTROYED, UiDataEntryType.LAYER_HANDLE_DESTROYED,
destroyedLayerHandleId.toString(), destroyedLayerHandleId.toString(),
'', '',
'',
treeGenerator.generate( treeGenerator.generate(
'DestroyedLayerHandleId', 'DestroyedLayerHandleId',
ObjectFormatter.format(destroyedLayerHandleId) ObjectFormatter.format(destroyedLayerHandleId)

View File

@@ -76,7 +76,9 @@ describe('PresenterTransactions', () => {
'LAYER_DESTROYED', 'LAYER_DESTROYED',
'LAYER_HANDLE_DESTROYED', 'LAYER_HANDLE_DESTROYED',
]); ]);
expect(outputUiData?.allIds.length).toEqual(116);
expect(outputUiData?.allTransactionIds.length).toEqual(1152);
expect(outputUiData?.allLayerAndDisplayIds.length).toEqual(116);
expect(outputUiData?.entries.length).toEqual(TOTAL_OUTPUT_ENTRIES); expect(outputUiData?.entries.length).toEqual(TOTAL_OUTPUT_ENTRIES);
@@ -96,6 +98,16 @@ describe('PresenterTransactions', () => {
expect(outputUiData!.scrollToIndex).toEqual(13); expect(outputUiData!.scrollToIndex).toEqual(13);
}); });
it('filters entries according to transaction ID filter', () => {
presenter.onIdFilterChanged('');
expect(outputUiData!.entries.length).toEqual(TOTAL_OUTPUT_ENTRIES);
presenter.onIdFilterChanged('2211908157465');
expect(new Set(outputUiData!.entries.map((entry) => entry.transactionId))).toEqual(
new Set(['2211908157465'])
);
});
it('filters entries according to VSYNC ID filter', () => { it('filters entries according to VSYNC ID filter', () => {
presenter.onVSyncIdFilterChanged([]); presenter.onVSyncIdFilterChanged([]);
expect(outputUiData!.entries.length).toEqual(TOTAL_OUTPUT_ENTRIES); expect(outputUiData!.entries.length).toEqual(TOTAL_OUTPUT_ENTRIES);
@@ -160,15 +172,21 @@ describe('PresenterTransactions', () => {
); );
}); });
it('filters entries according to ID filter', () => { it('filters entries according to layer or display ID filter', () => {
presenter.onIdFilterChanged([]); presenter.onLayerIdFilterChanged([]);
expect(new Set(outputUiData!.entries.map((entry) => entry.id)).size).toBeGreaterThan(20); expect(
new Set(outputUiData!.entries.map((entry) => entry.layerOrDisplayId)).size
).toBeGreaterThan(20);
presenter.onIdFilterChanged(['1']); presenter.onLayerIdFilterChanged(['1']);
expect(new Set(outputUiData!.entries.map((entry) => entry.id))).toEqual(new Set(['1'])); expect(new Set(outputUiData!.entries.map((entry) => entry.layerOrDisplayId))).toEqual(
new Set(['1'])
);
presenter.onIdFilterChanged(['1', '3']); presenter.onLayerIdFilterChanged(['1', '3']);
expect(new Set(outputUiData!.entries.map((entry) => entry.id))).toEqual(new Set(['1', '3'])); expect(new Set(outputUiData!.entries.map((entry) => entry.layerOrDisplayId))).toEqual(
new Set(['1', '3'])
);
}); });
it('filters entries according to "what" search string', () => { it('filters entries according to "what" search string', () => {

View File

@@ -21,7 +21,8 @@ class UiData {
public allPids: string[], public allPids: string[],
public allUids: string[], public allUids: string[],
public allTypes: string[], public allTypes: string[],
public allIds: string[], public allLayerAndDisplayIds: string[],
public allTransactionIds: string[],
public entries: UiDataEntry[], public entries: UiDataEntry[],
public currentEntryIndex: undefined | number, public currentEntryIndex: undefined | number,
public selectedEntryIndex: undefined | number, public selectedEntryIndex: undefined | number,
@@ -29,7 +30,7 @@ class UiData {
public currentPropertiesTree: undefined | PropertiesTreeNode public currentPropertiesTree: undefined | PropertiesTreeNode
) {} ) {}
static EMPTY = new UiData([], [], [], [], [], [], undefined, undefined, undefined, undefined); static EMPTY = new UiData([], [], [], [], [], [], [], undefined, undefined, undefined, undefined);
} }
class UiDataEntry { class UiDataEntry {
@@ -40,7 +41,8 @@ class UiDataEntry {
public pid: string, public pid: string,
public uid: string, public uid: string,
public type: string, public type: string,
public id: string, public layerOrDisplayId: string,
public transactionId: string,
public what: string, public what: string,
public propertiesTree?: PropertiesTreeNode public propertiesTree?: PropertiesTreeNode
) {} ) {}

View File

@@ -46,14 +46,18 @@ class ViewerTransactions implements Viewer {
this.presenter.onTypeFilterChanged((event as CustomEvent).detail); this.presenter.onTypeFilterChanged((event as CustomEvent).detail);
}); });
this.htmlElement.addEventListener(Events.IdFilterChanged, (event) => { this.htmlElement.addEventListener(Events.LayerIdFilterChanged, (event) => {
this.presenter.onIdFilterChanged((event as CustomEvent).detail); this.presenter.onLayerIdFilterChanged((event as CustomEvent).detail);
}); });
this.htmlElement.addEventListener(Events.WhatSearchStringChanged, (event) => { this.htmlElement.addEventListener(Events.WhatSearchStringChanged, (event) => {
this.presenter.onWhatSearchStringChanged((event as CustomEvent).detail); this.presenter.onWhatSearchStringChanged((event as CustomEvent).detail);
}); });
this.htmlElement.addEventListener(Events.IdFilterChanges, (event) => {
this.presenter.onIdFilterChanged((event as CustomEvent).detail);
});
this.htmlElement.addEventListener(Events.EntryClicked, (event) => { this.htmlElement.addEventListener(Events.EntryClicked, (event) => {
this.presenter.onEntryClicked((event as CustomEvent).detail); this.presenter.onEntryClicked((event as CustomEvent).detail);
}); });

View File

@@ -26,6 +26,12 @@ import {UiData} from './ui_data';
<div class="entries"> <div class="entries">
<div class="filters"> <div class="filters">
<div class="time"></div> <div class="time"></div>
<div class="id">
<mat-form-field appearance="fill">
<mat-label>TX ID</mat-label>
<input matInput [(ngModel)]="idString" (input)="onIdSearchStringChanged()" />
</mat-form-field>
</div>
<div class="vsyncid"> <div class="vsyncid">
<mat-form-field appearance="fill"> <mat-form-field appearance="fill">
<mat-label>VSYNC ID</mat-label> <mat-label>VSYNC ID</mat-label>
@@ -69,8 +75,8 @@ import {UiData} from './ui_data';
<div class="id"> <div class="id">
<mat-form-field appearance="fill"> <mat-form-field appearance="fill">
<mat-label>LAYER/DISP ID</mat-label> <mat-label>LAYER/DISP ID</mat-label>
<mat-select (selectionChange)="onIdFilterChanged($event)" multiple> <mat-select (selectionChange)="onLayerIdFilterChanged($event)" multiple>
<mat-option *ngFor="let id of uiData.allIds" [value]="id"> <mat-option *ngFor="let id of uiData.allLayerAndDisplayIds" [value]="id">
{{ id }} {{ id }}
</mat-option> </mat-option>
</mat-select> </mat-select>
@@ -94,6 +100,9 @@ import {UiData} from './ui_data';
<div class="time"> <div class="time">
<span class="mat-body-1">{{ entry.time }}</span> <span class="mat-body-1">{{ entry.time }}</span>
</div> </div>
<div class="id">
<span class="mat-body-1">{{ entry.transactionId }}</span>
</div>
<div class="vsyncid"> <div class="vsyncid">
<span class="mat-body-1">{{ entry.vsyncId }}</span> <span class="mat-body-1">{{ entry.vsyncId }}</span>
</div> </div>
@@ -107,7 +116,7 @@ import {UiData} from './ui_data';
<span class="mat-body-1">{{ entry.type }}</span> <span class="mat-body-1">{{ entry.type }}</span>
</div> </div>
<div class="id"> <div class="id">
<span class="mat-body-1">{{ entry.id }}</span> <span class="mat-body-1">{{ entry.layerOrDisplayId }}</span>
</div> </div>
<div class="what"> <div class="what">
<span class="mat-body-1">{{ entry.what }}</span> <span class="mat-body-1">{{ entry.what }}</span>
@@ -222,6 +231,7 @@ import {UiData} from './ui_data';
}) })
class ViewerTransactionsComponent { class ViewerTransactionsComponent {
uiData: UiData = UiData.EMPTY; uiData: UiData = UiData.EMPTY;
idString = '';
whatSearchString = ''; whatSearchString = '';
@ViewChild(CdkVirtualScrollViewport) private scrollComponent?: CdkVirtualScrollViewport; @ViewChild(CdkVirtualScrollViewport) private scrollComponent?: CdkVirtualScrollViewport;
@@ -255,14 +265,18 @@ class ViewerTransactionsComponent {
this.emitEvent(Events.TypeFilterChanged, event.value); this.emitEvent(Events.TypeFilterChanged, event.value);
} }
onIdFilterChanged(event: MatSelectChange) { onLayerIdFilterChanged(event: MatSelectChange) {
this.emitEvent(Events.IdFilterChanged, event.value); this.emitEvent(Events.LayerIdFilterChanged, event.value);
} }
onWhatSearchStringChange() { onWhatSearchStringChange() {
this.emitEvent(Events.WhatSearchStringChanged, this.whatSearchString); this.emitEvent(Events.WhatSearchStringChanged, this.whatSearchString);
} }
onIdSearchStringChanged() {
this.emitEvent(Events.IdFilterChanges, this.idString);
}
onEntryClicked(index: number) { onEntryClicked(index: number) {
this.emitEvent(Events.EntryClicked, index); this.emitEvent(Events.EntryClicked, index);
} }

View File

@@ -82,10 +82,11 @@ async function makeUiData(): Promise<UiData> {
'PID_VALUE', 'PID_VALUE',
'UID_VALUE', 'UID_VALUE',
'TYPE_VALUE', 'TYPE_VALUE',
'ID_VALUE', 'LAYER_OR_DISPLAY_ID_VALUE',
'TRANSACTION_ID_VALUE',
'flag1 | flag2 | ...', 'flag1 | flag2 | ...',
propertiesTree propertiesTree
); );
return new UiData([], [], [], [], [], [entry], 0, 0, 0, propertiesTree); return new UiData([], [], [], [], [], [], [entry], 0, 0, 0, propertiesTree);
} }