Modified: trunk/Tools/Scripts/display-profiler-output (136755 => 136756)
--- trunk/Tools/Scripts/display-profiler-output 2012-12-05 21:40:26 UTC (rev 136755)
+++ trunk/Tools/Scripts/display-profiler-output 2012-12-05 21:40:32 UTC (rev 136756)
@@ -27,15 +27,19 @@
require 'json'
require 'readline'
+require 'highline'
class Bytecode
- attr_accessor :bytecodeIndex, :opcode, :description, :topCounts
+ attr_accessor :bytecodes, :bytecodeIndex, :opcode, :description, :topCounts, :bottomCounts, :machineInlinees
- def initialize(bytecodeIndex, opcode, description)
+ def initialize(bytecodes, bytecodeIndex, opcode, description)
+ @bytecodes = bytecodes
@bytecodeIndex = bytecodeIndex
@opcode = opcode
@description = description
- @topCounts = []
+ @topCounts = [] # "source" counts
+ @bottomCounts = {} # "machine" counts, maps compilations to counts
+ @machineInlinees = {} # maps my compilation to a set of inlinees
end
def shouldHaveCounts?
@@ -46,7 +50,17 @@
@topCounts << count
end
- def totalExecutionCount
+ def addBottomCountForCompilation(count, compilation)
+ @bottomCounts[compilation] = [] unless @bottomCounts[compilation]
+ @bottomCounts[compilation] << count
+ end
+
+ def addMachineInlinee(compilation, inlinee)
+ @machineInlinees[compilation] = {} unless @machineInlinees[compilation]
+ @machineInlinees[compilation][inlinee] = true
+ end
+
+ def totalTopExecutionCount
sum = 0
@topCounts.each {
| value |
@@ -55,7 +69,7 @@
sum
end
- def executionCount(engine)
+ def topExecutionCount(engine)
sum = 0
@topCounts.each {
| value |
@@ -65,21 +79,51 @@
}
sum
end
+
+ def totalBottomExecutionCount
+ sum = 0
+ @bottomCounts.each_value {
+ | counts |
+ max = 0
+ counts.each {
+ | value |
+ max = [max, value.count].max
+ }
+ sum += max
+ }
+ sum
+ end
+
+ def bottomExecutionCount(engine)
+ sum = 0
+ @bottomCounts.each_pair {
+ | compilation, counts |
+ if compilation.engine == engine
+ max = 0
+ counts.each {
+ | value |
+ max = [max, value.count].max
+ }
+ sum += max
+ end
+ }
+ sum
+ end
end
class Bytecodes
- attr_accessor :hash, :source
- include Enumerable
+ attr_accessor :codeHash, :source, :machineInlineSites
def initialize(json)
- @hash = json["hash"].to_s
+ @codeHash = json["hash"].to_s
@source = json["sourceCode"].to_s
@bytecode = {}
json["bytecode"].each {
| subJson |
index = subJson["bytecodeIndex"].to_i
- @bytecode[index] = Bytecode.new(index, subJson["opcode"].to_s, subJson["description"].to_s)
+ @bytecode[index] = Bytecode.new(self, index, subJson["opcode"].to_s, subJson["description"].to_s)
}
+ @machineInlineSites = {} # maps compilation to a set of origins
end
def each
@@ -93,23 +137,64 @@
@bytecode[bytecodeIndex]
end
- def totalMaxExecutionCount
+ def addMachineInlineSite(compilation, origin)
+ @machineInlineSites[compilation] = {} unless @machineInlineSites[compilation]
+ @machineInlineSites[compilation][origin] = true
+ end
+
+ def totalMachineInlineSites
+ sum = 0
+ @machineInlineSites.each_value {
+ | set |
+ sum += set.size
+ }
+ sum
+ end
+
+ def sourceMachineInlineSites
+ set = {}
+ @machineInlineSites.each_value {
+ | mySet |
+ set.merge!(mySet)
+ }
+ set.size
+ end
+
+ def totalMaxTopExecutionCount
max = 0
@bytecode.each_value {
| bytecode |
- max = [max, bytecode.totalExecutionCount].max
+ max = [max, bytecode.totalTopExecutionCount].max
}
max
end
- def maxExecutionCount(engine)
+ def maxTopExecutionCount(engine)
max = 0
@bytecode.each_value {
| bytecode |
- max = [max, bytecode.executionCount(engine)].max
+ max = [max, bytecode.topExecutionCount(engine)].max
}
max
end
+
+ def totalMaxBottomExecutionCount
+ max = 0
+ @bytecode.each_value {
+ | bytecode |
+ max = [max, bytecode.totalBottomExecutionCount].max
+ }
+ max
+ end
+
+ def maxBottomExecutionCount(engine)
+ max = 0
+ @bytecode.each_value {
+ | bytecode |
+ max = [max, bytecode.bottomExecutionCount(engine)].max
+ }
+ max
+ end
end
def originStackFromJSON(json)
@@ -148,6 +233,15 @@
| subJson |
CompiledBytecode.new(subJson)
}
+ @descriptions.each {
+ | description |
+ next if description.origin.empty?
+ description.origin[1..-1].each_with_index {
+ | inlinee, index |
+ description.origin[0].addMachineInlinee(self, inlinee.bytecodes)
+ inlinee.bytecodes.addMachineInlineSite(self, description.origin[0...index])
+ }
+ }
@counters = {}
json["counters"].each {
| subJson |
@@ -155,8 +249,13 @@
counter = ExecutionCounter.new(origin, @engine, subJson["executionCount"].to_i)
@counters[origin] = counter
origin[-1].addTopCount(counter)
+ origin[0].addBottomCountForCompilation(counter, self)
}
end
+
+ def counter(origin)
+ @counters[origin]
+ end
end
$json = JSON::parse(IO::read(ARGV[0]))
@@ -207,13 +306,75 @@
end
end
-def sourceOnOneLine(source)
- source = source.gsub(/\s+/, ' ')
- if source.size > 80
- source[0..77] + "..."
+def sourceOnOneLine(source, limit)
+ source.gsub(/\s+/, ' ')[0...limit]
+end
+
+def screenWidth
+ HighLine::SystemExtensions.terminal_size[0]
+end
+
+def summary(mode)
+ remaining = screenWidth
+
+ hashCols = 11
+ remaining -= hashCols + 1
+
+ countCols = 10 * $engines.size
+ remaining -= countCols + 1
+
+ if mode == :full
+ machineCountCols = 10 * $engines.size
+ remaining -= machineCountCols + 1
+
+ inlinesCols = 9
+ remaining -= inlinesCols + 1
+ end
+
+ if remaining > 0
+ sourceCols = remaining
else
- source
+ sourceCols = nil
end
+
+ print(center("CodeBlock", hashCols) + " " + center("Source Counts", countCols))
+ if mode == :full
+ print(" " + center("Machine Counts", machineCountCols))
+ print(" " + center("Inlines", inlinesCols))
+ end
+ if sourceCols
+ print(" " + center("Source", sourceCols))
+ end
+ puts
+
+ print(center("", hashCols) + " " + center("Base/DFG", countCols))
+ if mode == :full
+ print(" " + center("Base/DFG", machineCountCols))
+ print(" " + center("Src/Total", inlinesCols))
+ end
+ puts
+ $bytecodes.sort {
+ | a, b |
+ b.totalMaxTopExecutionCount <=> a.totalMaxTopExecutionCount
+ }.each {
+ | bytecode |
+ print(center("#" + bytecode.codeHash, hashCols) + " " +
+ center($engines.map {
+ | engine |
+ bytecode.maxTopExecutionCount(engine).to_s
+ }.join("/"), countCols))
+ if mode == :full
+ print(" " + center($engines.map {
+ | engine |
+ bytecode.maxBottomExecutionCount(engine).to_s
+ }.join("/"), machineCountCols))
+ print(" " + center(bytecode.sourceMachineInlineSites.to_s + "/" + bytecode.totalMachineInlineSites.to_s, inlinesCols))
+ end
+ if sourceCols
+ print(" " + sourceOnOneLine(bytecode.source, sourceCols))
+ end
+ puts
+ }
end
def executeCommand(*commandArray)
@@ -222,42 +383,73 @@
case command
when "help", "h", "?"
puts "summary (s) Print a summary of code block execution rates."
+ puts "full (f) Same as summary, but prints more information."
+ puts "source Show the source for a code block."
+ puts "bytecode (b) Show the bytecode for a code block, with counts."
puts "display (d) Display details for a code block."
puts "help (h) Print this message."
puts "quit (q) Quit."
when "quit", "q", "exit"
exit 0
when "summary", "s"
- hashCols = 14
+ summary(:summary)
+ when "full", "f"
+ summary(:full)
+ when "source"
+ if args.length != 1
+ puts "Usage: source <code block hash>"
+ return
+ end
+ $bytecodes.each {
+ | bytecode |
+ if bytecode.codeHash == args[0]
+ puts bytecode.source
+ end
+ }
+ when "bytecode", "b"
+ if args.length != 1
+ puts "Usage: source <code block hash>"
+ return
+ end
+
+ hash = args[0]
+
countCols = 10 * $engines.size
+ machineCols = 10 * $engines.size
+ pad = 1
+ while (countCols + 1 + machineCols + pad) % 8 != 0
+ pad += 1
+ end
- puts(rpad("CodeBlock", hashCols) + " " + rpad($engines.join("/") + " Counts", countCols) + " Source")
- $bytecodes.sort {
- | a, b |
- b.totalMaxExecutionCount <=> a.totalMaxExecutionCount
- }.each {
- | bytecode |
- puts(center("#" + bytecode.hash, hashCols) + " " +
- center($engines.map {
- | engine |
- bytecode.maxExecutionCount(engine).to_s
- }.join("/"), countCols) + " " +
- sourceOnOneLine(bytecode.source))
+ puts(center("Source Counts", countCols) + " " + center("Machine Counts", machineCols) +
+ (" " * pad) + center("Bytecode for #{hash}", screenWidth - pad - countCols - 1 - machineCols))
+ puts(center("Base/DFG", countCols) + " " + center("Base/DFG", countCols))
+ $bytecodes.each {
+ | bytecodes |
+ next if bytecodes.codeHash != hash
+ bytecodes.each {
+ | bytecode |
+ if bytecode.shouldHaveCounts?
+ countsString = $engines.map {
+ | myEngine |
+ bytecode.topExecutionCount(myEngine)
+ }.join("/")
+ machineString = $engines.map {
+ | myEngine |
+ bytecode.bottomExecutionCount(myEngine)
+ }.join("/")
+ else
+ countsString = ""
+ machineString = ""
+ end
+ puts(center(countsString, countCols) + " " + center(machineString, machineCols) + (" " * pad) + bytecode.description.chomp)
+ }
}
when "display", "d"
case args.length
when 1
hash = args[0]
- engine = "Baseline"
- $compilations.each {
- | compilation |
- next if compilation.bytecode.hash != hash
-
- if compilation.engine == "DFG"
- engine = "DFG"
- break
- end
- }
+ engine = nil
when 2
if mayBeHash(args[0])
hash = args[0]
@@ -271,34 +463,63 @@
return
end
- unless $engines.index(engine)
- puts "#{engine} is not a valid engine, try #{$engines.join(' or ')}."
- return
+ if engine and not $engines.index(engine)
+ pattern = Regexp.new(Regexp.escape(engine), "i")
+ trueEngine = nil
+ $engines.each {
+ | myEngine |
+ if myEngine =~ pattern
+ trueEngine = myEngine
+ break
+ end
+ }
+ unless trueEngine
+ puts "#{engine} is not a valid engine, try #{$engines.join(' or ')}."
+ return
+ end
+ engine = trueEngine
end
- countCols = 10 * $engines.size
+ actualCountCols = 13
+ sourceCountCols = 10 * $engines.size
+
+ first = true
+ count = 0
$compilations.each {
| compilation |
- next if compilation.bytecode.hash != hash
- next if compilation.engine != engine
+ next if compilation.bytecode.codeHash != hash
+
+ count += 1
+
+ next if engine and compilation.engine != engine
- puts(rpad($engines.join("/") + " Counts", countCols) + " Disassembly for #{hash} in #{engine}")
+ if first
+ first = false
+ else
+ puts
+ end
+
+ puts("Compilation \##{count}:")
+ puts(center("Actual Counts", actualCountCols) + " " + center("Source Counts", sourceCountCols) + " " + center("Disassembly in #{compilation.engine}", screenWidth - 1 - sourceCountCols - 1 - actualCountCols))
+ puts((" " * actualCountCols) + " " + center("Base/DFG", sourceCountCols))
compilation.descriptions.each {
| description |
# FIXME: We should have a better way of detecting things like CountExecution nodes
# and slow path entries in the baseline JIT.
- next if description.description =~ /CountExecution\(/ and engine == "DFG"
- if description.origin.empty? or not description.origin[-1].shouldHaveCounts? or (engine == "Baseline" and description.description =~ /^\s*\(S\)/)
- countsString = ""
+ next if description.description =~ /CountExecution\(/ and compilation.engine == "DFG"
+ if description.origin.empty? or not description.origin[-1].shouldHaveCounts? or (compilation.engine == "Baseline" and description.description =~ /^\s*\(S\)/)
+ actualCountsString = ""
+ sourceCountsString = ""
else
- countsString = $engines.map {
+ actualCountsString = compilation.counter(description.origin).count.to_s
+ sourceCountsString = $engines.map {
| myEngine |
- description.origin[-1].executionCount(myEngine)
+ description.origin[-1].topExecutionCount(myEngine)
}.join("/")
end
description.description.split("\n").each {
| line |
- puts(center(countsString, countCols) + " " + line.chomp)
+ puts(center(actualCountsString, actualCountCols) + " " + center(sourceCountsString, sourceCountCols) + " " + line.chomp)
}
}
}