| Index: tools/stats-viewer.py
|
| diff --git a/tools/stats-viewer.py b/tools/stats-viewer.py
|
| index bd6a8fb913e24e8983ad85664799e722a53bc39f..220124fd8560c545699a58725b3c2ecc46f58b11 100755
|
| --- a/tools/stats-viewer.py
|
| +++ b/tools/stats-viewer.py
|
| @@ -1,3 +1,5 @@
|
| +#!/usr/bin/env python
|
| +#
|
| # Copyright 2008 the V8 project authors. All rights reserved.
|
| # Redistribution and use in source and binary forms, with or without
|
| # modification, are permitted provided that the following conditions are
|
| @@ -49,8 +51,9 @@ UPDATE_INTERVAL_MS = 100
|
| COUNTER_LABELS = {"t": "%i ms.", "c": "%i"}
|
|
|
|
|
| -# The magic number used to check if a file is not a counters file
|
| +# The magic numbers used to check if a file is not a counters file
|
| COUNTERS_FILE_MAGIC_NUMBER = 0xDEADFACE
|
| +CHROME_COUNTERS_FILE_MAGIC_NUMBER = 0x13131313
|
|
|
|
|
| class StatsViewer(object):
|
| @@ -99,10 +102,12 @@ class StatsViewer(object):
|
| fileno = data_file.fileno()
|
| self.shared_mmap = mmap.mmap(fileno, size, access=mmap.ACCESS_READ)
|
| data_access = SharedDataAccess(self.shared_mmap)
|
| - if data_access.IntAt(0) != COUNTERS_FILE_MAGIC_NUMBER:
|
| - print "File %s is not stats data." % self.data_name
|
| - sys.exit(1)
|
| - return CounterCollection(data_access)
|
| + if data_access.IntAt(0) == COUNTERS_FILE_MAGIC_NUMBER:
|
| + return CounterCollection(data_access)
|
| + elif data_access.IntAt(0) == CHROME_COUNTERS_FILE_MAGIC_NUMBER:
|
| + return ChromeCounterCollection(data_access)
|
| + print "File %s is not stats data." % self.data_name
|
| + sys.exit(1)
|
|
|
| def CleanUp(self):
|
| """Cleans up the memory mapped file if necessary."""
|
| @@ -356,6 +361,72 @@ class CounterCollection(object):
|
| return 4 + self.max_name_size
|
|
|
|
|
| +class ChromeCounter(object):
|
| + """A pointer to a single counter withing a binary counters file."""
|
| +
|
| + def __init__(self, data, name_offset, value_offset):
|
| + """Create a new instance.
|
| +
|
| + Args:
|
| + data: the shared data access object containing the counter
|
| + name_offset: the byte offset of the start of this counter's name
|
| + value_offset: the byte offset of the start of this counter's value
|
| + """
|
| + self.data = data
|
| + self.name_offset = name_offset
|
| + self.value_offset = value_offset
|
| +
|
| + def Value(self):
|
| + """Return the integer value of this counter."""
|
| + return self.data.IntAt(self.value_offset)
|
| +
|
| + def Name(self):
|
| + """Return the ascii name of this counter."""
|
| + result = ""
|
| + index = self.name_offset
|
| + current = self.data.ByteAt(index)
|
| + while current:
|
| + result += chr(current)
|
| + index += 1
|
| + current = self.data.ByteAt(index)
|
| + return result
|
| +
|
| +
|
| +class ChromeCounterCollection(object):
|
| + """An overlay over a counters file that provides access to the
|
| + individual counters contained in the file."""
|
| +
|
| + _HEADER_SIZE = 4 * 4
|
| + _NAME_SIZE = 32
|
| +
|
| + def __init__(self, data):
|
| + """Create a new instance.
|
| +
|
| + Args:
|
| + data: the shared data access object
|
| + """
|
| + self.data = data
|
| + self.max_counters = data.IntAt(8)
|
| + self.max_threads = data.IntAt(12)
|
| + self.counter_names_offset = \
|
| + self._HEADER_SIZE + self.max_threads * (self._NAME_SIZE + 2 * 4)
|
| + self.counter_values_offset = \
|
| + self.counter_names_offset + self.max_counters * self._NAME_SIZE
|
| +
|
| + def CountersInUse(self):
|
| + """Return the number of counters in active use."""
|
| + for i in xrange(self.max_counters):
|
| + if self.data.ByteAt(self.counter_names_offset + i * self._NAME_SIZE) == 0:
|
| + return i
|
| + return self.max_counters
|
| +
|
| + def Counter(self, i):
|
| + """Return the i'th counter."""
|
| + return ChromeCounter(self.data,
|
| + self.counter_names_offset + i * self._NAME_SIZE,
|
| + self.counter_values_offset + i * self.max_threads * 4)
|
| +
|
| +
|
| def Main(data_file):
|
| """Run the stats counter.
|
|
|
|
|