Changeset 136756 in webkit


Ignore:
Timestamp:
Dec 5, 2012, 1:40:32 PM (12 years ago)
Author:
fpizlo@apple.com
Message:

DFG profiler should display more information
https://bugs.webkit.org/show_bug.cgi?id=104163

Reviewed by Gavin Barraclough.

Added the following:

  • Distinguish between source counts and bytecode counts.


  • Add a "full" summary view that shows both kinds of counts, plus inline counts.


  • Add a "source" command to see the source.


  • Add a "bytecode" command to see the bytecode and counts.
  • Scripts/display-profiler-output:
Location:
trunk/Tools
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r136746 r136756  
     12012-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
    1202012-12-05  Yong Li  <yoli@rim.com>
    221
  • trunk/Tools/Scripts/display-profiler-output

    r136720 r136756  
    2828require 'json'
    2929require 'readline'
     30require 'highline'
    3031
    3132class 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
    3537        @bytecodeIndex = bytecodeIndex
    3638        @opcode = opcode
    3739        @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
    3943    end
    4044   
     
    4751    end
    4852   
    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
    5064        sum = 0
    5165        @topCounts.each {
     
    5670    end
    5771   
    58     def executionCount(engine)
     72    def topExecutionCount(engine)
    5973        sum = 0
    6074        @topCounts.each {
     
    6680        sum
    6781    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
    68112end
    69113
    70114class Bytecodes
    71     attr_accessor :hash, :source
    72     include Enumerable
     115    attr_accessor :codeHash, :source, :machineInlineSites
    73116   
    74117    def initialize(json)
    75         @hash = json["hash"].to_s
     118        @codeHash = json["hash"].to_s
    76119        @source = json["sourceCode"].to_s
    77120        @bytecode = {}
     
    79122            | subJson |
    80123            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
    83127    end
    84128   
     
    94138    end
    95139   
    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
    97164        max = 0
    98165        @bytecode.each_value {
    99166            | bytecode |
    100             max = [max, bytecode.totalExecutionCount].max
     167            max = [max, bytecode.totalTopExecutionCount].max
    101168        }
    102169        max
    103170    end
    104171   
    105     def maxExecutionCount(engine)
     172    def maxTopExecutionCount(engine)
    106173        max = 0
    107174        @bytecode.each_value {
    108175            | 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
    110195        }
    111196        max
     
    148233            | subJson |
    149234            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            }
    150244        }
    151245        @counters = {}
     
    156250            @counters[origin] = counter
    157251            origin[-1].addTopCount(counter)
    158         }
     252            origin[0].addBottomCountForCompilation(counter, self)
     253        }
     254    end
     255   
     256    def counter(origin)
     257        @counters[origin]
    159258    end
    160259end
     
    208307end
    209308
    210 def sourceOnOneLine(source)
    211     source = source.gsub(/\s+/, ' ')
    212     if source.size > 80
    213         source[0..77] + "..."
     309def sourceOnOneLine(source, limit)
     310    source.gsub(/\s+/, ' ')[0...limit]
     311end
     312
     313def screenWidth
     314    HighLine::SystemExtensions.terminal_size[0]
     315end
     316
     317def 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
    214336    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    }
    217378end
    218379
     
    223384    when "help", "h", "?"
    224385        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."
    225389        puts "display (d)     Display details for a code block."
    226390        puts "help (h)        Print this message."
     
    229393        exit 0
    230394    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       
    232417        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            }
    246447        }
    247448    when "display", "d"
     
    249450        when 1
    250451            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
    261453        when 2
    262454            if mayBeHash(args[0])
     
    272464        end
    273465       
    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
    280488        $compilations.each {
    281489            | 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
    284495           
    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))
    286505            compilation.descriptions.each {
    287506                | description |
    288507                # FIXME: We should have a better way of detecting things like CountExecution nodes
    289508                # 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 = ""
    293513                else
    294                     countsString = $engines.map {
     514                    actualCountsString = compilation.counter(description.origin).count.to_s
     515                    sourceCountsString = $engines.map {
    295516                        | myEngine |
    296                         description.origin[-1].executionCount(myEngine)
     517                        description.origin[-1].topExecutionCount(myEngine)
    297518                    }.join("/")
    298519                end
    299520                description.description.split("\n").each {
    300521                    | line |
    301                     puts(center(countsString, countCols) + " " + line.chomp)
     522                    puts(center(actualCountsString, actualCountCols) + " " + center(sourceCountsString, sourceCountCols) + " " + line.chomp)
    302523                }
    303524            }
Note: See TracChangeset for help on using the changeset viewer.