Add tags/errors to trace views.

At the start or end timestamp of a transition, or at an error timestamp, colour coded tags show up
next to the relevant layer/task in the WM and SF trace hierarchy views.
Tick the transition checkbox to only show entries that have tags/errors.
Compatible with flat checkbox.

Bug: b/196544612

Test: upload the zip onto the x20 (see bug) and test above.
Change-Id: Ied84adbedc38324629c8b50178b44041f8e8b66e
This commit is contained in:
Priyanka
2021-08-19 12:19:36 +00:00
parent 0e80ea1000
commit aadd3418fd
10 changed files with 179 additions and 34 deletions

View File

@@ -52,6 +52,8 @@
:ref="file.type"
:store="store"
:file="file"
:presentTags="Object.freeze(presentTags)"
:presentErrors="Object.freeze(presentErrors)"
@click="onDataViewFocus(file)"
/>
</div>
@@ -102,6 +104,7 @@ export default {
simplifyNames: true,
displayDefaults: true,
navigationStyle: NAVIGATION_STYLE.GLOBAL,
flickerTraceView: false,
}),
overlayRef: 'overlay',
mainContentStyle: {
@@ -110,7 +113,6 @@ export default {
presentTags: [],
presentErrors: [],
searchTypes: [SEARCH_TYPE.TIMESTAMP],
tagAndErrorTraces: false,
};
},
created() {
@@ -124,7 +126,7 @@ export default {
},
methods: {
/** get states from either tag files or error files */
/** Get states from either tag files or error files */
getUpdatedStates(files) {
var states = [];
for (const file of files) {
@@ -132,7 +134,7 @@ export default {
}
return states;
},
/** get tags from all uploaded tag files*/
/** Get tags from all uploaded tag files*/
getUpdatedTags() {
var tagStates = this.getUpdatedStates(this.tagFiles);
var tags = [];
@@ -144,7 +146,7 @@ export default {
});
return tags;
},
/** get tags from all uploaded error files*/
/** Get tags from all uploaded error files*/
getUpdatedErrors() {
var errorStates = this.getUpdatedStates(this.errorFiles);
var errors = [];
@@ -157,11 +159,11 @@ export default {
});
return errors;
},
/** set flicker mode check for if there are tag/error traces uploaded*/
/** Set flicker mode check for if there are tag/error traces uploaded*/
shouldUpdateTagAndErrorTraces() {
return this.tagFiles.length > 0 || this.errorFiles.length > 0;
},
/** activate flicker search tab if tags/errors uploaded*/
/** Activate flicker search tab if tags/errors uploaded*/
updateSearchTypes() {
this.searchTypes = [SEARCH_TYPE.TIMESTAMP];
if (this.tagAndErrorTraces) this.searchTypes.push(SEARCH_TYPE.TAG);

View File

@@ -40,12 +40,16 @@
v-if="showInWindowManagerTraceView(file)"
:store="store"
:file="file"
:presentTags="presentTags"
:presentErrors="presentErrors"
ref="view"
/>
<SurfaceFlingerTraceView
v-else-if="showInSurfaceFlingerTraceView(file)"
:store="store"
:file="file"
:presentTags="presentTags"
:presentErrors="presentErrors"
ref="view"
/>
<transactionsview
@@ -151,7 +155,7 @@ export default {
this.$emit('click', e);
},
},
props: ['store', 'file'],
props: ['store', 'file', 'presentTags', 'presentErrors'],
mixins: [FileType],
components: {
'traceview': TraceView,

View File

@@ -43,13 +43,28 @@
{{c.long}}
</md-tooltip>
</div>
<div class="flicker-tags" v-for="transition in transitions" :key="transition">
<Arrow
class="transition-arrow"
:style="{color: transitionArrowColor(transition)}"
/>
<md-tooltip md-direction="right"> {{transitionTooltip(transition)}} </md-tooltip>
</div>
<div class="flicker-tags" v-for="error in errors" :key="error.message">
<Arrow class="error-arrow"/>
<md-tooltip md-direction="right"> Error: {{error.message}} </md-tooltip>
</div>
</span>
</template>
<script>
import Arrow from './components/TagDisplay/Arrow.vue';
import {transitionMap} from './utils/consts.js';
export default {
name: 'DefaultTreeElement',
props: ['item', 'simplify-names'],
props: ['item', 'simplify-names', 'errors', 'transitions'],
methods: {
chipClassForChip(c) {
return [
@@ -59,6 +74,15 @@ export default {
(c.type?.toString() || c.class?.toString() || 'default'),
];
},
transitionArrowColor(transition) {
return transitionMap.get(transition).color;
},
transitionTooltip(transition) {
return transitionMap.get(transition).desc;
},
},
components: {
Arrow,
},
};
</script>
@@ -100,4 +124,12 @@ span {
flex: 1 1 auto;
width: 0;
}
.flicker-tags {
display: inline-block;
}
.error-arrow {
color: red;
}
</style>

View File

@@ -76,7 +76,7 @@
class="inline-error"
@click="setCurrentTimestamp(item.timestamp)"
>
Error
Error: {{item.message}}
</td>
</tr>
</table>
@@ -117,17 +117,17 @@ export default {
};
},
methods: {
/** set search type depending on tab selected */
/** Set search type depending on tab selected */
setSearchType(searchType) {
this.searchType = searchType;
},
/** set tab class to determine color highlight for active tab */
/** Set tab class to determine color highlight for active tab */
tabClass(searchType) {
var isActive = (this.searchType === searchType) ? 'active' : 'inactive';
return ['tab', isActive];
},
/** filter all the tags present in the trace by the searchbar input */
/** Filter all the tags present in the trace by the searchbar input */
filteredTags() {
var tags = [];
var filter = this.searchInput.toUpperCase();
@@ -136,7 +136,7 @@ export default {
});
return tags;
},
/** add filtered errors to filtered tags to integrate both into table*/
/** Add filtered errors to filtered tags to integrate both into table*/
filteredTagsAndErrors() {
var tagsAndErrors = [...this.filteredTags()];
var filter = this.searchInput.toUpperCase();
@@ -148,9 +148,9 @@ export default {
return tagsAndErrors;
},
/** each transition has two tags present
* isolate the tags for the desire transition
* add a desc to display the timestamps as strings
/** Each transition has two tags present
* Isolate the tags for the desire transition
* Add a desc to display the timestamps as strings
*/
transitionTags(id) {
var tags = this.filteredTags().filter((tag) => tag.id === id);
@@ -160,36 +160,36 @@ export default {
return tags;
},
/** find the start as minimum timestamp in transition tags */
/** Find the start as minimum timestamp in transition tags */
transitionStart(tags) {
var times = tags.map((tag) => tag.timestamp);
return times[0];
},
/** find the end as maximum timestamp in transition tags */
/** Find the end as maximum timestamp in transition tags */
transitionEnd(tags) {
var times = tags.map((tag) => tag.timestamp);
return times[times.length - 1];
},
/** upon selecting a start/end tag in the dropdown;
/** Upon selecting a start/end tag in the dropdown;
* navigates to that timestamp in the timeline */
setCurrentTimestamp(timestamp) {
this.$store.dispatch("updateTimelineTime", timestamp);
},
/** colour codes text of transition in dropdown */
/** Colour codes text of transition in dropdown */
transitionTextColor(transition) {
return transitionMap.get(transition).color;
},
/** displays transition description rather than variable name */
/** Displays transition description rather than variable name */
transitionDesc(transition) {
return transitionMap.get(transition).desc;
},
/** add a desc to display the error timestamps as strings */
/** Add a desc to display the error timestamps as strings */
errorDesc(timestamp) {
return nanos_to_string(timestamp);
},
/** navigates to closest timestamp in timeline to search input*/
/** Navigates to closest timestamp in timeline to search input*/
updateSearchForTimestamp() {
if (regExpTimestampSearch.test(this.searchInput)) {
var roundedTimestamp = parseInt(this.searchInput);

View File

@@ -14,7 +14,13 @@
-->
<template>
<TraceView :store="store" :file="file" :summarizer="summarizer" />
<TraceView
:store="store"
:file="file"
:summarizer="summarizer"
:presentTags="presentTags"
:presentErrors="presentErrors"
/>
</template>
<script>
@@ -22,7 +28,7 @@ import TraceView from '@/TraceView.vue';
export default {
name: 'SurfaceFlingerTraceView',
props: ['store', 'file'],
props: ['store', 'file', 'presentTags', 'presentErrors'],
components: {
TraceView,
},

View File

@@ -42,6 +42,7 @@
</md-checkbox>
<md-checkbox v-model="store.onlyVisible">Only visible</md-checkbox>
<md-checkbox v-model="store.flattened">Flat</md-checkbox>
<md-checkbox v-if="hasTagsOrErrors" v-model="store.flickerTraceView">Flicker</md-checkbox>
<md-field md-inline class="filter">
<label>Filter...</label>
<md-input v-model="hierarchyPropertyFilterString"></md-input>
@@ -56,6 +57,9 @@
:filter="hierarchyFilter"
:flattened="store.flattened"
:onlyVisible="store.onlyVisible"
:flickerTraceView="store.flickerTraceView"
:presentTags="presentTags"
:presentErrors="presentErrors"
:items-clickable="true"
:useGlobalCollapsedState="true"
:simplify-names="store.simplifyNames"
@@ -166,7 +170,7 @@ function findEntryInTree(tree, id) {
export default {
name: 'traceview',
props: ['store', 'file', 'summarizer'],
props: ['store', 'file', 'summarizer', 'presentTags', 'presentErrors'],
data() {
return {
propertyFilterString: '',
@@ -307,10 +311,30 @@ export default {
return prevEntry;
},
/** Performs check for id match between entry and present tags/errors
* must be carried out for every present tag/error
*/
matchItems(flickerItems, entryItem) {
var match = false;
flickerItems.forEach(flickerItem => {
if (flickerItem.taskId===entryItem.taskId || flickerItem.layerId===entryItem.id) {
match = true;
}
});
return match;
},
/** Returns check for id match between entry and present tags/errors */
isEntryTagMatch(entryItem) {
return this.matchItems(this.presentTags, entryItem) || this.matchItems(this.presentErrors, entryItem);
},
},
created() {
this.setData(this.file.data[this.file.selectedIndex ?? 0]);
},
destroyed() {
this.store.flickerTraceView = false;
},
watch: {
selectedIndex() {
this.setData(this.file.data[this.file.selectedIndex ?? 0]);
@@ -338,9 +362,12 @@ export default {
hierarchyFilter() {
const hierarchyPropertyFilter =
getFilter(this.hierarchyPropertyFilterString);
return this.store.onlyVisible ? (c) => {
var fil = this.store.onlyVisible ? (c) => {
return c.isVisible && hierarchyPropertyFilter(c);
} : hierarchyPropertyFilter;
return this.store.flickerTraceView ? (c) => {
return this.isEntryTagMatch(c);
} : fil;
},
propertyFilter() {
return getFilter(this.propertyFilterString);
@@ -364,6 +391,9 @@ export default {
return summary;
},
hasTagsOrErrors() {
return this.presentTags.length > 0 || this.presentErrors.length > 0;
},
},
components: {
'tree-view': TreeView,

View File

@@ -50,7 +50,12 @@
/>
</div>
<div v-else>
<DefaultTreeElement :item="item" :simplify-names="simplifyNames"/>
<DefaultTreeElement
:item="item"
:simplify-names="simplifyNames"
:errors="errors"
:transitions="transitions"
/>
</div>
</div>
<div v-show="isCollapsed">
@@ -89,6 +94,9 @@
:flattened="flattened"
:onlyVisible="onlyVisible"
:simplify-names="simplifyNames"
:flickerTraceView="flickerTraceView"
:presentTags="currentTags"
:presentErrors="currentErrors"
:force-flattened="applyingFlattened"
v-show="filterMatches(c)"
:items-clickable="itemsClickable"
@@ -113,7 +121,6 @@
<script>
import DefaultTreeElement from './DefaultTreeElement.vue';
import NodeContextMenu from './NodeContextMenu.vue';
import {DiffType} from './utils/diff.js';
/* in px, must be kept in sync with css, maybe find a better solution... */
@@ -143,6 +150,9 @@ export default {
// Custom view to use to render the elements in the tree view
'elementView',
'onlyVisible',
'flickerTraceView',
'presentTags',
'presentErrors',
],
data() {
const isCollapsedByDefault = this.collapse ?? false;
@@ -163,6 +173,10 @@ export default {
[DiffType.MODIFIED]: '.',
[DiffType.MOVED]: '.',
},
currentTags: [],
currentErrors: [],
transitions: [],
errors: [],
};
},
watch: {
@@ -179,6 +193,10 @@ export default {
},
currentTimestamp() {
// Update anything that is required to change when time changes.
this.currentTags = this.getCurrentItems(this.presentTags);
this.currentErrors = this.getCurrentItems(this.presentErrors);
this.transitions = this.getCurrentTransitions();
this.errors = this.getCurrentErrorTags();
this.updateCollapsedDiffClass();
},
isSelected(isSelected) {
@@ -426,7 +444,48 @@ export default {
marginTop: '0px',
}
}
}
},
/** Check if tag/error id matches entry id */
isIdMatch(a, b) {
return a.taskId===b.taskId || a.layerId===b.id;
},
/** Performs check for id match between entry and present tags/errors
* exits once match has been found
*/
matchItems(flickerItems) {
var match = false;
flickerItems.every(flickerItem => {
if (this.isIdMatch(flickerItem, this.item)) {
match = true;
return false;
}
});
return match;
},
/** Returns check for id match between entry and present tags/errors */
isEntryTagMatch() {
return this.matchItems(this.currentTags) || this.matchItems(this.currentErrors);
},
getCurrentItems(items) {
if (!items) return [];
else return items.filter(item => item.timestamp===this.currentTimestamp);
},
getCurrentTransitions() {
var transitions = [];
var ids = [];
this.currentTags.forEach(tag => {
if (!ids.includes(tag.id) && this.isIdMatch(tag, this.item)) {
transitions.push(tag.transition);
ids.push(tag.id);
}
});
return transitions;
},
getCurrentErrorTags() {
return this.currentErrors.filter(error => this.isIdMatch(error, this.item));
},
},
computed: {
hasDiff() {
@@ -486,7 +545,12 @@ export default {
const offset = levelOffset * (this.depth + this.isLeaf) + 'px';
var display = "";
if (this.onlyVisible && !this.item.isVisible) display = 'none';
if (!this.item.timestamp
&& this.flattened
&& (this.onlyVisible && !this.item.isVisible ||
this.flickerTraceView && !this.isEntryTagMatch())) {
display = 'none';
}
return {
marginLeft: '-' + offset,

View File

@@ -14,7 +14,13 @@
-->
<template>
<TraceView :store="store" :file="file" :summarizer="summarizer" />
<TraceView
:store="store"
:file="file"
:summarizer="summarizer"
:presentTags="presentTags"
:presentErrors="presentErrors"
/>
</template>
<script>
@@ -22,7 +28,7 @@ import TraceView from "@/TraceView.vue"
export default {
name: "WindowManagerTraceView",
props: ["store", "file"],
props: ["store", "file", "presentTags", "presentErrors"],
components: {
TraceView
},

View File

@@ -24,7 +24,6 @@ export default {
<style scoped>
.arrow {
display: inline-block;
position: absolute;
width: 0;
height: 0;
border-left: 6px solid transparent;

View File

@@ -92,10 +92,12 @@ export default {
}
.arrow-start {
position: absolute;
left: 0%;
}
.arrow-end {
position: absolute;
right: 0%;
}