| Index: tools/tickprocessor.py
|
| diff --git a/tools/tickprocessor.py b/tools/tickprocessor.py
|
| index 9459ae8c71db485bc1906dd846d2be2d49ecda90..145dfaed4f38d328021f74c4e0004270a57d1af7 100644
|
| --- a/tools/tickprocessor.py
|
| +++ b/tools/tickprocessor.py
|
| @@ -25,9 +25,9 @@
|
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
| -import csv, splaytree, sys
|
| +import csv, splaytree, sys, re
|
| from operator import itemgetter
|
| -import getopt, os
|
| +import getopt, os, string
|
|
|
| class CodeEntry(object):
|
|
|
| @@ -56,6 +56,9 @@ class CodeEntry(object):
|
| def IsSharedLibraryEntry(self):
|
| return False
|
|
|
| + def IsICEntry(self):
|
| + return False
|
| +
|
|
|
| class SharedLibraryEntry(CodeEntry):
|
|
|
| @@ -74,6 +77,7 @@ class JSCodeEntry(CodeEntry):
|
| self.size = size
|
| self.assembler = assembler
|
| self.region_ticks = None
|
| + self.builtin_ic_re = re.compile('^(Keyed)?(Call|Load|Store)IC_')
|
|
|
| def Tick(self, pc, stack):
|
| super(JSCodeEntry, self).Tick(pc, stack)
|
| @@ -116,6 +120,10 @@ class JSCodeEntry(CodeEntry):
|
| name = '<anonymous>' + name
|
| return self.type + ': ' + name
|
|
|
| + def IsICEntry(self):
|
| + return self.type in ('CallIC', 'LoadIC', 'StoreIC') or \
|
| + (self.type == 'Builtin' and self.builtin_ic_re.match(self.name))
|
| +
|
|
|
| class CodeRegion(object):
|
|
|
| @@ -159,10 +167,11 @@ class TickProcessor(object):
|
| # Flag indicating whether to ignore unaccounted ticks in the report
|
| self.ignore_unknown = False
|
|
|
| - def ProcessLogfile(self, filename, included_state = None, ignore_unknown = False):
|
| + def ProcessLogfile(self, filename, included_state = None, ignore_unknown = False, separate_ic = False):
|
| self.log_file = filename
|
| self.included_state = included_state
|
| self.ignore_unknown = ignore_unknown
|
| + self.separate_ic = separate_ic
|
|
|
| try:
|
| logfile = open(filename, 'rb')
|
| @@ -172,7 +181,7 @@ class TickProcessor(object):
|
| logreader = csv.reader(logfile)
|
| for row in logreader:
|
| if row[0] == 'tick':
|
| - self.ProcessTick(int(row[1], 16), int(row[2], 16), int(row[3]), row[4:])
|
| + self.ProcessTick(int(row[1], 16), int(row[2], 16), int(row[3]), self.PreprocessStack(row[4:]))
|
| elif row[0] == 'code-creation':
|
| self.ProcessCodeCreation(row[1], int(row[2], 16), int(row[3]), row[4])
|
| elif row[0] == 'code-move':
|
| @@ -261,13 +270,20 @@ class TickProcessor(object):
|
| return self.js_entries.FindGreatestsLessThan(pc).value
|
| return None
|
|
|
| - def ProcessStack(self, stack):
|
| + def PreprocessStack(self, stack):
|
| + # remove all non-addresses (e.g. 'overflow') and convert to int
|
| result = []
|
| for frame in stack:
|
| if frame.startswith('0x'):
|
| - entry = self.FindEntry(int(frame, 16))
|
| - if entry != None:
|
| - result.append(entry.ToString())
|
| + result.append(int(frame, 16))
|
| + return result
|
| +
|
| + def ProcessStack(self, stack):
|
| + result = []
|
| + for frame in stack:
|
| + entry = self.FindEntry(frame)
|
| + if entry != None:
|
| + result.append(entry.ToString())
|
| return result
|
|
|
| def ProcessTick(self, pc, sp, state, stack):
|
| @@ -281,7 +297,15 @@ class TickProcessor(object):
|
| return
|
| if entry.IsSharedLibraryEntry():
|
| self.number_of_library_ticks += 1
|
| - entry.Tick(pc, self.ProcessStack(stack))
|
| + if entry.IsICEntry() and not self.separate_ic:
|
| + if len(stack) > 0:
|
| + caller_pc = stack.pop(0)
|
| + self.total_number_of_ticks -= 1
|
| + self.ProcessTick(caller_pc, sp, state, stack)
|
| + else:
|
| + self.unaccounted_number_of_ticks += 1
|
| + else:
|
| + entry.Tick(pc, self.ProcessStack(stack))
|
|
|
| def PrintResults(self):
|
| print('Statistical profiling result from %s, (%d ticks, %d unaccounted, %d excluded).' %
|
| @@ -372,14 +396,16 @@ class TickProcessor(object):
|
| class CmdLineProcessor(object):
|
|
|
| def __init__(self):
|
| + self.options = ["js", "gc", "compiler", "other", "ignore-unknown", "separate-ic"]
|
| # default values
|
| self.state = None
|
| self.ignore_unknown = False
|
| self.log_file = None
|
| + self.separate_ic = False
|
|
|
| def ProcessArguments(self):
|
| try:
|
| - opts, args = getopt.getopt(sys.argv[1:], "jgco", ["js", "gc", "compiler", "other", "ignore-unknown"])
|
| + opts, args = getopt.getopt(sys.argv[1:], "jgco", self.options)
|
| except getopt.GetoptError:
|
| self.PrintUsageAndExit()
|
| for key, value in opts:
|
| @@ -393,6 +419,8 @@ class CmdLineProcessor(object):
|
| self.state = 3
|
| if key in ("--ignore-unknown"):
|
| self.ignore_unknown = True
|
| + if key in ("--separate-ic"):
|
| + self.separate_ic = True
|
| self.ProcessRequiredArgs(args)
|
|
|
| def ProcessRequiredArgs(self, args):
|
| @@ -402,14 +430,15 @@ class CmdLineProcessor(object):
|
| return
|
|
|
| def PrintUsageAndExit(self):
|
| - print('Usage: %(script_name)s --{js,gc,compiler,other} %(req_opts)s' % {
|
| + print('Usage: %(script_name)s --{%(opts)s} %(req_opts)s' % {
|
| 'script_name': os.path.basename(sys.argv[0]),
|
| + 'opts': string.join(self.options, ','),
|
| 'req_opts': self.GetRequiredArgsNames()
|
| })
|
| sys.exit(2)
|
|
|
| def RunLogfileProcessing(self, tick_processor):
|
| - tick_processor.ProcessLogfile(self.log_file, self.state, self.ignore_unknown)
|
| + tick_processor.ProcessLogfile(self.log_file, self.state, self.ignore_unknown, self.separate_ic)
|
|
|
|
|
| if __name__ == '__main__':
|
|
|