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 |