OLD | NEW |
1 #!/usr/bin/env ruby | 1 #!/usr/bin/env ruby |
2 | 2 |
3 # Copyright (C) 2012, 2013 Apple Inc. All rights reserved. | 3 # Copyright (C) 2012, 2013 Apple Inc. All rights reserved. |
4 # | 4 # |
5 # Redistribution and use in source and binary forms, with or without | 5 # Redistribution and use in source and binary forms, with or without |
6 # modification, are permitted provided that the following conditions | 6 # modification, are permitted provided that the following conditions |
7 # are met: | 7 # are met: |
8 # 1. Redistributions of source code must retain the above copyright | 8 # 1. Redistributions of source code must retain the above copyright |
9 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
10 # 2. Redistributions in binary form must reproduce the above copyright | 10 # 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 24 matching lines...) Expand all Loading... |
35 $stderr.puts | 35 $stderr.puts |
36 $stderr.puts "Try running:" | 36 $stderr.puts "Try running:" |
37 $stderr.puts | 37 $stderr.puts |
38 $stderr.puts "sudo gem install json" | 38 $stderr.puts "sudo gem install json" |
39 $stderr.puts "sudo gem install highline" | 39 $stderr.puts "sudo gem install highline" |
40 exit 1 | 40 exit 1 |
41 end | 41 end |
42 | 42 |
43 class Bytecode | 43 class Bytecode |
44 attr_accessor :bytecodes, :bytecodeIndex, :opcode, :description, :topCounts,
:bottomCounts, :machineInlinees, :osrExits | 44 attr_accessor :bytecodes, :bytecodeIndex, :opcode, :description, :topCounts,
:bottomCounts, :machineInlinees, :osrExits |
45 | 45 |
46 def initialize(bytecodes, bytecodeIndex, opcode, description) | 46 def initialize(bytecodes, bytecodeIndex, opcode, description) |
47 @bytecodes = bytecodes | 47 @bytecodes = bytecodes |
48 @bytecodeIndex = bytecodeIndex | 48 @bytecodeIndex = bytecodeIndex |
49 @opcode = opcode | 49 @opcode = opcode |
50 @description = description | 50 @description = description |
51 @topCounts = [] # "source" counts | 51 @topCounts = [] # "source" counts |
52 @bottomCounts = {} # "machine" counts, maps compilations to counts | 52 @bottomCounts = {} # "machine" counts, maps compilations to counts |
53 @machineInlinees = {} # maps my compilation to a set of inlinees | 53 @machineInlinees = {} # maps my compilation to a set of inlinees |
54 @osrExits = [] | 54 @osrExits = [] |
55 end | 55 end |
56 | 56 |
57 def shouldHaveCounts? | 57 def shouldHaveCounts? |
58 @opcode != "op_call_put_result" | 58 @opcode != "op_call_put_result" |
59 end | 59 end |
60 | 60 |
61 def addTopCount(count) | 61 def addTopCount(count) |
62 @topCounts << count | 62 @topCounts << count |
63 end | 63 end |
64 | 64 |
65 def addBottomCountForCompilation(count, compilation) | 65 def addBottomCountForCompilation(count, compilation) |
66 @bottomCounts[compilation] = [] unless @bottomCounts[compilation] | 66 @bottomCounts[compilation] = [] unless @bottomCounts[compilation] |
67 @bottomCounts[compilation] << count | 67 @bottomCounts[compilation] << count |
68 end | 68 end |
69 | 69 |
70 def addMachineInlinee(compilation, inlinee) | 70 def addMachineInlinee(compilation, inlinee) |
71 @machineInlinees[compilation] = {} unless @machineInlinees[compilation] | 71 @machineInlinees[compilation] = {} unless @machineInlinees[compilation] |
72 @machineInlinees[compilation][inlinee] = true | 72 @machineInlinees[compilation][inlinee] = true |
73 end | 73 end |
74 | 74 |
75 def totalTopExecutionCount | 75 def totalTopExecutionCount |
76 sum = 0 | 76 sum = 0 |
77 @topCounts.each { | 77 @topCounts.each { |
78 | value | | 78 | value | |
79 sum += value.count | 79 sum += value.count |
80 } | 80 } |
81 sum | 81 sum |
82 end | 82 end |
83 | 83 |
84 def topExecutionCount(engine) | 84 def topExecutionCount(engine) |
85 sum = 0 | 85 sum = 0 |
86 @topCounts.each { | 86 @topCounts.each { |
87 | value | | 87 | value | |
88 if value.engine == engine | 88 if value.engine == engine |
89 sum += value.count | 89 sum += value.count |
90 end | 90 end |
91 } | 91 } |
92 sum | 92 sum |
93 end | 93 end |
94 | 94 |
95 def totalBottomExecutionCount | 95 def totalBottomExecutionCount |
96 sum = 0 | 96 sum = 0 |
97 @bottomCounts.each_value { | 97 @bottomCounts.each_value { |
98 | counts | | 98 | counts | |
99 max = 0 | 99 max = 0 |
100 counts.each { | 100 counts.each { |
101 | value | | 101 | value | |
102 max = [max, value.count].max | 102 max = [max, value.count].max |
103 } | 103 } |
104 sum += max | 104 sum += max |
105 } | 105 } |
106 sum | 106 sum |
107 end | 107 end |
108 | 108 |
109 def bottomExecutionCount(engine) | 109 def bottomExecutionCount(engine) |
110 sum = 0 | 110 sum = 0 |
111 @bottomCounts.each_pair { | 111 @bottomCounts.each_pair { |
112 | compilation, counts | | 112 | compilation, counts | |
113 if compilation.engine == engine | 113 if compilation.engine == engine |
114 max = 0 | 114 max = 0 |
115 counts.each { | 115 counts.each { |
116 | value | | 116 | value | |
117 max = [max, value.count].max | 117 max = [max, value.count].max |
118 } | 118 } |
119 sum += max | 119 sum += max |
120 end | 120 end |
121 } | 121 } |
122 sum | 122 sum |
123 end | 123 end |
124 | 124 |
125 def totalExitCount | 125 def totalExitCount |
126 sum = 0 | 126 sum = 0 |
127 @osrExits.each { | 127 @osrExits.each { |
128 | exit | | 128 | exit | |
129 sum += exit.count | 129 sum += exit.count |
130 } | 130 } |
131 sum | 131 sum |
132 end | 132 end |
133 end | 133 end |
134 | 134 |
135 class Bytecodes | 135 class Bytecodes |
136 attr_accessor :codeHash, :inferredName, :source, :instructionCount, :machine
InlineSites, :compilations | 136 attr_accessor :codeHash, :inferredName, :source, :instructionCount, :machine
InlineSites, :compilations |
137 | 137 |
138 def initialize(json) | 138 def initialize(json) |
139 @codeHash = json["hash"].to_s | 139 @codeHash = json["hash"].to_s |
140 @inferredName = json["inferredName"].to_s | 140 @inferredName = json["inferredName"].to_s |
141 @source = json["sourceCode"].to_s | 141 @source = json["sourceCode"].to_s |
142 @instructionCount = json["instructionCount"].to_i | 142 @instructionCount = json["instructionCount"].to_i |
143 @bytecode = {} | 143 @bytecode = {} |
144 json["bytecode"].each { | 144 json["bytecode"].each { |
145 | subJson | | 145 | subJson | |
146 index = subJson["bytecodeIndex"].to_i | 146 index = subJson["bytecodeIndex"].to_i |
147 @bytecode[index] = Bytecode.new(self, index, subJson["opcode"].to_s,
subJson["description"].to_s) | 147 @bytecode[index] = Bytecode.new(self, index, subJson["opcode"].to_s,
subJson["description"].to_s) |
148 } | 148 } |
149 @machineInlineSites = {} # maps compilation to a set of origins | 149 @machineInlineSites = {} # maps compilation to a set of origins |
150 @compilations = [] | 150 @compilations = [] |
151 end | 151 end |
152 | 152 |
153 def name(limit) | 153 def name(limit) |
154 if to_s.size > limit | 154 if to_s.size > limit |
155 "\##{@codeHash}" | 155 "\##{@codeHash}" |
156 else | 156 else |
157 to_s | 157 to_s |
158 end | 158 end |
159 end | 159 end |
160 | 160 |
161 def to_s | 161 def to_s |
162 "#{@inferredName}\##{@codeHash}" | 162 "#{@inferredName}\##{@codeHash}" |
163 end | 163 end |
164 | 164 |
165 def matches(pattern) | 165 def matches(pattern) |
166 if pattern =~ /^#/ | 166 if pattern =~ /^#/ |
167 $~.post_match == @codeHash | 167 $~.post_match == @codeHash |
168 elsif pattern =~ /#/ | 168 elsif pattern =~ /#/ |
169 pattern == to_s | 169 pattern == to_s |
170 else | 170 else |
171 pattern == @inferredName or pattern == @codeHash | 171 pattern == @inferredName or pattern == @codeHash |
172 end | 172 end |
173 end | 173 end |
174 | 174 |
175 def each | 175 def each |
176 @bytecode.values.sort{|a, b| a.bytecodeIndex <=> b.bytecodeIndex}.each { | 176 @bytecode.values.sort{|a, b| a.bytecodeIndex <=> b.bytecodeIndex}.each { |
177 | value | | 177 | value | |
178 yield value | 178 yield value |
179 } | 179 } |
180 end | 180 end |
181 | 181 |
182 def bytecode(bytecodeIndex) | 182 def bytecode(bytecodeIndex) |
183 @bytecode[bytecodeIndex] | 183 @bytecode[bytecodeIndex] |
184 end | 184 end |
185 | 185 |
186 def addMachineInlineSite(compilation, origin) | 186 def addMachineInlineSite(compilation, origin) |
187 @machineInlineSites[compilation] = {} unless @machineInlineSites[compila
tion] | 187 @machineInlineSites[compilation] = {} unless @machineInlineSites[compila
tion] |
188 @machineInlineSites[compilation][origin] = true | 188 @machineInlineSites[compilation][origin] = true |
189 end | 189 end |
190 | 190 |
191 def totalMachineInlineSites | 191 def totalMachineInlineSites |
192 sum = 0 | 192 sum = 0 |
193 @machineInlineSites.each_value { | 193 @machineInlineSites.each_value { |
194 | set | | 194 | set | |
195 sum += set.size | 195 sum += set.size |
196 } | 196 } |
197 sum | 197 sum |
198 end | 198 end |
199 | 199 |
200 def sourceMachineInlineSites | 200 def sourceMachineInlineSites |
201 set = {} | 201 set = {} |
202 @machineInlineSites.each_value { | 202 @machineInlineSites.each_value { |
203 | mySet | | 203 | mySet | |
204 set.merge!(mySet) | 204 set.merge!(mySet) |
205 } | 205 } |
206 set.size | 206 set.size |
207 end | 207 end |
208 | 208 |
209 def totalMaxTopExecutionCount | 209 def totalMaxTopExecutionCount |
210 max = 0 | 210 max = 0 |
211 @bytecode.each_value { | 211 @bytecode.each_value { |
212 | bytecode | | 212 | bytecode | |
213 max = [max, bytecode.totalTopExecutionCount].max | 213 max = [max, bytecode.totalTopExecutionCount].max |
214 } | 214 } |
215 max | 215 max |
216 end | 216 end |
217 | 217 |
218 def maxTopExecutionCount(engine) | 218 def maxTopExecutionCount(engine) |
219 max = 0 | 219 max = 0 |
220 @bytecode.each_value { | 220 @bytecode.each_value { |
221 | bytecode | | 221 | bytecode | |
222 max = [max, bytecode.topExecutionCount(engine)].max | 222 max = [max, bytecode.topExecutionCount(engine)].max |
223 } | 223 } |
224 max | 224 max |
225 end | 225 end |
226 | 226 |
227 def totalMaxBottomExecutionCount | 227 def totalMaxBottomExecutionCount |
228 max = 0 | 228 max = 0 |
229 @bytecode.each_value { | 229 @bytecode.each_value { |
230 | bytecode | | 230 | bytecode | |
231 max = [max, bytecode.totalBottomExecutionCount].max | 231 max = [max, bytecode.totalBottomExecutionCount].max |
232 } | 232 } |
233 max | 233 max |
234 end | 234 end |
235 | 235 |
236 def maxBottomExecutionCount(engine) | 236 def maxBottomExecutionCount(engine) |
237 max = 0 | 237 max = 0 |
238 @bytecode.each_value { | 238 @bytecode.each_value { |
239 | bytecode | | 239 | bytecode | |
240 max = [max, bytecode.bottomExecutionCount(engine)].max | 240 max = [max, bytecode.bottomExecutionCount(engine)].max |
241 } | 241 } |
242 max | 242 max |
243 end | 243 end |
244 | 244 |
245 def totalExitCount | 245 def totalExitCount |
246 sum = 0 | 246 sum = 0 |
247 each { | 247 each { |
248 | bytecode | | 248 | bytecode | |
249 sum += bytecode.totalExitCount | 249 sum += bytecode.totalExitCount |
250 } | 250 } |
251 sum | 251 sum |
252 end | 252 end |
253 end | 253 end |
254 | 254 |
255 class ProfiledBytecode | 255 class ProfiledBytecode |
256 attr_reader :bytecodeIndex, :description | 256 attr_reader :bytecodeIndex, :description |
257 | 257 |
258 def initialize(json) | 258 def initialize(json) |
259 @bytecodeIndex = json["bytecodeIndex"].to_i | 259 @bytecodeIndex = json["bytecodeIndex"].to_i |
260 @description = json["description"].to_s | 260 @description = json["description"].to_s |
261 end | 261 end |
262 end | 262 end |
263 | 263 |
264 class ProfiledBytecodes | 264 class ProfiledBytecodes |
265 attr_reader :header, :bytecodes | 265 attr_reader :header, :bytecodes |
266 | 266 |
267 def initialize(json) | 267 def initialize(json) |
268 @header = json["header"] | 268 @header = json["header"] |
269 @bytecodes = $bytecodes[json["bytecodesID"].to_i] | 269 @bytecodes = $bytecodes[json["bytecodesID"].to_i] |
270 @sequence = json["bytecode"].map { | 270 @sequence = json["bytecode"].map { |
271 | subJson | | 271 | subJson | |
272 ProfiledBytecode.new(subJson) | 272 ProfiledBytecode.new(subJson) |
273 } | 273 } |
274 end | 274 end |
275 | 275 |
276 def each | 276 def each |
277 @sequence.each { | 277 @sequence.each { |
278 | description | | 278 | description | |
279 yield description | 279 yield description |
280 } | 280 } |
281 end | 281 end |
282 end | 282 end |
283 | 283 |
284 def originStackFromJSON(json) | 284 def originStackFromJSON(json) |
285 json.map { | 285 json.map { |
286 | subJson | | 286 | subJson | |
287 $bytecodes[subJson["bytecodesID"].to_i].bytecode(subJson["bytecodeIndex"
].to_i) | 287 $bytecodes[subJson["bytecodesID"].to_i].bytecode(subJson["bytecodeIndex"
].to_i) |
288 } | 288 } |
289 end | 289 end |
290 | 290 |
291 class CompiledBytecode | 291 class CompiledBytecode |
292 attr_accessor :origin, :description | 292 attr_accessor :origin, :description |
293 | 293 |
294 def initialize(json) | 294 def initialize(json) |
295 @origin = originStackFromJSON(json["origin"]) | 295 @origin = originStackFromJSON(json["origin"]) |
296 @description = json["description"].to_s | 296 @description = json["description"].to_s |
297 end | 297 end |
298 end | 298 end |
299 | 299 |
300 class ExecutionCounter | 300 class ExecutionCounter |
301 attr_accessor :origin, :engine, :count | 301 attr_accessor :origin, :engine, :count |
302 | 302 |
303 def initialize(origin, engine, count) | 303 def initialize(origin, engine, count) |
304 @origin = origin | 304 @origin = origin |
305 @engine = engine | 305 @engine = engine |
306 @count = count | 306 @count = count |
307 end | 307 end |
308 end | 308 end |
309 | 309 |
310 class OSRExit | 310 class OSRExit |
311 attr_reader :compilation, :origin, :codeAddresses, :exitKind, :isWatchpoint,
:count | 311 attr_reader :compilation, :origin, :codeAddresses, :exitKind, :isWatchpoint,
:count |
312 | 312 |
313 def initialize(compilation, origin, codeAddresses, exitKind, isWatchpoint, c
ount) | 313 def initialize(compilation, origin, codeAddresses, exitKind, isWatchpoint, c
ount) |
314 @compilation = compilation | 314 @compilation = compilation |
315 @origin = origin | 315 @origin = origin |
316 @codeAddresses = codeAddresses | 316 @codeAddresses = codeAddresses |
317 @exitKind = exitKind | 317 @exitKind = exitKind |
318 @isWatchpoint = isWatchpoint | 318 @isWatchpoint = isWatchpoint |
319 @count = count | 319 @count = count |
320 end | 320 end |
321 | 321 |
322 def dumpForDisplay(prefix) | 322 def dumpForDisplay(prefix) |
323 puts(prefix + "EXIT: due to #{@exitKind}, #{@count} times") | 323 puts(prefix + "EXIT: due to #{@exitKind}, #{@count} times") |
324 end | 324 end |
325 end | 325 end |
326 | 326 |
327 class Compilation | 327 class Compilation |
328 attr_accessor :bytecode, :engine, :descriptions, :counters, :compilationInde
x | 328 attr_accessor :bytecode, :engine, :descriptions, :counters, :compilationInde
x |
329 attr_accessor :osrExits, :profiledBytecodes, :numInlinedGetByIds, :numInline
dPutByIds | 329 attr_accessor :osrExits, :profiledBytecodes, :numInlinedGetByIds, :numInline
dPutByIds |
330 attr_accessor :numInlinedCalls | 330 attr_accessor :numInlinedCalls |
331 | 331 |
332 def initialize(json) | 332 def initialize(json) |
333 @bytecode = $bytecodes[json["bytecodesID"].to_i] | 333 @bytecode = $bytecodes[json["bytecodesID"].to_i] |
334 @bytecode.compilations << self | 334 @bytecode.compilations << self |
335 @compilationIndex = @bytecode.compilations.size | 335 @compilationIndex = @bytecode.compilations.size |
336 @engine = json["compilationKind"] | 336 @engine = json["compilationKind"] |
337 @descriptions = json["descriptions"].map { | 337 @descriptions = json["descriptions"].map { |
338 | subJson | | 338 | subJson | |
339 CompiledBytecode.new(subJson) | 339 CompiledBytecode.new(subJson) |
340 } | 340 } |
341 @descriptions.each { | 341 @descriptions.each { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 } | 374 } |
375 @profiledBytecodes = [] | 375 @profiledBytecodes = [] |
376 json["profiledBytecodes"].each { | 376 json["profiledBytecodes"].each { |
377 | subJson | | 377 | subJson | |
378 @profiledBytecodes << ProfiledBytecodes.new(subJson) | 378 @profiledBytecodes << ProfiledBytecodes.new(subJson) |
379 } | 379 } |
380 @numInlinedGetByIds = json["numInlinedGetByIds"] | 380 @numInlinedGetByIds = json["numInlinedGetByIds"] |
381 @numInlinedPutByIds = json["numInlinedPutByIds"] | 381 @numInlinedPutByIds = json["numInlinedPutByIds"] |
382 @numInlinedCalls = json["numInlinedCalls"] | 382 @numInlinedCalls = json["numInlinedCalls"] |
383 end | 383 end |
384 | 384 |
385 def counter(origin) | 385 def counter(origin) |
386 @counters[origin] | 386 @counters[origin] |
387 end | 387 end |
388 | 388 |
389 def to_s | 389 def to_s |
390 "#{bytecode}-#{compilationIndex}-#{engine}" | 390 "#{bytecode}-#{compilationIndex}-#{engine}" |
391 end | 391 end |
392 end | 392 end |
393 | 393 |
394 class DescriptionLine | 394 class DescriptionLine |
395 attr_reader :actualCountsString, :sourceCountsString, :disassembly, :shouldS
how | 395 attr_reader :actualCountsString, :sourceCountsString, :disassembly, :shouldS
how |
396 | 396 |
397 def initialize(actualCountsString, sourceCountsString, disassembly, shouldSh
ow) | 397 def initialize(actualCountsString, sourceCountsString, disassembly, shouldSh
ow) |
398 @actualCountsString = actualCountsString | 398 @actualCountsString = actualCountsString |
399 @sourceCountsString = sourceCountsString | 399 @sourceCountsString = sourceCountsString |
400 @disassembly = disassembly | 400 @disassembly = disassembly |
401 @shouldShow = shouldShow | 401 @shouldShow = shouldShow |
402 end | 402 end |
403 | 403 |
404 def codeAddress | 404 def codeAddress |
405 if @disassembly =~ /^\s*(0x[0-9a-fA-F]+):/ | 405 if @disassembly =~ /^\s*(0x[0-9a-fA-F]+):/ |
406 $1.hex | 406 $1.hex |
407 else | 407 else |
408 nil | 408 nil |
409 end | 409 end |
410 end | 410 end |
411 end | 411 end |
412 | 412 |
413 if ARGV.length != 1 | 413 if ARGV.length != 1 |
414 $stderr.puts "Usage: display-profiler-output <path to profiler output file>" | 414 $stderr.puts "Usage: display-profiler-output <path to profiler output file>" |
415 $stderr.puts | 415 $stderr.puts |
416 $stderr.puts "The typical usage pattern for the profiler currently looks som
ething like:" | 416 $stderr.puts "The typical usage pattern for the profiler currently looks som
ething like:" |
417 $stderr.puts | 417 $stderr.puts |
418 $stderr.puts "Path/To/jsc -p profile.json myprogram.js" | 418 $stderr.puts "Path/To/jsc -p profile.json myprogram.js" |
419 $stderr.puts "display-profiler-output profile.json" | 419 $stderr.puts "display-profiler-output profile.json" |
420 exit 1 | 420 exit 1 |
421 end | 421 end |
422 | 422 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
467 def screenWidth | 467 def screenWidth |
468 if $stdin.tty? | 468 if $stdin.tty? |
469 HighLine::SystemExtensions.terminal_size[0] | 469 HighLine::SystemExtensions.terminal_size[0] |
470 else | 470 else |
471 200 | 471 200 |
472 end | 472 end |
473 end | 473 end |
474 | 474 |
475 def summary(mode) | 475 def summary(mode) |
476 remaining = screenWidth | 476 remaining = screenWidth |
477 | 477 |
478 # Figure out how many columns we need for the code block names, and for coun
ts | 478 # Figure out how many columns we need for the code block names, and for coun
ts |
479 maxCount = 0 | 479 maxCount = 0 |
480 maxName = 0 | 480 maxName = 0 |
481 $bytecodes.each { | 481 $bytecodes.each { |
482 | bytecodes | | 482 | bytecodes | |
483 maxCount = ([maxCount] + $engines.map { | 483 maxCount = ([maxCount] + $engines.map { |
484 | engine | | 484 | engine | |
485 bytecodes.maxTopExecutionCount(engine) | 485 bytecodes.maxTopExecutionCount(engine) |
486 } + $engines.map { | 486 } + $engines.map { |
487 | engine | | 487 | engine | |
488 bytecodes.maxBottomExecutionCount(engine) | 488 bytecodes.maxBottomExecutionCount(engine) |
489 }).max | 489 }).max |
490 maxName = [bytecodes.to_s.size, maxName].max | 490 maxName = [bytecodes.to_s.size, maxName].max |
491 } | 491 } |
492 maxCountDigits = maxCount.to_s.size | 492 maxCountDigits = maxCount.to_s.size |
493 | 493 |
494 hashCols = [[maxName, 30].min, "CodeBlock".size].max | 494 hashCols = [[maxName, 30].min, "CodeBlock".size].max |
495 remaining -= hashCols + 1 | 495 remaining -= hashCols + 1 |
496 | 496 |
497 countCols = [maxCountDigits * $engines.size, "Source Counts".size].max | 497 countCols = [maxCountDigits * $engines.size, "Source Counts".size].max |
498 remaining -= countCols + 1 | 498 remaining -= countCols + 1 |
499 | 499 |
500 if mode == :full | 500 if mode == :full |
501 instructionCountCols = 6 | 501 instructionCountCols = 6 |
502 remaining -= instructionCountCols + 1 | 502 remaining -= instructionCountCols + 1 |
503 | 503 |
504 machineCountCols = [maxCountDigits * $engines.size, "Machine Counts".siz
e].max | 504 machineCountCols = [maxCountDigits * $engines.size, "Machine Counts".siz
e].max |
505 remaining -= machineCountCols + 1 | 505 remaining -= machineCountCols + 1 |
506 | 506 |
507 compilationsCols = 7 | 507 compilationsCols = 7 |
508 remaining -= compilationsCols + 1 | 508 remaining -= compilationsCols + 1 |
509 | 509 |
510 inlinesCols = 9 | 510 inlinesCols = 9 |
511 remaining -= inlinesCols + 1 | 511 remaining -= inlinesCols + 1 |
512 | 512 |
513 exitCountCols = 7 | 513 exitCountCols = 7 |
514 remaining -= exitCountCols + 1 | 514 remaining -= exitCountCols + 1 |
515 | 515 |
516 recentOptsCols = 12 | 516 recentOptsCols = 12 |
517 remaining -= recentOptsCols + 1 | 517 remaining -= recentOptsCols + 1 |
518 end | 518 end |
519 | 519 |
520 if remaining > 0 | 520 if remaining > 0 |
521 sourceCols = remaining | 521 sourceCols = remaining |
522 else | 522 else |
523 sourceCols = nil | 523 sourceCols = nil |
524 end | 524 end |
525 | 525 |
526 print(center("CodeBlock", hashCols)) | 526 print(center("CodeBlock", hashCols)) |
527 if mode == :full | 527 if mode == :full |
528 print(" " + center("#Instr", instructionCountCols)) | 528 print(" " + center("#Instr", instructionCountCols)) |
529 end | 529 end |
530 print(" " + center("Source Counts", countCols)) | 530 print(" " + center("Source Counts", countCols)) |
531 if mode == :full | 531 if mode == :full |
532 print(" " + center("Machine Counts", machineCountCols)) | 532 print(" " + center("Machine Counts", machineCountCols)) |
533 print(" " + center("#Compil", compilationsCols)) | 533 print(" " + center("#Compil", compilationsCols)) |
534 print(" " + center("Inlines", inlinesCols)) | 534 print(" " + center("Inlines", inlinesCols)) |
535 print(" " + center("#Exits", exitCountCols)) | 535 print(" " + center("#Exits", exitCountCols)) |
536 print(" " + center("Last Opts", recentOptsCols)) | 536 print(" " + center("Last Opts", recentOptsCols)) |
537 end | 537 end |
538 if sourceCols | 538 if sourceCols |
539 print(" " + center("Source", sourceCols)) | 539 print(" " + center("Source", sourceCols)) |
540 end | 540 end |
541 puts | 541 puts |
542 | 542 |
543 print(center("", hashCols)) | 543 print(center("", hashCols)) |
544 if mode == :full | 544 if mode == :full |
545 print(" " + (" " * instructionCountCols)) | 545 print(" " + (" " * instructionCountCols)) |
546 end | 546 end |
547 print(" " + center("Base/DFG", countCols)) | 547 print(" " + center("Base/DFG", countCols)) |
548 if mode == :full | 548 if mode == :full |
549 print(" " + center("Base/DFG", machineCountCols)) | 549 print(" " + center("Base/DFG", machineCountCols)) |
550 print(" " + (" " * compilationsCols)) | 550 print(" " + (" " * compilationsCols)) |
551 print(" " + center("Src/Total", inlinesCols)) | 551 print(" " + center("Src/Total", inlinesCols)) |
552 print(" " + (" " * exitCountCols)) | 552 print(" " + (" " * exitCountCols)) |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
621 | bytecode | | 621 | bytecode | |
622 if bytecode.matches(args[0]) | 622 if bytecode.matches(args[0]) |
623 puts bytecode.source | 623 puts bytecode.source |
624 end | 624 end |
625 } | 625 } |
626 when "bytecode", "b" | 626 when "bytecode", "b" |
627 if args.length != 1 | 627 if args.length != 1 |
628 puts "Usage: source <code block hash>" | 628 puts "Usage: source <code block hash>" |
629 return | 629 return |
630 end | 630 end |
631 | 631 |
632 hash = args[0] | 632 hash = args[0] |
633 | 633 |
634 countCols = 10 * $engines.size | 634 countCols = 10 * $engines.size |
635 machineCols = 10 * $engines.size | 635 machineCols = 10 * $engines.size |
636 pad = 1 | 636 pad = 1 |
637 while (countCols + 1 + machineCols + pad) % 8 != 0 | 637 while (countCols + 1 + machineCols + pad) % 8 != 0 |
638 pad += 1 | 638 pad += 1 |
639 end | 639 end |
640 | 640 |
641 $bytecodes.each { | 641 $bytecodes.each { |
642 | bytecodes | | 642 | bytecodes | |
643 next unless bytecodes.matches(hash) | 643 next unless bytecodes.matches(hash) |
644 puts(center("Source Counts", countCols) + " " + center("Machine Coun
ts", machineCols) + | 644 puts(center("Source Counts", countCols) + " " + center("Machine Coun
ts", machineCols) + |
645 (" " * pad) + center("Bytecode for #{bytecodes}", screenWidth -
pad - countCols - 1 - machineCols)) | 645 (" " * pad) + center("Bytecode for #{bytecodes}", screenWidth -
pad - countCols - 1 - machineCols)) |
646 puts(center("Base/DFG", countCols) + " " + center("Base/DFG", countC
ols)) | 646 puts(center("Base/DFG", countCols) + " " + center("Base/DFG", countC
ols)) |
647 bytecodes.each { | 647 bytecodes.each { |
648 | bytecode | | 648 | bytecode | |
649 if bytecode.shouldHaveCounts? | 649 if bytecode.shouldHaveCounts? |
650 countsString = $engines.map { | 650 countsString = $engines.map { |
(...skipping 14 matching lines...) Expand all Loading... |
665 puts(center("!!!!!", countCols) + " " + center("!!!!!", mach
ineCols) + (" " * (pad + 10)) + | 665 puts(center("!!!!!", countCols) + " " + center("!!!!!", mach
ineCols) + (" " * (pad + 10)) + |
666 "EXIT: in #{exit.compilation} due to #{exit.exitKind},
#{exit.count} times") | 666 "EXIT: in #{exit.compilation} due to #{exit.exitKind},
#{exit.count} times") |
667 } | 667 } |
668 } | 668 } |
669 } | 669 } |
670 when "profiling", "p" | 670 when "profiling", "p" |
671 if args.length != 1 | 671 if args.length != 1 |
672 puts "Usage: profiling <code block hash>" | 672 puts "Usage: profiling <code block hash>" |
673 return | 673 return |
674 end | 674 end |
675 | 675 |
676 hash = args[0] | 676 hash = args[0] |
677 | 677 |
678 first = true | 678 first = true |
679 $compilations.each { | 679 $compilations.each { |
680 | compilation | | 680 | compilation | |
681 | 681 |
682 compilation.profiledBytecodes.each { | 682 compilation.profiledBytecodes.each { |
683 | profiledBytecodes | | 683 | profiledBytecodes | |
684 if profiledBytecodes.bytecodes.matches(hash) | 684 if profiledBytecodes.bytecodes.matches(hash) |
685 if first | 685 if first |
686 first = false | 686 first = false |
687 else | 687 else |
688 puts | 688 puts |
689 end | 689 end |
690 | 690 |
691 puts "Compilation #{compilation}:" | 691 puts "Compilation #{compilation}:" |
692 profiledBytecodes.header.each { | 692 profiledBytecodes.header.each { |
693 | header | | 693 | header | |
694 puts(" " * 6 + header) | 694 puts(" " * 6 + header) |
695 } | 695 } |
696 profiledBytecodes.each { | 696 profiledBytecodes.each { |
697 | bytecode | | 697 | bytecode | |
698 puts(" " * 8 + bytecode.description) | 698 puts(" " * 8 + bytecode.description) |
699 profiledBytecodes.bytecodes.bytecode(bytecode.bytecodeIn
dex).osrExits.each { | 699 profiledBytecodes.bytecodes.bytecode(bytecode.bytecodeIn
dex).osrExits.each { |
700 | exit | | 700 | exit | |
701 if exit.compilation == compilation | 701 if exit.compilation == compilation |
702 puts(" !!!!! EXIT: due to #{exit.exitK
ind}, #{exit.count} times") | 702 puts(" !!!!! EXIT: due to #{exit.exitK
ind}, #{exit.count} times") |
703 end | 703 end |
704 } | 704 } |
705 } | 705 } |
706 end | 706 end |
707 } | 707 } |
708 } | 708 } |
709 when "inlines" | 709 when "inlines" |
710 if args.length != 1 | 710 if args.length != 1 |
711 puts "Usage: inlines <code block hash>" | 711 puts "Usage: inlines <code block hash>" |
712 return | 712 return |
713 end | 713 end |
714 | 714 |
715 hash = args[0] | 715 hash = args[0] |
716 | 716 |
717 $bytecodes.each { | 717 $bytecodes.each { |
718 | bytecodes | | 718 | bytecodes | |
719 next unless bytecodes.matches(hash) | 719 next unless bytecodes.matches(hash) |
720 | 720 |
721 # FIXME: print something useful to say more about which code block t
his is. | 721 # FIXME: print something useful to say more about which code block t
his is. |
722 | 722 |
723 $compilations.each { | 723 $compilations.each { |
724 | compilation | | 724 | compilation | |
725 myOrigins = [] | 725 myOrigins = [] |
726 compilation.descriptions.each { | 726 compilation.descriptions.each { |
727 | description | | 727 | description | |
728 if description.origin.index { | 728 if description.origin.index { |
729 | myBytecode | | 729 | myBytecode | |
730 bytecodes == myBytecode.bytecodes | 730 bytecodes == myBytecode.bytecodes |
731 } | 731 } |
732 myOrigins << description.origin | 732 myOrigins << description.origin |
733 end | 733 end |
734 } | 734 } |
735 myOrigins.uniq! | 735 myOrigins.uniq! |
736 myOrigins.sort! { | 736 myOrigins.sort! { |
737 | a, b | | 737 | a, b | |
738 result = 0 | 738 result = 0 |
739 [a.size, b.size].min.times { | 739 [a.size, b.size].min.times { |
740 | index | | 740 | index | |
741 result = a[index].bytecodeIndex <=> b[index].bytecodeInd
ex | 741 result = a[index].bytecodeIndex <=> b[index].bytecodeInd
ex |
742 break if result != 0 | 742 break if result != 0 |
743 } | 743 } |
744 result | 744 result |
745 } | 745 } |
746 | 746 |
747 next if myOrigins.empty? | 747 next if myOrigins.empty? |
748 | 748 |
749 printArray = [] | 749 printArray = [] |
750 lastPrintStack = [] | 750 lastPrintStack = [] |
751 | 751 |
752 def originToPrintStack(origin) | 752 def originToPrintStack(origin) |
753 (0...(origin.size - 1)).map { | 753 (0...(origin.size - 1)).map { |
754 | index | | 754 | index | |
755 "bc\##{origin[index].bytecodeIndex} --> #{origin[index +
1].bytecodes}" | 755 "bc\##{origin[index].bytecodeIndex} --> #{origin[index +
1].bytecodes}" |
756 } | 756 } |
757 end | 757 end |
758 | 758 |
759 def printStack(printArray, stack, lastStack) | 759 def printStack(printArray, stack, lastStack) |
760 stillCommon = true | 760 stillCommon = true |
761 stack.each_with_index { | 761 stack.each_with_index { |
762 | entry, index | | 762 | entry, index | |
763 next if stillCommon and entry == lastStack[index] | 763 next if stillCommon and entry == lastStack[index] |
764 printArray << (" " * (index + 1) + entry) | 764 printArray << (" " * (index + 1) + entry) |
765 stillCommon = false | 765 stillCommon = false |
766 } | 766 } |
767 end | 767 end |
768 | 768 |
769 myOrigins.each { | 769 myOrigins.each { |
770 | origin | | 770 | origin | |
771 currentPrintStack = originToPrintStack(origin) | 771 currentPrintStack = originToPrintStack(origin) |
772 printStack(printArray, currentPrintStack, lastPrintStack) | 772 printStack(printArray, currentPrintStack, lastPrintStack) |
773 lastPrintStack = currentPrintStack | 773 lastPrintStack = currentPrintStack |
774 } | 774 } |
775 | 775 |
776 next if printArray.empty? | 776 next if printArray.empty? |
777 | 777 |
778 puts "Compilation #{compilation}:" | 778 puts "Compilation #{compilation}:" |
779 printArray.each { | 779 printArray.each { |
780 | entry | | 780 | entry | |
781 puts entry | 781 puts entry |
782 } | 782 } |
783 } | 783 } |
784 } | 784 } |
785 when "display", "d" | 785 when "display", "d" |
786 compilationIndex = nil | 786 compilationIndex = nil |
787 | 787 |
788 case args.length | 788 case args.length |
789 when 1 | 789 when 1 |
790 if args[0] == "*" | 790 if args[0] == "*" |
791 hash = nil | 791 hash = nil |
792 else | 792 else |
793 hash = args[0] | 793 hash = args[0] |
794 end | 794 end |
795 engine = nil | 795 engine = nil |
796 when 2 | 796 when 2 |
797 if mayBeHash(args[0]) | 797 if mayBeHash(args[0]) |
798 hash = args[0] | 798 hash = args[0] |
799 engine = args[1] | 799 engine = args[1] |
800 else | 800 else |
801 engine = args[0] | 801 engine = args[0] |
802 hash = args[1] | 802 hash = args[1] |
803 end | 803 end |
804 else | 804 else |
805 puts "Usage: summary <code block hash> <engine>" | 805 puts "Usage: summary <code block hash> <engine>" |
806 return | 806 return |
807 end | 807 end |
808 | 808 |
809 if hash and hash =~ /-([0-9]+)-/ | 809 if hash and hash =~ /-([0-9]+)-/ |
810 hash = $~.pre_match | 810 hash = $~.pre_match |
811 engine = $~.post_match | 811 engine = $~.post_match |
812 compilationIndex = $1.to_i | 812 compilationIndex = $1.to_i |
813 end | 813 end |
814 | 814 |
815 if engine and not $engines.index(engine) | 815 if engine and not $engines.index(engine) |
816 pattern = Regexp.new(Regexp.escape(engine), "i") | 816 pattern = Regexp.new(Regexp.escape(engine), "i") |
817 trueEngine = nil | 817 trueEngine = nil |
818 $engines.each { | 818 $engines.each { |
819 | myEngine | | 819 | myEngine | |
820 if myEngine =~ pattern | 820 if myEngine =~ pattern |
821 trueEngine = myEngine | 821 trueEngine = myEngine |
822 break | 822 break |
823 end | 823 end |
824 } | 824 } |
825 unless trueEngine | 825 unless trueEngine |
826 puts "#{engine} is not a valid engine, try #{$engines.join(' or
')}." | 826 puts "#{engine} is not a valid engine, try #{$engines.join(' or
')}." |
827 return | 827 return |
828 end | 828 end |
829 engine = trueEngine | 829 engine = trueEngine |
830 end | 830 end |
831 | 831 |
832 actualCountCols = 13 | 832 actualCountCols = 13 |
833 sourceCountCols = 10 * $engines.size | 833 sourceCountCols = 10 * $engines.size |
834 | 834 |
835 first = true | 835 first = true |
836 $compilations.each { | 836 $compilations.each { |
837 | compilation | | 837 | compilation | |
838 next if hash and not compilation.bytecode.matches(hash) | 838 next if hash and not compilation.bytecode.matches(hash) |
839 next if engine and compilation.engine != engine | 839 next if engine and compilation.engine != engine |
840 next if compilationIndex and compilation.compilationIndex != compila
tionIndex | 840 next if compilationIndex and compilation.compilationIndex != compila
tionIndex |
841 | 841 |
842 if first | 842 if first |
843 first = false | 843 first = false |
844 else | 844 else |
845 puts | 845 puts |
846 end | 846 end |
847 | 847 |
848 puts("Compilation #{compilation}:") | 848 puts("Compilation #{compilation}:") |
849 puts(" Num inlined: GetByIds: #{compilation.numInlinedGetByIds}
PutByIds: #{compilation.numInlinedPutByIds} Calls: #{compilation.numInlinedCall
s}") | 849 puts(" Num inlined: GetByIds: #{compilation.numInlinedGetByIds}
PutByIds: #{compilation.numInlinedPutByIds} Calls: #{compilation.numInlinedCall
s}") |
850 puts(center("Actual Counts", actualCountCols) + " " + center("Source
Counts", sourceCountCols) + " " + center("Disassembly in #{compilation.engine}"
, screenWidth - 1 - sourceCountCols - 1 - actualCountCols)) | 850 puts(center("Actual Counts", actualCountCols) + " " + center("Source
Counts", sourceCountCols) + " " + center("Disassembly in #{compilation.engine}"
, screenWidth - 1 - sourceCountCols - 1 - actualCountCols)) |
851 puts((" " * actualCountCols) + " " + center("Base/DFG", sourceCountC
ols)) | 851 puts((" " * actualCountCols) + " " + center("Base/DFG", sourceCountC
ols)) |
852 | 852 |
853 lines = [] | 853 lines = [] |
854 | 854 |
855 compilation.descriptions.each { | 855 compilation.descriptions.each { |
856 | description | | 856 | description | |
857 # FIXME: We should have a better way of detecting things like Co
untExecution nodes | 857 # FIXME: We should have a better way of detecting things like Co
untExecution nodes |
(...skipping 11 matching lines...) Expand all Loading... |
869 sourceCountsString = $engines.map { | 869 sourceCountsString = $engines.map { |
870 | myEngine | | 870 | myEngine | |
871 description.origin[-1].topExecutionCount(myEngine) | 871 description.origin[-1].topExecutionCount(myEngine) |
872 }.join("/") | 872 }.join("/") |
873 end | 873 end |
874 description.description.split("\n").each { | 874 description.description.split("\n").each { |
875 | line | | 875 | line | |
876 lines << DescriptionLine.new(actualCountsString, sourceCount
sString, line.chomp, shouldShow) | 876 lines << DescriptionLine.new(actualCountsString, sourceCount
sString, line.chomp, shouldShow) |
877 } | 877 } |
878 } | 878 } |
879 | 879 |
880 exitPrefix = center("!!!!!", actualCountCols) + " " + center("!!!!!"
, sourceCountCols) + (" " * 25) | 880 exitPrefix = center("!!!!!", actualCountCols) + " " + center("!!!!!"
, sourceCountCols) + (" " * 25) |
881 | 881 |
882 lines.each_with_index { | 882 lines.each_with_index { |
883 | line, index | | 883 | line, index | |
884 codeAddress = line.codeAddress | 884 codeAddress = line.codeAddress |
885 if codeAddress | 885 if codeAddress |
886 list = compilation.osrExits[codeAddress] | 886 list = compilation.osrExits[codeAddress] |
887 if list | 887 if list |
888 list.each { | 888 list.each { |
889 | exit | | 889 | exit | |
890 if exit.isWatchpoint | 890 if exit.isWatchpoint |
891 exit.dumpForDisplay(exitPrefix) | 891 exit.dumpForDisplay(exitPrefix) |
892 end | 892 end |
893 } | 893 } |
894 end | 894 end |
895 end | 895 end |
896 if line.shouldShow | 896 if line.shouldShow |
897 puts(center(line.actualCountsString, actualCountCols) + " "
+ center(line.sourceCountsString, sourceCountCols) + " " + line.disassembly) | 897 puts(center(line.actualCountsString, actualCountCols) + " "
+ center(line.sourceCountsString, sourceCountCols) + " " + line.disassembly) |
898 end | 898 end |
899 if codeAddress | 899 if codeAddress |
900 # Find the next disassembly address. | 900 # Find the next disassembly address. |
901 endIndex = index + 1 | 901 endIndex = index + 1 |
902 endAddress = nil | 902 endAddress = nil |
903 while endIndex < lines.size | 903 while endIndex < lines.size |
904 myAddress = lines[endIndex].codeAddress | 904 myAddress = lines[endIndex].codeAddress |
905 if myAddress | 905 if myAddress |
906 endAddress = myAddress | 906 endAddress = myAddress |
907 break | 907 break |
908 end | 908 end |
909 endIndex += 1 | 909 endIndex += 1 |
910 end | 910 end |
911 | 911 |
912 if endAddress | 912 if endAddress |
913 list = compilation.osrExits[endAddress] | 913 list = compilation.osrExits[endAddress] |
914 if list | 914 if list |
915 list.each { | 915 list.each { |
916 | exit | | 916 | exit | |
917 unless exit.isWatchpoint | 917 unless exit.isWatchpoint |
918 exit.dumpForDisplay(exitPrefix) | 918 exit.dumpForDisplay(exitPrefix) |
919 end | 919 end |
920 } | 920 } |
921 end | 921 end |
922 end | 922 end |
923 end | 923 end |
924 } | 924 } |
925 } | 925 } |
926 else | 926 else |
927 puts "Invalid command: #{command}" | 927 puts "Invalid command: #{command}" |
928 end | 928 end |
929 end | 929 end |
930 | 930 |
931 if $stdin.tty? | 931 if $stdin.tty? |
932 executeCommand("full") | 932 executeCommand("full") |
933 end | 933 end |
934 | 934 |
935 while commandLine = Readline.readline("> ", true) | 935 while commandLine = Readline.readline("> ", true) |
936 executeCommand(*commandLine.split) | 936 executeCommand(*commandLine.split) |
937 end | 937 end |
938 | 938 |
OLD | NEW |