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 |