1 <!DOCTYPE html> 2 <!-- 3 Copyright (c) 2015 The Chromium Authors. All rights reserved. 4 Use of this source code is governed by a BSD-style license that can be 5 found in the LICENSE file. 6 --> 7 <link rel="import" href="/experimental/mappers/reduce.html"> 8 <link rel="import" href="/tracing/extras/ads/domain_category.html"> 9 <link rel="import" href="/tracing/extras/chrome/slice_title_fixer.html"> 10 <link rel="import" href="/tracing/model/source_info/js_source_info.html"> 11 12 <script> 13 'use strict'; 14 15 tr.exportTo('pi.m', function() { 16 var JSSourceState = tr.model.source_info.JSSourceState; 17 18 function SliceCostInfo() { 19 this.threadGroup = undefined; 20 this.railTypeName = undefined; 21 this.title = undefined; 22 this.domainCategory = undefined; 23 this.domain = undefined; 24 this.userFriendlyCategory = undefined; 25 26 this.selfTime = 0; 27 this.cpuSelfTime = 0; 28 29 this.jsTime = 0; 30 this.jsTimeByState = {}; 31 for (var state in JSSourceState) { 32 this.jsTimeByState[JSSourceState[state]] = 0; 33 } 34 this.data = {}; 35 } 36 37 SliceCostInfo.asReduceTarget = function(key, firstValue) { 38 var sliceCostInfo = new SliceCostInfo(); 39 sliceCostInfo.threadGroup = firstValue.threadGroup; 40 sliceCostInfo.railTypeName = firstValue.railTypeName; 41 sliceCostInfo.title = firstValue.title; 42 sliceCostInfo.domainCategory = firstValue.domainCategory; 43 sliceCostInfo.domain = firstValue.domain; 44 sliceCostInfo.userFriendlyCategory = firstValue.userFriendlyCategory; 45 sliceCostInfo.data = firstValue.data; 46 return sliceCostInfo; 47 }; 48 49 SliceCostInfo.fromDict = function(d) { 50 var sliceCostInfo = new SliceCostInfo(); 51 sliceCostInfo.threadGroup = d.threadGroup; 52 sliceCostInfo.railTypeName = d.railTypeName; 53 sliceCostInfo.title = d.title; 54 sliceCostInfo.domainCategory = d.domainCategory; 55 sliceCostInfo.domain = d.domain; 56 sliceCostInfo.userFriendlyCategory = d.userFriendlyCategory; 57 sliceCostInfo.selfTime = d.selfTime; 58 sliceCostInfo.cpuSelfTime = d.cpuSelfTime; 59 sliceCostInfo.jsTime = d.jsTime || 0; 60 for (var state in JSSourceState) { 61 if (d.jsTimeByState === undefined) { 62 sliceCostInfo.jsTimeByState[state] = 0; 63 } else { 64 sliceCostInfo.jsTimeByState[JSSourceState[state]] = 65 d.jsTimeByState[JSSourceState[state]] || 0; 66 } 67 } 68 sliceCostInfo.data = d.data; 69 return sliceCostInfo; 70 }; 71 72 SliceCostInfo.prototype = { 73 push: function(sliceCostKey, threadSlice) { 74 if (threadSlice.selfTime !== undefined) 75 this.selfTime += threadSlice.selfTime; 76 if (threadSlice.cpuSelfTime !== undefined) 77 this.cpuSelfTime += threadSlice.cpuSelfTime; 78 if (threadSlice.jsTime !== undefined) 79 this.jsTime += threadSlice.jsTime; 80 if (threadSlice.jsTimeByState !== undefined) { 81 for (var state in JSSourceState) { 82 this.jsTimeByState[JSSourceState[state]] += 83 threadSlice.jsTimeByState[JSSourceState[state]]; 84 } 85 } 86 }, 87 88 finalizeAndGetResult: function() { 89 return this; 90 } 91 }; 92 93 94 function getSliceCostReport(model, threadGrouping, railTypeNameByGUID, 95 filterFunction, dataCB) { 96 var reduce = new pi.m.StreamingReducer(SliceCostInfo.asReduceTarget); 97 98 function generateDomainCosts(slice) { 99 // V8.Execute events may generate several sliceCostInfo, based on the 100 // origin of the JS being executed. 101 var range = new tr.b.Range(); 102 slice.addBoundsToRange(range); 103 var filtered = range.filterArray( 104 slice.parentContainer.samples, 105 function(sample) {return sample.start;}); 106 filtered.forEach(function(sample) { 107 var sliceCostInfo = new SliceCostInfo(); 108 sliceCostInfo.threadGroup = threadGrouping.getGroupNameForEvent(slice); 109 sliceCostInfo.railTypeName = railTypeNameByGUID[slice.guid]; 110 111 var ufc = model.getUserFriendlyCategoryFromEvent(slice); 112 sliceCostInfo.userFriendlyCategory = ufc || 'other'; 113 sliceCostInfo.title = tr.e.chrome.SliceTitleFixer.fromEvent(slice); 114 sliceCostInfo.domain = sample.leafStackFrame.domain; 115 sliceCostInfo.domainCategory = 116 tr.e.ads.DomainCategory.fromDomain(sliceCostInfo.domain); 117 sliceCostInfo.selfTime = sample.weight; 118 sliceCostInfo.cpuSelfTime = sample.weight; 119 if (dataCB !== undefined) 120 sliceCostInfo.data = dataCB(slice); 121 // Let's use the state of the leaf frame. TODO(chiniforooshan): 122 // understand what it means if frames of a sample stack are in different 123 // states (BUG #1542). 124 var sourceInfo = sample.leafStackFrame.sourceInfo; 125 if (sourceInfo === undefined || 126 !(sourceInfo instanceof tr.model.source_info.JSSourceInfo)) { 127 sliceCostInfo.jsTime = sample.weight; 128 sliceCostInfo.jsTimeByState[JSSourceState.UNKNOWN] = sample.weight; 129 } else { 130 sliceCostInfo.jsTimeByState[sourceInfo.state] = sample.weight; 131 } 132 var key = sliceCostInfo.threadGroup + '/' + 133 sliceCostInfo.railTypeName + '/' + 134 sliceCostInfo.title + '/' + 135 sliceCostInfo.domain; 136 reduce.push(key, sliceCostInfo); 137 }); 138 } 139 140 for (var event of model.descendentEvents()) { 141 if (!(event instanceof tr.model.ThreadSlice)) 142 continue; 143 if (filterFunction && !filterFunction(event)) 144 continue; 145 146 var threadSlice = event; 147 if (threadSlice.title === 'V8.Execute') { 148 generateDomainCosts(threadSlice); 149 continue; 150 } 151 152 var sliceCostInfo = new SliceCostInfo(); 153 sliceCostInfo.threadGroup = threadGrouping.getGroupNameForEvent( 154 threadSlice); 155 sliceCostInfo.railTypeName = railTypeNameByGUID[threadSlice.guid]; 156 var ufc = model.getUserFriendlyCategoryFromEvent(threadSlice); 157 sliceCostInfo.userFriendlyCategory = ufc || 'other'; 158 sliceCostInfo.title = tr.e.chrome.SliceTitleFixer.fromEvent(threadSlice); 159 // For all other events, just generate one sliceCostInfo. 160 sliceCostInfo.selfTime = threadSlice.selfTime; 161 sliceCostInfo.cpuSelfTime = threadSlice.cpuSelfTime; 162 if (dataCB !== undefined) 163 sliceCostInfo.data = dataCB(event); 164 165 var key = sliceCostInfo.threadGroup + '/' + 166 sliceCostInfo.railTypeName + '/' + 167 sliceCostInfo.title; 168 reduce.push(key, sliceCostInfo); 169 } 170 171 var sliceCostInfos = []; 172 reduce.finalizeAndIterResults(function(key, sliceCostInfo) { 173 sliceCostInfos.push(sliceCostInfo); 174 }); 175 return sliceCostInfos; 176 } 177 178 tr.mre.FunctionRegistry.register(getSliceCostReport); 179 180 return { 181 SliceCostInfo: SliceCostInfo, 182 183 getSliceCostReport: getSliceCostReport 184 }; 185 }); 186 </script> 187