Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/env python
      2 #
      3 # Copyright (C) 2013 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 #      http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 
     17 """WebView postprocessor for the go/memdump tool.
     18 
     19 Processes the output of memdump (see go/memdump) aggregating memory usage
     20 information for WebView analysis (both classic and chromium).
     21 
     22 Usage: adb shell /path/to/target/memdump <target-PID> | ./memreport.py > out.csv
     23 """
     24 
     25 
     26 import os
     27 import re
     28 import sys
     29 
     30 from sets import Set
     31 
     32 
     33 _ENTRIES = [
     34     ('Total', '.* r... .*'),
     35     (' Read-only', '.* r--. .*'),
     36     (' Read-write', '.* rw.. .*'),
     37     ('  Read-write (no x)', '.* rw-. .*'),
     38     (' Executable', '.* ..x. .*'),
     39     ('Anonymous total', '.* .... .* .*shared_other=[0-9]+ ($|.*dlmalloc.*)'),
     40     (' Anonymous executable (JIT)', '.* ..x. .* shared_other=[0-9]+ ($|.*dlmalloc.*)'),
     41     (' Anonymous read-write', '.* rw.. .* .*shared_other=[0-9]+ ($|.*dlmalloc.*)'),
     42     ('  Native heap (dlmalloc)', '.* r... .* /.*dlmalloc.*'),
     43     ('File total', '.* .... .* /((?!dev/ashmem/dlmalloc).*)'),
     44     (' File executable', '.* ..x. .* /((?!dev/ashmem/dlmalloc).*)'),
     45     (' File read-write', '.* rw.. .* /((?!dev/ashmem/dlmalloc).*)'),
     46     (' Dalvik', '.* rw.. .* /.*dalvik.*'),
     47     ('  Dalvik heap', '.* rw.. .* /.*dalvik-heap.*'),
     48     (' Ashmem', '.* rw.. .* /dev/ashmem .*'),
     49     (' libwebcore.so total', '.* r... .* /.*libwebcore.so'),
     50     ('  libwebcore.so read-only', '.* r--. .* /.*libwebcore.so'),
     51     ('  libwebcore.so read-write', '.* rw-. .* /.*libwebcore.so'),
     52     ('  libwebcore.so executable', '.* r.x. .* /.*libwebcore.so'),
     53     (' libwebviewchromium.so total', '.* r... .* /.*libwebviewchromium.so'),
     54     ('  libwebviewchromium.so read-only', '.* r--. .* /.*libwebviewchromium.so'),
     55     ('  libwebviewchromium.so read-write', '.* rw-. .* /.*libwebviewchromium.so'),
     56     ('  libwebviewchromium.so executable', '.* r.x. .* /.*libwebviewchromium.so'),
     57     (' Driver mappings', '.* .... .* /dev/\w+$'),
     58     ('  /dev/maliN total', '.* .... .* /dev/mali.*'),
     59     ('OTHER (non file non anon)', '.* .... .*shared_other=[0-9]+ [^/]+'),
     60     (' DMA buffers', '.* .... .*shared_other=[0-9]+ .*dmabuf.*'),
     61     ]
     62 
     63 
     64 def _CollectMemoryStats(memdump, region_filters):
     65   processes = []
     66   mem_usage_for_regions = None
     67   regexps = {}
     68   for region_filter in region_filters:
     69     regexps[region_filter] = re.compile(region_filter)
     70   for line in memdump:
     71     if 'PID=' in line:
     72       mem_usage_for_regions = {}
     73       processes.append(mem_usage_for_regions)
     74       continue
     75     matched_regions = Set([])
     76     for region_filter in region_filters:
     77       if regexps[region_filter].match(line.rstrip('\r\n')):
     78         matched_regions.add(region_filter)
     79         if not region_filter in mem_usage_for_regions:
     80           mem_usage_for_regions[region_filter] = {
     81               'private_unevictable': 0,
     82               'private': 0,
     83               'shared_app': 0.0,
     84               'shared_other_unevictable': 0,
     85               'shared_other': 0,
     86           }
     87     for matched_region in matched_regions:
     88       mem_usage = mem_usage_for_regions[matched_region]
     89       for key in mem_usage:
     90         for token in line.split(' '):
     91           if (key+'=') in token:
     92             field = token.split('=')[1]
     93             if key != 'shared_app':
     94               mem_usage[key] += int(field)
     95             else:  # shared_app=[\d,\d...]
     96               array = eval(field)
     97               for i in xrange(len(array)):
     98                 mem_usage[key] += float(array[i]) / (i + 2)
     99             break
    100   return processes
    101 
    102 
    103 def _ConvertMemoryField(field):
    104   return str(field / (1024))
    105 
    106 
    107 def _DumpCSV(processes_stats):
    108   total_map = {}
    109   i = 0
    110   for process in processes_stats:
    111     i += 1
    112     print ',private,private_unevictable,shared_other,shared_other_unevictable,'
    113     for (k, v) in _ENTRIES:
    114       header_column = k + ',' if 'NOHEADER' not in os.environ else ','
    115       if not v in process:
    116         print header_column + '0,0,0,0,'
    117         continue
    118       if not v in total_map:
    119         total_map[v] = 0
    120       total_map[v] += process[v]['private'] + process[v]['shared_app']
    121       print (
    122           header_column +
    123           _ConvertMemoryField(process[v]['private']) + ',' +
    124           _ConvertMemoryField(process[v]['private_unevictable']) + ',' +
    125           _ConvertMemoryField(process[v]['shared_other']) + ',' +
    126           _ConvertMemoryField(process[v]['shared_other_unevictable']) + ','
    127           )
    128 
    129 
    130 def main(argv):
    131   _DumpCSV(_CollectMemoryStats(sys.stdin, [value for (key, value) in _ENTRIES]))
    132 
    133 
    134 if __name__ == '__main__':
    135   main(sys.argv)
    136