| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # | 2 # |
| 3 # Copyright 2008 the V8 project authors. All rights reserved. | 3 # Copyright 2008 the V8 project authors. All rights reserved. |
| 4 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
| 5 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
| 6 # met: | 6 # met: |
| 7 # | 7 # |
| 8 # * Redistributions of source code must retain the above copyright | 8 # * 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 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 """Mount the binary counters file as a memory-mapped file. If | 97 """Mount the binary counters file as a memory-mapped file. If |
| 98 something goes wrong print an informative message and exit the | 98 something goes wrong print an informative message and exit the |
| 99 program.""" | 99 program.""" |
| 100 if not os.path.exists(self.data_name): | 100 if not os.path.exists(self.data_name): |
| 101 maps_name = "/proc/%s/maps" % self.data_name | 101 maps_name = "/proc/%s/maps" % self.data_name |
| 102 if not os.path.exists(maps_name): | 102 if not os.path.exists(maps_name): |
| 103 print "\"%s\" is neither a counter file nor a PID." % self.data_name | 103 print "\"%s\" is neither a counter file nor a PID." % self.data_name |
| 104 sys.exit(1) | 104 sys.exit(1) |
| 105 maps_file = open(maps_name, "r") | 105 maps_file = open(maps_name, "r") |
| 106 try: | 106 try: |
| 107 m = re.search(r"/dev/shm/\S*", maps_file.read()) | 107 self.data_name = None |
| 108 if m is not None and os.path.exists(m.group(0)): | 108 for m in re.finditer(r"/dev/shm/\S*", maps_file.read()): |
| 109 self.data_name = m.group(0) | 109 if os.path.exists(m.group(0)): |
| 110 else: | 110 self.data_name = m.group(0) |
| 111 break |
| 112 if self.data_name is None: |
| 111 print "Can't find counter file in maps for PID %s." % self.data_name | 113 print "Can't find counter file in maps for PID %s." % self.data_name |
| 112 sys.exit(1) | 114 sys.exit(1) |
| 113 finally: | 115 finally: |
| 114 maps_file.close() | 116 maps_file.close() |
| 115 data_file = open(self.data_name, "r") | 117 data_file = open(self.data_name, "r") |
| 116 size = os.fstat(data_file.fileno()).st_size | 118 size = os.fstat(data_file.fileno()).st_size |
| 117 fileno = data_file.fileno() | 119 fileno = data_file.fileno() |
| 118 self.shared_mmap = mmap.mmap(fileno, size, access=mmap.ACCESS_READ) | 120 self.shared_mmap = mmap.mmap(fileno, size, access=mmap.ACCESS_READ) |
| 119 data_access = SharedDataAccess(self.shared_mmap) | 121 data_access = SharedDataAccess(self.shared_mmap) |
| 120 if data_access.IntAt(0) == COUNTERS_FILE_MAGIC_NUMBER: | 122 if data_access.IntAt(0) == COUNTERS_FILE_MAGIC_NUMBER: |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 407 index += 1 | 409 index += 1 |
| 408 current = self.data.ByteAt(index) | 410 current = self.data.ByteAt(index) |
| 409 return result | 411 return result |
| 410 | 412 |
| 411 | 413 |
| 412 class ChromeCounterCollection(object): | 414 class ChromeCounterCollection(object): |
| 413 """An overlay over a counters file that provides access to the | 415 """An overlay over a counters file that provides access to the |
| 414 individual counters contained in the file.""" | 416 individual counters contained in the file.""" |
| 415 | 417 |
| 416 _HEADER_SIZE = 4 * 4 | 418 _HEADER_SIZE = 4 * 4 |
| 417 _NAME_SIZE = 32 | 419 _COUNTER_NAME_SIZE = 64 |
| 420 _THREAD_NAME_SIZE = 32 |
| 418 | 421 |
| 419 def __init__(self, data): | 422 def __init__(self, data): |
| 420 """Create a new instance. | 423 """Create a new instance. |
| 421 | 424 |
| 422 Args: | 425 Args: |
| 423 data: the shared data access object | 426 data: the shared data access object |
| 424 """ | 427 """ |
| 425 self.data = data | 428 self.data = data |
| 426 self.max_counters = data.IntAt(8) | 429 self.max_counters = data.IntAt(8) |
| 427 self.max_threads = data.IntAt(12) | 430 self.max_threads = data.IntAt(12) |
| 428 self.counter_names_offset = \ | 431 self.counter_names_offset = \ |
| 429 self._HEADER_SIZE + self.max_threads * (self._NAME_SIZE + 2 * 4) | 432 self._HEADER_SIZE + self.max_threads * (self._THREAD_NAME_SIZE + 2 * 4) |
| 430 self.counter_values_offset = \ | 433 self.counter_values_offset = \ |
| 431 self.counter_names_offset + self.max_counters * self._NAME_SIZE | 434 self.counter_names_offset + self.max_counters * self._COUNTER_NAME_SIZE |
| 432 | 435 |
| 433 def CountersInUse(self): | 436 def CountersInUse(self): |
| 434 """Return the number of counters in active use.""" | 437 """Return the number of counters in active use.""" |
| 435 for i in xrange(self.max_counters): | 438 for i in xrange(self.max_counters): |
| 436 if self.data.ByteAt(self.counter_names_offset + i * self._NAME_SIZE) == 0: | 439 name_offset = self.counter_names_offset + i * self._COUNTER_NAME_SIZE |
| 440 if self.data.ByteAt(name_offset) == 0: |
| 437 return i | 441 return i |
| 438 return self.max_counters | 442 return self.max_counters |
| 439 | 443 |
| 440 def Counter(self, i): | 444 def Counter(self, i): |
| 441 """Return the i'th counter.""" | 445 """Return the i'th counter.""" |
| 442 return ChromeCounter(self.data, | 446 name_offset = self.counter_names_offset + i * self._COUNTER_NAME_SIZE |
| 443 self.counter_names_offset + i * self._NAME_SIZE, | 447 value_offset = self.counter_values_offset + i * self.max_threads * 4 |
| 444 self.counter_values_offset + i * self.max_threads * 4) | 448 return ChromeCounter(self.data, name_offset, value_offset) |
| 445 | 449 |
| 446 | 450 |
| 447 def Main(data_file, name_filter): | 451 def Main(data_file, name_filter): |
| 448 """Run the stats counter. | 452 """Run the stats counter. |
| 449 | 453 |
| 450 Args: | 454 Args: |
| 451 data_file: The counters file to monitor. | 455 data_file: The counters file to monitor. |
| 452 name_filter: The regexp filter to apply to counter names. | 456 name_filter: The regexp filter to apply to counter names. |
| 453 """ | 457 """ |
| 454 StatsViewer(data_file, name_filter).Run() | 458 StatsViewer(data_file, name_filter).Run() |
| 455 | 459 |
| 456 | 460 |
| 457 if __name__ == "__main__": | 461 if __name__ == "__main__": |
| 458 parser = optparse.OptionParser("usage: %prog [--filter=re] " | 462 parser = optparse.OptionParser("usage: %prog [--filter=re] " |
| 459 "<stats data>|<test_shell pid>") | 463 "<stats data>|<test_shell pid>") |
| 460 parser.add_option("--filter", | 464 parser.add_option("--filter", |
| 461 default=".*", | 465 default=".*", |
| 462 help=("regexp filter for counter names " | 466 help=("regexp filter for counter names " |
| 463 "[default: %default]")) | 467 "[default: %default]")) |
| 464 (options, args) = parser.parse_args() | 468 (options, args) = parser.parse_args() |
| 465 if len(args) != 1: | 469 if len(args) != 1: |
| 466 parser.print_help() | 470 parser.print_help() |
| 467 sys.exit(1) | 471 sys.exit(1) |
| 468 Main(args[0], re.compile(options.filter)) | 472 Main(args[0], re.compile(options.filter)) |
| OLD | NEW |