Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / tools / memory_inspector / memory_inspector / frontends / command_line.py
1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """Command line frontend for Memory Inspector"""
6
7 import json
8 import memory_inspector
9 import optparse
10 import os
11 import time
12
13 from memory_inspector import constants
14 from memory_inspector.classification import mmap_classifier
15 from memory_inspector.core import backends
16 from memory_inspector.data import serialization
17
18
19 def main():
20   COMMANDS = ['devices', 'ps', 'stats', 'mmaps', 'classified_mmaps']
21   usage = ('%prog [options] ' + ' | '.join(COMMANDS))
22   parser = optparse.OptionParser(usage=usage)
23   parser.add_option('-b', '--backend', help='Backend name '
24                     '(e.g., Android)', type='string', default='Android')
25   parser.add_option('-s', '--device_id', help='Device '
26                     'id (e.g., Android serial)', type='string')
27   parser.add_option('-p', '--process_id', help='Target process id',
28                     type='int')
29   parser.add_option('-m', '--filter_process_name', help='Process '
30                     'name to match', type='string')
31   parser.add_option('-r', '--mmap_rule',
32                     help='mmap rule', type='string',
33                     default=os.path.join(constants.CLASSIFICATION_RULES_PATH,
34                         'default', 'mmap-android.py'))
35   (options, args) = parser.parse_args()
36
37   memory_inspector.RegisterAllBackends()
38
39   if not args or args[0] not in COMMANDS:
40     parser.print_help()
41     return -1
42
43   if args[0] == 'devices':
44     _ListDevices(options.backend)
45     return 0
46
47   number_of_devices = 0
48   if options.device_id:
49     device_id = options.device_id
50     number_of_devices = 1
51   else:
52     for device in backends.ListDevices():
53       if device.backend.name == options.backend:
54         number_of_devices += 1
55         device_id = device.id
56
57   if number_of_devices == 0:
58     print "No devices connected"
59     return -1
60
61   if number_of_devices > 1:
62     print ('More than 1 device connected. You need to provide'
63         ' --device_id')
64     return -1
65
66   device = backends.GetDevice(options.backend, device_id)
67   if not device:
68     print 'Device', device_id, 'does not exist'
69     return -1
70
71   device.Initialize()
72   if args[0] == 'ps':
73     if not options.filter_process_name:
74       print 'Listing all processes'
75     else:
76       print ('Listing processes matching '
77           + options.filter_process_name.lower())
78     print ''
79     print '%-10s : %-50s : %12s %12s %12s' % (
80         'Process ID', 'Process Name', 'RUN_TIME', 'THREADS',
81         'MEM_RSS_KB')
82     print ''
83     for process in device.ListProcesses():
84       if (not options.filter_process_name or
85           options.filter_process_name.lower() in process.name.lower()):
86         stats = process.GetStats()
87         run_time_min, run_time_sec = divmod(stats.run_time, 60)
88         print '%10s : %-50s : %6s m %2s s %8s %12s' % (
89             process.pid, _Truncate(process.name, 50), run_time_min,
90             run_time_sec, stats.threads, stats.vm_rss)
91     return 0
92
93   if not options.process_id:
94     print 'You need to provide --process_id'
95     return -1
96
97   process = device.GetProcess(options.process_id)
98
99   if not process:
100     print 'Cannot find process [%d] on device %s' % (
101         options.process_id, device.id)
102     return -1
103   elif args[0] == 'stats':
104     _ListProcessStats(process)
105     return 0
106   elif args[0] == 'mmaps':
107     _ListProcessMmaps(process)
108     return 0
109   elif args[0] == 'classified_mmaps':
110     _ListProcessClassifiedMmaps(process, options.mmap_rule)
111     return 0
112
113
114 def _ListDevices(backend_name):
115   print 'Device list:'
116   print ''
117   for device in backends.ListDevices():
118     if device.backend.name == backend_name:
119       print '%-16s : %s' % (device.id, device.name)
120
121
122 def _ListProcessStats(process):
123   """Prints process stats periodically
124   """
125   print 'Stats for process: [%d] %s' % (process.pid, process.name)
126   print '%-10s : %-50s : %12s %12s %13s %12s %14s' % (
127       'Process ID', 'Process Name', 'RUN_TIME', 'THREADS',
128       'CPU_USAGE', 'MEM_RSS_KB', 'PAGE_FAULTS')
129   print ''
130   while True:
131     stats = process.GetStats()
132     run_time_min, run_time_sec = divmod(stats.run_time, 60)
133     print '%10s : %-50s : %6s m %2s s %8s %12s %13s %11s' % (
134         process.pid, _Truncate(process.name, 50), run_time_min, run_time_sec,
135         stats.threads, stats.cpu_usage, stats.vm_rss, stats.page_faults)
136     time.sleep(1)
137
138
139 def _ListProcessMmaps(process):
140   """Prints process memory maps
141   """
142   print 'Memory Maps for process: [%d] %s' % (process.pid, process.name)
143   print '%-10s %-10s %6s %12s %12s %13s %13s %-40s' % (
144       'START', 'END', 'FLAGS', 'PRIV.DIRTY', 'PRIV.CLEAN',
145       'SHARED DIRTY', 'SHARED CLEAN', 'MAPPED_FILE')
146   print '%38s %12s %12s %13s' % ('(kb)', '(kb)', '(kb)', '(kb)')
147   print ''
148   maps = process.DumpMemoryMaps()
149   for entry in maps.entries:
150     print '%-10x %-10x %6s %12s %12s %13s %13s %-40s' % (
151         entry.start, entry.end, entry.prot_flags,
152         entry.priv_dirty_bytes / 1024, entry.priv_clean_bytes / 1024,
153         entry.shared_dirty_bytes / 1024,
154         entry.shared_clean_bytes / 1024, entry.mapped_file)
155
156
157 def _ListProcessClassifiedMmaps(process, mmap_rule):
158   """Prints process classified memory maps
159   """
160   maps = process.DumpMemoryMaps()
161   if not os.path.exists(mmap_rule):
162     print 'File', mmap_rule, 'not found'
163     return
164   with open(mmap_rule) as f:
165     rules = mmap_classifier.LoadRules(f.read())
166   classified_results_tree =  mmap_classifier.Classify(maps, rules)
167   print json.dumps(classified_results_tree, cls=serialization.Encoder)
168
169
170 def _Truncate(name, max_length):
171   if len(name) <= max_length:
172     return name
173   return '%s...' % name[0:(max_length - 3)]