Upstream version 10.38.222.0
[platform/framework/web/crosswalk.git] / src / tools / multi_process_rss.py
1 #!/usr/bin/env python
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
4 # found in the LICENSE file.
5
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.
8 #
9 # Usage:
10 # ./multi-process-rss.py <pid>|<pid>r [...]
11 #
12 # If <pid> has 'r' at the end, all descendants of the process are accounted.
13 #
14 # Example:
15 # ./multi-process-rss.py 12345 23456r
16 #
17 # The command line above counts the RSS of 1) process 12345, 2) process 23456
18 # and 3) all descendant processes of process 23456.
19
20
21 import collections
22 import logging
23 import os
24 import psutil
25 import sys
26
27
28 if sys.platform.startswith('linux'):
29   _TOOLS_PATH = os.path.dirname(os.path.abspath(__file__))
30   _TOOLS_LINUX_PATH = os.path.join(_TOOLS_PATH, 'linux')
31   sys.path.append(_TOOLS_LINUX_PATH)
32   import procfs  # pylint: disable=F0401
33
34
35 class _NullHandler(logging.Handler):
36   def emit(self, record):
37     pass
38
39
40 _LOGGER = logging.getLogger('multi-process-rss')
41 _LOGGER.addHandler(_NullHandler())
42
43
44 def _recursive_get_children(pid):
45   try:
46     children = psutil.Process(pid).get_children()
47   except psutil.error.NoSuchProcess:
48     return []
49   descendant = []
50   for child in children:
51     descendant.append(child.pid)
52     descendant.extend(_recursive_get_children(child.pid))
53   return descendant
54
55
56 def list_pids(argv):
57   pids = []
58   for arg in argv[1:]:
59     try:
60       if arg.endswith('r'):
61         recursive = True
62         pid = int(arg[:-1])
63       else:
64         recursive = False
65         pid = int(arg)
66     except ValueError:
67       raise SyntaxError("%s is not an integer." % arg)
68     else:
69       pids.append(pid)
70     if recursive:
71       children = _recursive_get_children(pid)
72       pids.extend(children)
73
74   pids = sorted(set(pids), key=pids.index)  # uniq: maybe slow, but simple.
75
76   return pids
77
78
79 def count_pageframes(pids):
80   pageframes = collections.defaultdict(int)
81   pagemap_dct = {}
82   for pid in pids:
83     maps = procfs.ProcMaps.load(pid)
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
92
93   for pid, pagemap in pagemap_dct.iteritems():
94     for vma in pagemap.vma_internals.itervalues():
95       for pageframe, number in vma.pageframes.iteritems():
96         pageframes[pageframe] += number
97
98   return pageframes
99
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
118 def main(argv):
119   logging_handler = logging.StreamHandler()
120   logging_handler.setLevel(logging.WARNING)
121   logging_handler.setFormatter(logging.Formatter(
122       '%(asctime)s:%(name)s:%(levelname)s:%(message)s'))
123
124   _LOGGER.setLevel(logging.WARNING)
125   _LOGGER.addHandler(logging_handler)
126
127   if sys.platform.startswith('linux'):
128     logging.getLogger('procfs').setLevel(logging.WARNING)
129     logging.getLogger('procfs').addHandler(logging_handler)
130     pids = list_pids(argv)
131     pageframes = count_pageframes(pids)
132   else:
133     _LOGGER.error('%s is not supported.' % sys.platform)
134     return 1
135
136   # TODO(dmikurube): Classify this total RSS.
137   print len(pageframes) * 4096
138
139   return 0
140
141
142 if __name__ == '__main__':
143   sys.exit(main(sys.argv))