| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 # Counts a resident set size (RSS) of multiple processes without double-counts. | 6 # Counts a resident set size (RSS) of multiple processes without double-counts. |
| 7 # If they share the same page frame, the page frame is counted only once. | 7 # If they share the same page frame, the page frame is counted only once. |
| 8 # | 8 # |
| 9 # Usage: | 9 # Usage: |
| 10 # ./multi-process-rss.py <pid>|<pid>r [...] | 10 # ./multi-process-rss.py <pid>|<pid>r [...] |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 class _NullHandler(logging.Handler): | 35 class _NullHandler(logging.Handler): |
| 36 def emit(self, record): | 36 def emit(self, record): |
| 37 pass | 37 pass |
| 38 | 38 |
| 39 | 39 |
| 40 _LOGGER = logging.getLogger('multi-process-rss') | 40 _LOGGER = logging.getLogger('multi-process-rss') |
| 41 _LOGGER.addHandler(_NullHandler()) | 41 _LOGGER.addHandler(_NullHandler()) |
| 42 | 42 |
| 43 | 43 |
| 44 def _recursive_get_children(pid): | 44 def _recursive_get_children(pid): |
| 45 children = psutil.Process(pid).get_children() | 45 try: |
| 46 children = psutil.Process(pid).get_children() |
| 47 except psutil.error.NoSuchProcess: |
| 48 return [] |
| 46 descendant = [] | 49 descendant = [] |
| 47 for child in children: | 50 for child in children: |
| 48 descendant.append(child.pid) | 51 descendant.append(child.pid) |
| 49 descendant.extend(_recursive_get_children(child.pid)) | 52 descendant.extend(_recursive_get_children(child.pid)) |
| 50 return descendant | 53 return descendant |
| 51 | 54 |
| 52 | 55 |
| 53 def list_pids(argv): | 56 def list_pids(argv): |
| 54 pids = [] | 57 pids = [] |
| 55 for arg in argv[1:]: | 58 for arg in argv[1:]: |
| (...skipping 15 matching lines...) Expand all Loading... |
| 71 pids = sorted(set(pids), key=pids.index) # uniq: maybe slow, but simple. | 74 pids = sorted(set(pids), key=pids.index) # uniq: maybe slow, but simple. |
| 72 | 75 |
| 73 return pids | 76 return pids |
| 74 | 77 |
| 75 | 78 |
| 76 def count_pageframes(pids): | 79 def count_pageframes(pids): |
| 77 pageframes = collections.defaultdict(int) | 80 pageframes = collections.defaultdict(int) |
| 78 pagemap_dct = {} | 81 pagemap_dct = {} |
| 79 for pid in pids: | 82 for pid in pids: |
| 80 maps = procfs.ProcMaps.load(pid) | 83 maps = procfs.ProcMaps.load(pid) |
| 81 pagemap_dct[pid] = procfs.ProcPagemap.load(pid, maps) | 84 if not maps: |
| 85 _LOGGER.warning('/proc/%d/maps not found.' % pid) |
| 86 continue |
| 87 pagemap = procfs.ProcPagemap.load(pid, maps) |
| 88 if not pagemap: |
| 89 _LOGGER.warning('/proc/%d/pagemap not found.' % pid) |
| 90 continue |
| 91 pagemap_dct[pid] = pagemap |
| 82 | 92 |
| 83 for pid, pagemap in pagemap_dct.iteritems(): | 93 for pid, pagemap in pagemap_dct.iteritems(): |
| 84 for vma in pagemap.vma_internals.itervalues(): | 94 for vma in pagemap.vma_internals.itervalues(): |
| 85 for pageframe, number in vma.pageframes.iteritems(): | 95 for pageframe, number in vma.pageframes.iteritems(): |
| 86 pageframes[pageframe] += number | 96 pageframes[pageframe] += number |
| 87 | 97 |
| 88 return pageframes | 98 return pageframes |
| 89 | 99 |
| 90 | 100 |
| 101 def count_statm(pids): |
| 102 resident = 0 |
| 103 shared = 0 |
| 104 private = 0 |
| 105 |
| 106 for pid in pids: |
| 107 statm = procfs.ProcStatm.load(pid) |
| 108 if not statm: |
| 109 _LOGGER.warning('/proc/%d/statm not found.' % pid) |
| 110 continue |
| 111 resident += statm.resident |
| 112 shared += statm.share |
| 113 private += (statm.resident - statm.share) |
| 114 |
| 115 return (resident, shared, private) |
| 116 |
| 117 |
| 91 def main(argv): | 118 def main(argv): |
| 92 logging_handler = logging.StreamHandler() | 119 logging_handler = logging.StreamHandler() |
| 93 logging_handler.setLevel(logging.WARNING) | 120 logging_handler.setLevel(logging.WARNING) |
| 94 logging_handler.setFormatter(logging.Formatter( | 121 logging_handler.setFormatter(logging.Formatter( |
| 95 '%(asctime)s:%(name)s:%(levelname)s:%(message)s')) | 122 '%(asctime)s:%(name)s:%(levelname)s:%(message)s')) |
| 96 | 123 |
| 97 _LOGGER.setLevel(logging.WARNING) | 124 _LOGGER.setLevel(logging.WARNING) |
| 98 _LOGGER.addHandler(logging_handler) | 125 _LOGGER.addHandler(logging_handler) |
| 99 | 126 |
| 100 if sys.platform.startswith('linux'): | 127 if sys.platform.startswith('linux'): |
| 101 logging.getLogger('procfs').setLevel(logging.WARNING) | 128 logging.getLogger('procfs').setLevel(logging.WARNING) |
| 102 logging.getLogger('procfs').addHandler(logging_handler) | 129 logging.getLogger('procfs').addHandler(logging_handler) |
| 103 pids = list_pids(argv) | 130 pids = list_pids(argv) |
| 104 pageframes = count_pageframes(pids) | 131 pageframes = count_pageframes(pids) |
| 105 else: | 132 else: |
| 106 _LOGGER.error('%s is not supported.' % sys.platform) | 133 _LOGGER.error('%s is not supported.' % sys.platform) |
| 107 return 1 | 134 return 1 |
| 108 | 135 |
| 109 # TODO(dmikurube): Classify this total RSS. | 136 # TODO(dmikurube): Classify this total RSS. |
| 110 print len(pageframes) * 4096 | 137 print len(pageframes) * 4096 |
| 111 | 138 |
| 112 return 0 | 139 return 0 |
| 113 | 140 |
| 114 | 141 |
| 115 if __name__ == '__main__': | 142 if __name__ == '__main__': |
| 116 sys.exit(main(sys.argv)) | 143 sys.exit(main(sys.argv)) |
| OLD | NEW |