Changeset 136756 in webkit
- Timestamp:
- Dec 5, 2012, 1:40:32 PM (12 years ago)
- Location:
- trunk/Tools
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Tools/ChangeLog
r136746 r136756 1 2012-12-05 Filip Pizlo <fpizlo@apple.com> 2 3 DFG profiler should display more information 4 https://bugs.webkit.org/show_bug.cgi?id=104163 5 6 Reviewed by Gavin Barraclough. 7 8 Added the following: 9 10 - Distinguish between source counts and bytecode counts. 11 12 - Add a "full" summary view that shows both kinds of counts, plus inline counts. 13 14 - Add a "source" command to see the source. 15 16 - Add a "bytecode" command to see the bytecode and counts. 17 18 * Scripts/display-profiler-output: 19 1 20 2012-12-05 Yong Li <yoli@rim.com> 2 21 -
trunk/Tools/Scripts/display-profiler-output
r136720 r136756 28 28 require 'json' 29 29 require 'readline' 30 require 'highline' 30 31 31 32 class Bytecode 32 attr_accessor :bytecodeIndex, :opcode, :description, :topCounts 33 34 def initialize(bytecodeIndex, opcode, description) 33 attr_accessor :bytecodes, :bytecodeIndex, :opcode, :description, :topCounts, :bottomCounts, :machineInlinees 34 35 def initialize(bytecodes, bytecodeIndex, opcode, description) 36 @bytecodes = bytecodes 35 37 @bytecodeIndex = bytecodeIndex 36 38 @opcode = opcode 37 39 @description = description 38 @topCounts = [] 40 @topCounts = [] # "source" counts 41 @bottomCounts = {} # "machine" counts, maps compilations to counts 42 @machineInlinees = {} # maps my compilation to a set of inlinees 39 43 end 40 44 … … 47 51 end 48 52 49 def totalExecutionCount 53 def addBottomCountForCompilation(count, compilation) 54 @bottomCounts[compilation] = [] unless @bottomCounts[compilation] 55 @bottomCounts[compilation] << count 56 end 57 58 def addMachineInlinee(compilation, inlinee) 59 @machineInlinees[compilation] = {} unless @machineInlinees[compilation] 60 @machineInlinees[compilation][inlinee] = true 61 end 62 63 def totalTopExecutionCount 50 64 sum = 0 51 65 @topCounts.each { … … 56 70 end 57 71 58 def executionCount(engine)72 def topExecutionCount(engine) 59 73 sum = 0 60 74 @topCounts.each { … … 66 80 sum 67 81 end 82 83 def totalBottomExecutionCount 84 sum = 0 85 @bottomCounts.each_value { 86 | counts | 87 max = 0 88 counts.each { 89 | value | 90 max = [max, value.count].max 91 } 92 sum += max 93 } 94 sum 95 end 96 97 def bottomExecutionCount(engine) 98 sum = 0 99 @bottomCounts.each_pair { 100 | compilation, counts | 101 if compilation.engine == engine 102 max = 0 103 counts.each { 104 | value | 105 max = [max, value.count].max 106 } 107 sum += max 108 end 109 } 110 sum 111 end 68 112 end 69 113 70 114 class Bytecodes 71 attr_accessor :hash, :source 72 include Enumerable 115 attr_accessor :codeHash, :source, :machineInlineSites 73 116 74 117 def initialize(json) 75 @ hash = json["hash"].to_s118 @codeHash = json["hash"].to_s 76 119 @source = json["sourceCode"].to_s 77 120 @bytecode = {} … … 79 122 | subJson | 80 123 index = subJson["bytecodeIndex"].to_i 81 @bytecode[index] = Bytecode.new(index, subJson["opcode"].to_s, subJson["description"].to_s) 82 } 124 @bytecode[index] = Bytecode.new(self, index, subJson["opcode"].to_s, subJson["description"].to_s) 125 } 126 @machineInlineSites = {} # maps compilation to a set of origins 83 127 end 84 128 … … 94 138 end 95 139 96 def totalMaxExecutionCount 140 def addMachineInlineSite(compilation, origin) 141 @machineInlineSites[compilation] = {} unless @machineInlineSites[compilation] 142 @machineInlineSites[compilation][origin] = true 143 end 144 145 def totalMachineInlineSites 146 sum = 0 147 @machineInlineSites.each_value { 148 | set | 149 sum += set.size 150 } 151 sum 152 end 153 154 def sourceMachineInlineSites 155 set = {} 156 @machineInlineSites.each_value { 157 | mySet | 158 set.merge!(mySet) 159 } 160 set.size 161 end 162 163 def totalMaxTopExecutionCount 97 164 max = 0 98 165 @bytecode.each_value { 99 166 | bytecode | 100 max = [max, bytecode.total ExecutionCount].max167 max = [max, bytecode.totalTopExecutionCount].max 101 168 } 102 169 max 103 170 end 104 171 105 def max ExecutionCount(engine)172 def maxTopExecutionCount(engine) 106 173 max = 0 107 174 @bytecode.each_value { 108 175 | bytecode | 109 max = [max, bytecode.executionCount(engine)].max 176 max = [max, bytecode.topExecutionCount(engine)].max 177 } 178 max 179 end 180 181 def totalMaxBottomExecutionCount 182 max = 0 183 @bytecode.each_value { 184 | bytecode | 185 max = [max, bytecode.totalBottomExecutionCount].max 186 } 187 max 188 end 189 190 def maxBottomExecutionCount(engine) 191 max = 0 192 @bytecode.each_value { 193 | bytecode | 194 max = [max, bytecode.bottomExecutionCount(engine)].max 110 195 } 111 196 max … … 148 233 | subJson | 149 234 CompiledBytecode.new(subJson) 235 } 236 @descriptions.each { 237 | description | 238 next if description.origin.empty? 239 description.origin[1..-1].each_with_index { 240 | inlinee, index | 241 description.origin[0].addMachineInlinee(self, inlinee.bytecodes) 242 inlinee.bytecodes.addMachineInlineSite(self, description.origin[0...index]) 243 } 150 244 } 151 245 @counters = {} … … 156 250 @counters[origin] = counter 157 251 origin[-1].addTopCount(counter) 158 } 252 origin[0].addBottomCountForCompilation(counter, self) 253 } 254 end 255 256 def counter(origin) 257 @counters[origin] 159 258 end 160 259 end … … 208 307 end 209 308 210 def sourceOnOneLine(source) 211 source = source.gsub(/\s+/, ' ') 212 if source.size > 80 213 source[0..77] + "..." 309 def sourceOnOneLine(source, limit) 310 source.gsub(/\s+/, ' ')[0...limit] 311 end 312 313 def screenWidth 314 HighLine::SystemExtensions.terminal_size[0] 315 end 316 317 def summary(mode) 318 remaining = screenWidth 319 320 hashCols = 11 321 remaining -= hashCols + 1 322 323 countCols = 10 * $engines.size 324 remaining -= countCols + 1 325 326 if mode == :full 327 machineCountCols = 10 * $engines.size 328 remaining -= machineCountCols + 1 329 330 inlinesCols = 9 331 remaining -= inlinesCols + 1 332 end 333 334 if remaining > 0 335 sourceCols = remaining 214 336 else 215 source 216 end 337 sourceCols = nil 338 end 339 340 print(center("CodeBlock", hashCols) + " " + center("Source Counts", countCols)) 341 if mode == :full 342 print(" " + center("Machine Counts", machineCountCols)) 343 print(" " + center("Inlines", inlinesCols)) 344 end 345 if sourceCols 346 print(" " + center("Source", sourceCols)) 347 end 348 puts 349 350 print(center("", hashCols) + " " + center("Base/DFG", countCols)) 351 if mode == :full 352 print(" " + center("Base/DFG", machineCountCols)) 353 print(" " + center("Src/Total", inlinesCols)) 354 end 355 puts 356 $bytecodes.sort { 357 | a, b | 358 b.totalMaxTopExecutionCount <=> a.totalMaxTopExecutionCount 359 }.each { 360 | bytecode | 361 print(center("#" + bytecode.codeHash, hashCols) + " " + 362 center($engines.map { 363 | engine | 364 bytecode.maxTopExecutionCount(engine).to_s 365 }.join("/"), countCols)) 366 if mode == :full 367 print(" " + center($engines.map { 368 | engine | 369 bytecode.maxBottomExecutionCount(engine).to_s 370 }.join("/"), machineCountCols)) 371 print(" " + center(bytecode.sourceMachineInlineSites.to_s + "/" + bytecode.totalMachineInlineSites.to_s, inlinesCols)) 372 end 373 if sourceCols 374 print(" " + sourceOnOneLine(bytecode.source, sourceCols)) 375 end 376 puts 377 } 217 378 end 218 379 … … 223 384 when "help", "h", "?" 224 385 puts "summary (s) Print a summary of code block execution rates." 386 puts "full (f) Same as summary, but prints more information." 387 puts "source Show the source for a code block." 388 puts "bytecode (b) Show the bytecode for a code block, with counts." 225 389 puts "display (d) Display details for a code block." 226 390 puts "help (h) Print this message." … … 229 393 exit 0 230 394 when "summary", "s" 231 hashCols = 14 395 summary(:summary) 396 when "full", "f" 397 summary(:full) 398 when "source" 399 if args.length != 1 400 puts "Usage: source <code block hash>" 401 return 402 end 403 $bytecodes.each { 404 | bytecode | 405 if bytecode.codeHash == args[0] 406 puts bytecode.source 407 end 408 } 409 when "bytecode", "b" 410 if args.length != 1 411 puts "Usage: source <code block hash>" 412 return 413 end 414 415 hash = args[0] 416 232 417 countCols = 10 * $engines.size 233 234 puts(rpad("CodeBlock", hashCols) + " " + rpad($engines.join("/") + " Counts", countCols) + " Source") 235 $bytecodes.sort { 236 | a, b | 237 b.totalMaxExecutionCount <=> a.totalMaxExecutionCount 238 }.each { 239 | bytecode | 240 puts(center("#" + bytecode.hash, hashCols) + " " + 241 center($engines.map { 242 | engine | 243 bytecode.maxExecutionCount(engine).to_s 244 }.join("/"), countCols) + " " + 245 sourceOnOneLine(bytecode.source)) 418 machineCols = 10 * $engines.size 419 pad = 1 420 while (countCols + 1 + machineCols + pad) % 8 != 0 421 pad += 1 422 end 423 424 puts(center("Source Counts", countCols) + " " + center("Machine Counts", machineCols) + 425 (" " * pad) + center("Bytecode for #{hash}", screenWidth - pad - countCols - 1 - machineCols)) 426 puts(center("Base/DFG", countCols) + " " + center("Base/DFG", countCols)) 427 $bytecodes.each { 428 | bytecodes | 429 next if bytecodes.codeHash != hash 430 bytecodes.each { 431 | bytecode | 432 if bytecode.shouldHaveCounts? 433 countsString = $engines.map { 434 | myEngine | 435 bytecode.topExecutionCount(myEngine) 436 }.join("/") 437 machineString = $engines.map { 438 | myEngine | 439 bytecode.bottomExecutionCount(myEngine) 440 }.join("/") 441 else 442 countsString = "" 443 machineString = "" 444 end 445 puts(center(countsString, countCols) + " " + center(machineString, machineCols) + (" " * pad) + bytecode.description.chomp) 446 } 246 447 } 247 448 when "display", "d" … … 249 450 when 1 250 451 hash = args[0] 251 engine = "Baseline" 252 $compilations.each { 253 | compilation | 254 next if compilation.bytecode.hash != hash 255 256 if compilation.engine == "DFG" 257 engine = "DFG" 258 break 259 end 260 } 452 engine = nil 261 453 when 2 262 454 if mayBeHash(args[0]) … … 272 464 end 273 465 274 unless $engines.index(engine) 275 puts "#{engine} is not a valid engine, try #{$engines.join(' or ')}." 276 return 277 end 278 279 countCols = 10 * $engines.size 466 if engine and not $engines.index(engine) 467 pattern = Regexp.new(Regexp.escape(engine), "i") 468 trueEngine = nil 469 $engines.each { 470 | myEngine | 471 if myEngine =~ pattern 472 trueEngine = myEngine 473 break 474 end 475 } 476 unless trueEngine 477 puts "#{engine} is not a valid engine, try #{$engines.join(' or ')}." 478 return 479 end 480 engine = trueEngine 481 end 482 483 actualCountCols = 13 484 sourceCountCols = 10 * $engines.size 485 486 first = true 487 count = 0 280 488 $compilations.each { 281 489 | compilation | 282 next if compilation.bytecode.hash != hash 283 next if compilation.engine != engine 490 next if compilation.bytecode.codeHash != hash 491 492 count += 1 493 494 next if engine and compilation.engine != engine 284 495 285 puts(rpad($engines.join("/") + " Counts", countCols) + " Disassembly for #{hash} in #{engine}") 496 if first 497 first = false 498 else 499 puts 500 end 501 502 puts("Compilation \##{count}:") 503 puts(center("Actual Counts", actualCountCols) + " " + center("Source Counts", sourceCountCols) + " " + center("Disassembly in #{compilation.engine}", screenWidth - 1 - sourceCountCols - 1 - actualCountCols)) 504 puts((" " * actualCountCols) + " " + center("Base/DFG", sourceCountCols)) 286 505 compilation.descriptions.each { 287 506 | description | 288 507 # FIXME: We should have a better way of detecting things like CountExecution nodes 289 508 # and slow path entries in the baseline JIT. 290 next if description.description =~ /CountExecution\(/ and engine == "DFG" 291 if description.origin.empty? or not description.origin[-1].shouldHaveCounts? or (engine == "Baseline" and description.description =~ /^\s*\(S\)/) 292 countsString = "" 509 next if description.description =~ /CountExecution\(/ and compilation.engine == "DFG" 510 if description.origin.empty? or not description.origin[-1].shouldHaveCounts? or (compilation.engine == "Baseline" and description.description =~ /^\s*\(S\)/) 511 actualCountsString = "" 512 sourceCountsString = "" 293 513 else 294 countsString = $engines.map { 514 actualCountsString = compilation.counter(description.origin).count.to_s 515 sourceCountsString = $engines.map { 295 516 | myEngine | 296 description.origin[-1]. executionCount(myEngine)517 description.origin[-1].topExecutionCount(myEngine) 297 518 }.join("/") 298 519 end 299 520 description.description.split("\n").each { 300 521 | line | 301 puts(center( countsString, countCols) + " " + line.chomp)522 puts(center(actualCountsString, actualCountCols) + " " + center(sourceCountsString, sourceCountCols) + " " + line.chomp) 302 523 } 303 524 }
Note:
See TracChangeset
for help on using the changeset viewer.