xref: /optee_os/scripts/mem_usage.py (revision 3be7773f363875da601f86934dfa84c2ae249df6)
1#!/usr/bin/env python3
2#
3# Copyright (c) 2014-2017, Linaro Limited
4# All rights reserved.
5#
6# SPDX-License-Identifier: BSD-3-Clause
7
8import argparse
9import os
10import subprocess
11import sys
12
13
14def get_args():
15    parser = argparse.ArgumentParser(description='Shows the memory usage '
16                                     'of an OP-TEE based on ELF sections')
17    parser.add_argument('tee_elf', help='the OP-TEE ELF file (tee.elf)')
18    parser.add_argument('-a', '--all', action='store_true',
19                        help=' same as -i -p -u -U')
20    parser.add_argument('-n', '--no-map', action='store_true',
21                        help=' do not show the detailed section mappings and '
22                        'RAM usage')
23    parser.add_argument('-i', '--init', action='store_true',
24                        help='report the total size of the .*_init sections')
25    parser.add_argument('-p', '--paged', action='store_true',
26                        help='report the total size of the .*_pageable '
27                        'sections')
28    parser.add_argument('-u', '--unpaged', action='store_true',
29                        help='report the total size of the unpaged sections, '
30                        'that is, all sections but the ones in --init or '
31                        '--paged')
32    parser.add_argument('-U', '--unpaged-no-heap', action='store_true',
33                        help='report the size of all unpaged sections '
34                        'excluding heap space. Reflects the size of unpaged '
35                        'code and data (.text, .rodata, .data, .bss, .nozi '
36                        'and possibly unwind tables)')
37    parser.add_argument('-r', '--raw', action='store_true',
38                        help='when processing -i, -p, -u, or -U, show only '
39                        'the size (in decimal) and no other text')
40    return parser.parse_args()
41
42
43def printf(format, *args):
44    sys.stdout.write(format % args)
45
46
47def print_sect(name, addr, size, round_up=False, print_num_pages=False):
48    if args.no_map:
49        return
50    if size == 0:
51        size_kib = 0
52        num_pages = 0
53    else:
54        if round_up:
55            size_kib = (size - 1) / 1024 + 1
56        else:
57            size_kib = size / 1024
58        num_pages = (size - 1) / 4096 + 1
59
60    printf('%-16s %.8X - %.8X size %.8X %3d KiB', name, addr, addr + size,
61           size, size_kib)
62    if print_num_pages:
63        printf(' %d pages', num_pages)
64    printf('\n')
65
66
67def print_pager_stat(name, size):
68    size_kib = size / 1024
69    if args.raw:
70        printf('%d ', size)
71    else:
72        printf('%-36s size %.8X %3d KiB\n', name, size, size_kib)
73
74
75def readelf_cmd():
76    return os.getenv('CROSS_COMPILE', '') + 'readelf'
77
78
79def main():
80    global args
81
82    in_shdr = False
83    sects = []
84    init_size = 0
85    paged_size = 0
86    unpaged_size = 0
87    unpaged_no_heap_size = 0
88
89    args = get_args()
90    env = os.environ.copy()
91    env['LC_ALL'] = 'C'
92    readelf = subprocess.Popen([readelf_cmd(), '-S', '-W', args.tee_elf],
93                               stdout=subprocess.PIPE, env=env,
94                               universal_newlines=True)
95    for line in iter(readelf.stdout.readline, ''):
96        if 'Section Headers:' in line:
97            in_shdr = True
98            continue
99        if 'Key to Flags:' in line:
100            in_shdr = False
101            continue
102        if in_shdr:
103            words = line.split()
104            if words[0] == '[':
105                words.pop(0)
106            try:
107                (_, name, _, addr, offs, size, _,
108                 flags) = words[:8]
109            except:
110                continue
111            if (flags == 'AX' or flags == 'WA' or flags == 'A' or
112                    flags == 'AL'):
113                sects.append({'name': name, 'addr': addr,
114                              'offs': offs, 'size': size})
115    for sect in sects:
116        if sect['addr'] != 0:
117            first_addr = sect['addr']
118            break
119    last_addr = sects[-1]['addr']
120    last_size = sects[-1]['size']
121
122    ram_usage = int(last_addr, 16) + int(last_size, 16) - int(first_addr, 16)
123    print_sect('RAM Usage', int(first_addr, 16), ram_usage, True, True)
124
125    last_addr = 0
126    last_size = 0
127    for sect in sects:
128        name = sect['name']
129        addr = int(sect['addr'], 16)
130        size = int(sect['size'], 16)
131
132        if last_addr != 0 and addr != last_addr + last_size:
133            print_sect('*hole*', last_addr + last_size,
134                       addr - (last_addr + last_size))
135        print_sect(name, addr, size)
136        if name.endswith('_init'):
137            init_size += size
138        elif name.endswith('_pageable'):
139            paged_size += size
140        else:
141            if not name.startswith('.heap'):
142                unpaged_no_heap_size += size
143            unpaged_size += size
144        last_addr = addr
145        last_size = size
146
147    if args.all or args.init:
148        print_pager_stat('Init sections (.*_init)', init_size)
149    if args.all or args.paged:
150        print_pager_stat('Paged sections (.*_pageable)', paged_size)
151    if args.all or args.unpaged:
152        print_pager_stat('Unpaged sections ', unpaged_size)
153    if args.all or args.unpaged_no_heap:
154        print_pager_stat('Unpaged sections (heap excluded)',
155                         unpaged_no_heap_size)
156    if (args.raw and (args.all or args.init or args.paged or
157                      args.unpaged or args.unpaged_no_heap)):
158        printf('\n')
159
160
161if __name__ == "__main__":
162    main()
163