ui: Highlight flamegraph issue on heap_graph_non_finalized_graph, take 2
The initial change was aosp/2019015. The feedback on that was to
show a modal indicating that the flamegraph is not finalised.
The end result looks like this:
https://screenshot.googleplex.com/ZNqu6LYsvTYaLMi
Bug: 222270825
Change-Id: Ic684be1a86637101984a557e07a3922507d401f0
diff --git a/ui/src/assets/modal.scss b/ui/src/assets/modal.scss
index f65961e..20a80a8 100644
--- a/ui/src/assets/modal.scss
+++ b/ui/src/assets/modal.scss
@@ -147,7 +147,8 @@
animation: mmfadeIn .3s cubic-bezier(0.0, 0.0, 0.2, 1);
}
-.micromodal-slide[aria-hidden="false"] .modal-container {
+.micromodal-slide[aria-hidden="false"] .modal-container,
+.micromodal-slide[aria-hidden="false"] .partial-modal-container {
animation: mmslideIn .3s cubic-bezier(0, 0, .2, 1);
}
@@ -155,11 +156,13 @@
animation: mmfadeOut .3s cubic-bezier(0.0, 0.0, 0.2, 1);
}
-.micromodal-slide[aria-hidden="true"] .modal-container {
+.micromodal-slide[aria-hidden="true"] .modal-container,
+.micromodal-slide[aria-hidden="true"] .partial-modal-container {
animation: mmslideOut .3s cubic-bezier(0, 0, .2, 1);
}
.micromodal-slide .modal-container,
+.micromodal-slide .partial-modal-container,
.micromodal-slide .modal-overlay {
will-change: transform;
}
@@ -215,3 +218,32 @@
.modal-small {
font-size: 11px;
}
+
+.partial-modal-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0,0,0,0.6);
+ display: flex;
+ justify-content: center;
+ z-index: 999;
+}
+
+.partial-modal-container {
+ background-color: #fff;
+ margin-top: 1vh;
+ padding: 30px 30px 20px 30px;
+ max-width: 90vw;
+ height: fit-content;
+ border-radius: 4px;
+ overflow-y: auto;
+ box-sizing: border-box;
+}
+
+.partial-modal-header {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
diff --git a/ui/src/common/actions.ts b/ui/src/common/actions.ts
index bd914e0..8366f65 100644
--- a/ui/src/common/actions.ts
+++ b/ui/src/common/actions.ts
@@ -1006,6 +1006,10 @@
setPivotStateReduxState(
state: StateDraft, args: {pivotTableState: PivotTableReduxState}) {
state.pivotTableRedux = args.pivotTableState;
+ },
+
+ dismissFlamegraphModal(state: StateDraft, _: {}) {
+ state.flamegraphModalDismissed = true;
}
};
diff --git a/ui/src/common/empty_state.ts b/ui/src/common/empty_state.ts
index cc57df5..ac287d2 100644
--- a/ui/src/common/empty_state.ts
+++ b/ui/src/common/empty_state.ts
@@ -97,6 +97,7 @@
recordingInProgress: false,
recordingCancelled: false,
extensionInstalled: false,
+ flamegraphModalDismissed: false,
recordingTarget: recordTargetStore.getValidTarget(),
availableAdbDevices: [],
diff --git a/ui/src/common/state.ts b/ui/src/common/state.ts
index 18df6ce..3bc8359 100644
--- a/ui/src/common/state.ts
+++ b/ui/src/common/state.ts
@@ -79,7 +79,8 @@
// typed key/value because a `Map` does not preserve type during
// serialisation+deserialisation.
// 15: Added state for Pivot Table V2
-export const STATE_VERSION = 15;
+// 16: Added boolean tracking if the flamegraph modal was dismissed
+export const STATE_VERSION = 16;
export const SCROLLING_TRACK_GROUP = 'ScrollingTracks';
@@ -463,6 +464,7 @@
recordingInProgress: boolean;
recordingCancelled: boolean;
extensionInstalled: boolean;
+ flamegraphModalDismissed: boolean;
recordingTarget: RecordingTarget;
availableAdbDevices: AdbRecordingTarget[];
lastRecordingError?: string;
diff --git a/ui/src/controller/flamegraph_controller.ts b/ui/src/controller/flamegraph_controller.ts
index cb7ea7e..cb74e41 100644
--- a/ui/src/controller/flamegraph_controller.ts
+++ b/ui/src/controller/flamegraph_controller.ts
@@ -101,7 +101,7 @@
if (hasAreaChanged) {
const upids = [];
if (!area) {
- publishFlamegraphDetails(
+ this.checkCompletionAndPublishFlamegraph(
{...frontendGlobals.flamegraphDetails, isInAreaSelection: false});
return;
}
@@ -114,7 +114,7 @@
upids.push((trackState.config as PerfSampleConfig).upid);
}
if (upids.length === 0) {
- publishFlamegraphDetails(
+ this.checkCompletionAndPublishFlamegraph(
{...frontendGlobals.flamegraphDetails, isInAreaSelection: false});
return;
}
@@ -228,7 +228,17 @@
this.flamegraphDetails.expandedCallsite = expandedCallsite;
this.flamegraphDetails.viewingOption = viewingOption;
this.flamegraphDetails.isInAreaSelection = hasAreaChanged;
- publishFlamegraphDetails(this.flamegraphDetails);
+ this.checkCompletionAndPublishFlamegraph(this.flamegraphDetails);
+ }
+
+ private async checkCompletionAndPublishFlamegraph(flamegraphDetails:
+ FlamegraphDetails) {
+ flamegraphDetails.graphIncomplete =
+ (await this.args.engine.query(`select value from stats
+ where severity = 'error' and name = 'heap_graph_non_finalized_graph'`))
+ .firstRow({value: NUM})
+ .value > 0;
+ publishFlamegraphDetails(flamegraphDetails);
}
async getFlamegraphData(
diff --git a/ui/src/frontend/flamegraph_panel.ts b/ui/src/frontend/flamegraph_panel.ts
index 35a4d9f..368ab32 100644
--- a/ui/src/frontend/flamegraph_panel.ts
+++ b/ui/src/frontend/flamegraph_panel.ts
@@ -29,8 +29,10 @@
import {PerfettoMouseEvent} from './events';
import {Flamegraph, NodeRendering} from './flamegraph';
import {globals} from './globals';
+import {showPartialModal} from './modal';
import {Panel, PanelSize} from './panel';
import {debounce} from './rate_limiters';
+import {Router} from './router';
import {getCurrentTrace} from './sidebar';
import {convertTraceToPprofAndDownload} from './trace_converter';
@@ -119,6 +121,7 @@
}
}
},
+ this.maybeShowModal(flamegraphDetails.graphIncomplete),
m('.details-panel-heading.flamegraph-profile',
{onclick: (e: MouseEvent) => e.stopPropagation()},
[
@@ -165,6 +168,39 @@
}
}
+
+ private maybeShowModal(graphIncomplete?: boolean): m.Vnode|undefined {
+ if (!graphIncomplete || globals.state.flamegraphModalDismissed) {
+ return undefined;
+ }
+ return showPartialModal({
+ title: 'The flamegraph is incomplete',
+ content:
+ m('div',
+ m('div',
+ 'The current trace does not have a fully formed flamegraph.')),
+ buttons: [
+ {
+ text: 'Show the errors',
+ primary: true,
+ id: 'incomplete_graph_show',
+ action: () => {
+ Router.navigate('#!/info');
+ }
+ },
+ {
+ text: 'Skip',
+ primary: false,
+ id: 'incomplete_graph_skip',
+ action: () => {
+ globals.dispatch(Actions.dismissFlamegraphModal({}));
+ globals.rafScheduler.scheduleFullRedraw();
+ }
+ }
+ ],
+ });
+ }
+
private getTitle(): string {
switch (this.profileType!) {
case ProfileType.NATIVE_HEAP_PROFILE:
diff --git a/ui/src/frontend/globals.ts b/ui/src/frontend/globals.ts
index dd5b51b..aa48edf 100644
--- a/ui/src/frontend/globals.ts
+++ b/ui/src/frontend/globals.ts
@@ -124,6 +124,9 @@
// isInAreaSelection is true if a flamegraph is part of the current area
// selection.
isInAreaSelection?: boolean;
+ // When heap_graph_non_finalized_graph has a count >0, we mark the graph
+ // as incomplete.
+ graphIncomplete?: boolean;
}
export interface CpuProfileDetails {
diff --git a/ui/src/frontend/modal.ts b/ui/src/frontend/modal.ts
index 69482e3..40badd9 100644
--- a/ui/src/frontend/modal.ts
+++ b/ui/src/frontend/modal.ts
@@ -84,3 +84,13 @@
});
return buttons;
}
+
+export function showPartialModal(attrs: ModalDefinition): m.Vnode {
+ return m(
+ '.partial-modal-overlay',
+ {tabindex: -1},
+ m('.partial-modal-container',
+ m('header.partial-modal-header', m('h2.modal-title', attrs.title)),
+ m('main.modal-content', attrs.content),
+ m('footer.modal-footer', ...makeButtons(attrs.buttons))));
+}