OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 "use strict" |
| 6 |
| 7 let codeKinds = [ |
| 8 "UNKNOWN", |
| 9 "CPPCOMP", |
| 10 "CPPGC", |
| 11 "CPPEXT", |
| 12 "CPP", |
| 13 "LIB", |
| 14 "IC", |
| 15 "BC", |
| 16 "STUB", |
| 17 "BUILTIN", |
| 18 "REGEXP", |
| 19 "JSOPT", |
| 20 "JSUNOPT" |
| 21 ]; |
| 22 |
| 23 function resolveCodeKind(code) { |
| 24 if (!code || !code.type) { |
| 25 return "UNKNOWN"; |
| 26 } else if (code.type === "CPP") { |
| 27 return "CPP"; |
| 28 } else if (code.type === "SHARED_LIB") { |
| 29 return "LIB"; |
| 30 } else if (code.type === "CODE") { |
| 31 if (code.kind === "LoadIC" || |
| 32 code.kind === "StoreIC" || |
| 33 code.kind === "KeyedStoreIC" || |
| 34 code.kind === "KeyedLoadIC" || |
| 35 code.kind === "LoadGlobalIC" || |
| 36 code.kind === "Handler") { |
| 37 return "IC"; |
| 38 } else if (code.kind === "BytecodeHandler") { |
| 39 return "BC"; |
| 40 } else if (code.kind === "Stub") { |
| 41 return "STUB"; |
| 42 } else if (code.kind === "Builtin") { |
| 43 return "BUILTIN"; |
| 44 } else if (code.kind === "RegExp") { |
| 45 return "REGEXP"; |
| 46 } |
| 47 console.log("Unknown CODE: '" + code.kind + "'."); |
| 48 return "CODE"; |
| 49 } else if (code.type === "JS") { |
| 50 if (code.kind === "Builtin") { |
| 51 return "JSUNOPT"; |
| 52 } else if (code.kind === "Opt") { |
| 53 return "JSOPT"; |
| 54 } else if (code.kind === "Unopt") { |
| 55 return "JSUNOPT"; |
| 56 } |
| 57 } |
| 58 console.log("Unknown code type '" + type + "'."); |
| 59 } |
| 60 |
| 61 function resolveCodeKindAndVmState(code, vmState) { |
| 62 let kind = resolveCodeKind(code); |
| 63 if (kind === "CPP") { |
| 64 if (vmState === 1) { |
| 65 kind = "CPPGC"; |
| 66 } else if (vmState === 2) { |
| 67 kind = "CPPCOMP"; |
| 68 } else if (vmState === 4) { |
| 69 kind = "CPPEXT"; |
| 70 } |
| 71 } |
| 72 return kind; |
| 73 } |
| 74 |
| 75 function createNodeFromStackEntry(code) { |
| 76 let name = code ? code.name : "UNKNOWN"; |
| 77 |
| 78 return { name, type : resolveCodeKind(code), |
| 79 children : [], ownTicks : 0, ticks : 0 }; |
| 80 } |
| 81 |
| 82 function addStackToTree(file, stack, tree, filter, ascending, start) { |
| 83 if (start === undefined) { |
| 84 start = ascending ? 0 : stack.length - 2; |
| 85 } |
| 86 tree.ticks++; |
| 87 for (let i = start; |
| 88 ascending ? (i < stack.length) : (i >= 0); |
| 89 i += ascending ? 2 : -2) { |
| 90 let codeId = stack[i]; |
| 91 let code = codeId >= 0 ? file.code[codeId] : undefined; |
| 92 if (filter) { |
| 93 let type = code ? code.type : undefined; |
| 94 let kind = code ? code.kind : undefined; |
| 95 if (!filter(type, kind)) continue; |
| 96 } |
| 97 |
| 98 // For JavaScript function, pretend there is one instance of optimized |
| 99 // function and one instance of unoptimized function per SFI. |
| 100 let type = resolveCodeKind(code); |
| 101 let childId; |
| 102 if (type === "JSOPT") { |
| 103 childId = code.func * 4 + 1; |
| 104 } else if (type === "JSUNOPT") { |
| 105 childId = code.func * 4 + 2; |
| 106 } else { |
| 107 childId = codeId * 4; |
| 108 } |
| 109 let child = tree.children[childId]; |
| 110 if (!child) { |
| 111 child = createNodeFromStackEntry(code); |
| 112 tree.children[childId] = child; |
| 113 } |
| 114 child.ticks++; |
| 115 tree = child; |
| 116 } |
| 117 tree.ownTicks++; |
| 118 } |
| 119 |
| 120 function createEmptyNode(name) { |
| 121 return { |
| 122 name : name, |
| 123 type : "CAT", |
| 124 children : [], |
| 125 ownTicks : 0, |
| 126 ticks : 0 |
| 127 }; |
| 128 } |
| 129 |
| 130 class PlainCallTreeProcessor { |
| 131 constructor(filter, isBottomUp) { |
| 132 this.filter = filter; |
| 133 this.tree = createEmptyNode("root"); |
| 134 this.isBottomUp = isBottomUp; |
| 135 } |
| 136 |
| 137 addStack(file, timestamp, vmState, stack) { |
| 138 addStackToTree(file, stack, this.tree, this.filter, this.isBottomUp); |
| 139 } |
| 140 } |
| 141 |
| 142 class CategorizedCallTreeProcessor { |
| 143 constructor(filter, isBottomUp) { |
| 144 this.filter = filter; |
| 145 let root = createEmptyNode("root"); |
| 146 let categories = {}; |
| 147 function addCategory(name, types) { |
| 148 let n = createEmptyNode(name); |
| 149 for (let i = 0; i < types.length; i++) { |
| 150 categories[types[i]] = n; |
| 151 } |
| 152 root.children.push(n); |
| 153 } |
| 154 addCategory("JS Optimized", [ "JSOPT" ]); |
| 155 addCategory("JS Unoptimized", [ "JSUNOPT", "BC" ]); |
| 156 addCategory("IC", [ "IC" ]); |
| 157 addCategory("RegExp", [ "REGEXP" ]); |
| 158 addCategory("Other generated", [ "STUB", "BUILTIN" ]); |
| 159 addCategory("C++", [ "CPP", "LIB" ]); |
| 160 addCategory("C++/GC", [ "CPPGC" ]); |
| 161 addCategory("C++/Compiler", [ "CPPCOMP" ]); |
| 162 addCategory("C++/External", [ "CPPEXT" ]); |
| 163 addCategory("Unknown", [ "UNKNOWN" ]); |
| 164 |
| 165 this.tree = root; |
| 166 this.categories = categories; |
| 167 this.isBottomUp = isBottomUp; |
| 168 } |
| 169 |
| 170 addStack(file, timestamp, vmState, stack) { |
| 171 if (stack.length === 0) return; |
| 172 let codeId = stack[0]; |
| 173 let code = codeId >= 0 ? file.code[codeId] : undefined; |
| 174 let kind = resolveCodeKindAndVmState(code, vmState); |
| 175 let node = this.categories[kind]; |
| 176 |
| 177 this.tree.ticks++; |
| 178 |
| 179 console.assert(node); |
| 180 |
| 181 addStackToTree(file, stack, node, this.filter, this.isBottomUp); |
| 182 } |
| 183 } |
| 184 |
| 185 class FunctionListTree { |
| 186 constructor(filter) { |
| 187 this.tree = { name : "root", children : [], ownTicks : 0, ticks : 0 }; |
| 188 this.codeVisited = []; |
| 189 this.filter = filter; |
| 190 } |
| 191 |
| 192 addStack(file, timestamp, vmState, stack) { |
| 193 this.tree.ticks++; |
| 194 let child = null; |
| 195 for (let i = stack.length - 2; i >= 0; i -= 2) { |
| 196 let codeId = stack[i]; |
| 197 if (codeId < 0 || this.codeVisited[codeId]) continue; |
| 198 |
| 199 let code = codeId >= 0 ? file.code[codeId] : undefined; |
| 200 if (this.filter) { |
| 201 let type = code ? code.type : undefined; |
| 202 let kind = code ? code.kind : undefined; |
| 203 if (!this.filter(type, kind)) continue; |
| 204 } |
| 205 child = this.tree.children[codeId]; |
| 206 if (!child) { |
| 207 child = createNodeFromStackEntry(code); |
| 208 this.tree.children[codeId] = child; |
| 209 } |
| 210 child.ticks++; |
| 211 this.codeVisited[codeId] = true; |
| 212 } |
| 213 if (child) { |
| 214 child.ownTicks++; |
| 215 } |
| 216 |
| 217 for (let i = 0; i < stack.length; i += 2) { |
| 218 let codeId = stack[i]; |
| 219 if (codeId >= 0) this.codeVisited[codeId] = false; |
| 220 } |
| 221 } |
| 222 } |
| 223 |
| 224 |
| 225 class CategorySampler { |
| 226 constructor(file, bucketCount) { |
| 227 this.bucketCount = bucketCount; |
| 228 |
| 229 this.firstTime = file.ticks[0].tm; |
| 230 let lastTime = file.ticks[file.ticks.length - 1].tm; |
| 231 this.step = (lastTime - this.firstTime) / bucketCount; |
| 232 |
| 233 this.buckets = []; |
| 234 let bucket = {}; |
| 235 for (let i = 0; i < codeKinds.length; i++) { |
| 236 bucket[codeKinds[i]] = 0; |
| 237 } |
| 238 for (let i = 0; i < bucketCount; i++) { |
| 239 this.buckets.push(Object.assign({ total : 0 }, bucket)); |
| 240 } |
| 241 } |
| 242 |
| 243 addStack(file, timestamp, vmState, stack) { |
| 244 let i = Math.floor((timestamp - this.firstTime) / this.step); |
| 245 if (i == this.buckets.length) i--; |
| 246 console.assert(i >= 0 && i < this.buckets.length); |
| 247 |
| 248 let bucket = this.buckets[i]; |
| 249 bucket.total++; |
| 250 |
| 251 let codeId = (stack.length > 0) ? stack[0] : -1; |
| 252 let code = codeId >= 0 ? file.code[codeId] : undefined; |
| 253 let kind = resolveCodeKindAndVmState(code, vmState); |
| 254 bucket[kind]++; |
| 255 } |
| 256 } |
| 257 |
| 258 // Generates a tree out of a ticks sequence. |
| 259 // {file} is the JSON files with the ticks and code objects. |
| 260 // {startTime}, {endTime} is the interval. |
| 261 // {tree} is the processor of stacks. |
| 262 function generateTree( |
| 263 file, startTime, endTime, tree) { |
| 264 let ticks = file.ticks; |
| 265 let i = 0; |
| 266 while (i < ticks.length && ticks[i].tm < startTime) { |
| 267 i++; |
| 268 } |
| 269 |
| 270 let tickCount = 0; |
| 271 while (i < ticks.length && ticks[i].tm < endTime) { |
| 272 tree.addStack(file, ticks[i].tm, ticks[i].vm, ticks[i].s); |
| 273 i++; |
| 274 tickCount++; |
| 275 } |
| 276 |
| 277 return tickCount; |
| 278 } |
OLD | NEW |