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:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
},
|
||||
|
||||
@@ -24,7 +24,6 @@ export default {
|
||||
<style scoped>
|
||||
.arrow {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 6px solid transparent;
|
||||
|
||||
@@ -92,10 +92,12 @@ export default {
|
||||
}
|
||||
|
||||
.arrow-start {
|
||||
position: absolute;
|
||||
left: 0%;
|
||||
}
|
||||
|
||||
.arrow-end {
|
||||
position: absolute;
|
||||
right: 0%;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user