Skip to content

Commit 09c4474

Browse files
authored
Merge pull request #1282 from tannewt/frozen_debug
Add debug info to the generated frozen_mpy.c
2 parents 554f82f + b4dcbb7 commit 09c4474

File tree

3 files changed

+66
-8
lines changed

3 files changed

+66
-8
lines changed

py/mkenv.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ endif
7272

7373
MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py
7474
MPY_CROSS = $(TOP)/mpy-cross/mpy-cross
75-
MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py
75+
MPY_TOOL = $(PYTHON3) $(TOP)/tools/mpy-tool.py
7676
PREPROCESS_FROZEN_MODULES = PYTHONPATH=$(TOP)/tools/python-semver $(TOP)/tools/preprocess_frozen_modules.py
7777

7878
all:

py/mkrules.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ xargs -n1 "$(abspath $(MPY_CROSS))" $(MPY_CROSS_FLAGS)
130130
# to build frozen_mpy.c from all .mpy files
131131
# You need to define MPY_TOOL_LONGINT_IMPL in mpconfigport.mk
132132
# if the default will not work (mpz is the default).
133-
$(BUILD)/frozen_mpy.c: $(BUILD)/frozen_mpy $(BUILD)/genhdr/qstrdefs.generated.h
133+
$(BUILD)/frozen_mpy.c: $(BUILD)/frozen_mpy $(BUILD)/genhdr/qstrdefs.generated.h $(TOP)/tools/mpy-tool.py
134134
$(STEPECHO) "Creating $@"
135135
$(Q)$(MPY_TOOL) $(MPY_TOOL_LONGINT_IMPL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(shell $(FIND) -L $(BUILD)/frozen_mpy -type f -name '*.mpy') > $@
136136
endif

tools/mpy-tool.py

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ class Config:
7878
MP_BC_LOAD_ATTR = 0x1e
7979
MP_BC_STORE_ATTR = 0x26
8080

81+
# load opcode names
82+
opcode_names = {}
83+
with open("../../py/bc0.h") as f:
84+
for line in f.readlines():
85+
if line.startswith("#define"):
86+
s = line.split(maxsplit=3)
87+
if len(s) < 3:
88+
continue
89+
_, name, value = s[:3]
90+
opcode = int(value.strip("()"), 0)
91+
opcode_names[opcode] = name
92+
8193
def make_opcode_format():
8294
def OC4(a, b, c, d):
8395
return a | (b << 2) | (c << 4) | (d << 6)
@@ -252,35 +264,50 @@ def freeze(self, parent_name):
252264
i += 1
253265
RawCode.escaped_names.add(self.escaped_name)
254266

267+
sizes = {"bytecode": 0, "strings": 0, "raw_code_overhead": 0, "const_table_overhead": 0, "string_overhead": 0, "number_overhead": 0}
255268
# emit children first
256269
for rc in self.raw_codes:
257-
rc.freeze(self.escaped_name + '_')
270+
subsize = rc.freeze(self.escaped_name + '_')
271+
for k in sizes:
272+
sizes[k] += subsize[k]
273+
258274

259275
# generate bytecode data
260276
print()
261277
print('// frozen bytecode for file %s, scope %s%s' % (self.source_file.str, parent_name, self.simple_name.str))
278+
print("// bytecode size", len(self.bytecode))
262279
print('STATIC ', end='')
263280
if not config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE:
264281
print('const ', end='')
265282
print('byte bytecode_data_%s[%u] = {' % (self.escaped_name, len(self.bytecode)))
283+
sizes["bytecode"] += len(self.bytecode)
266284
print(' ', end='')
267285
for i in range(self.ip2):
268286
print(' 0x%02x,' % self.bytecode[i], end='')
269287
print()
288+
print(" // simple name")
270289
print(' ', self.simple_name.qstr_id, '& 0xff,', self.simple_name.qstr_id, '>> 8,')
290+
print(" // source file")
271291
print(' ', self.source_file.qstr_id, '& 0xff,', self.source_file.qstr_id, '>> 8,')
292+
print(" // code info")
272293
print(' ', end='')
273294
for i in range(self.ip2 + 4, self.ip):
274295
print(' 0x%02x,' % self.bytecode[i], end='')
275296
print()
297+
print(" // bytecode")
276298
ip = self.ip
277299
while ip < len(self.bytecode):
278300
f, sz = mp_opcode_format(self.bytecode, ip)
301+
opcode = self.bytecode[ip]
302+
if opcode in opcode_names:
303+
opcode = opcode_names[opcode]
304+
else:
305+
opcode = '0x%02x' % opcode
279306
if f == 1:
280307
qst = self._unpack_qstr(ip + 1).qstr_id
281-
print(' ', '0x%02x,' % self.bytecode[ip], qst, '& 0xff,', qst, '>> 8,')
308+
print(' {}, {} & 0xff, {} >> 8,'.format(opcode, qst, qst))
282309
else:
283-
print(' ', ''.join('0x%02x, ' % self.bytecode[ip + i] for i in range(sz)))
310+
print(' {},{}'.format(opcode, ''.join(' 0x%02x,' % self.bytecode[ip + i] for i in range(1, sz))))
284311
ip += sz
285312
print('};')
286313

@@ -295,9 +322,12 @@ def freeze(self, parent_name):
295322
obj_type = 'mp_type_str'
296323
else:
297324
obj_type = 'mp_type_bytes'
298-
print('STATIC const mp_obj_str_t %s = {{&%s}, %u, %u, (const byte*)"%s"};'
325+
print('STATIC const mp_obj_str_t %s = {{&%s}, %u, %u, (const byte*)"%s"}; // %s'
299326
% (obj_name, obj_type, qstrutil.compute_hash(obj, config.MICROPY_QSTR_BYTES_IN_HASH),
300-
len(obj), ''.join(('\\x%02x' % b) for b in obj)))
327+
len(obj), ''.join(('\\x%02x' % b) for b in obj), obj))
328+
sizes["strings"] += len(obj)
329+
sizes["string_overhead"] += 16
330+
301331
elif is_int_type(obj):
302332
if config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_NONE:
303333
# TODO check if we can actually fit this long-int into a small-int
@@ -321,14 +351,17 @@ def freeze(self, parent_name):
321351
print('STATIC const mp_obj_int_t %s = {{&mp_type_int}, '
322352
'{.neg=%u, .fixed_dig=1, .alloc=%u, .len=%u, .dig=(uint%u_t[]){%s}}};'
323353
% (obj_name, neg, ndigs, ndigs, bits_per_dig, digs))
354+
sizes["number_overhead"] += 16
324355
elif type(obj) is float:
325356
print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B')
326357
print('STATIC const mp_obj_float_t %s = {{&mp_type_float}, %.16g};'
327358
% (obj_name, obj))
328359
print('#endif')
360+
sizes["number_overhead"] += 8
329361
elif type(obj) is complex:
330362
print('STATIC const mp_obj_complex_t %s = {{&mp_type_complex}, %.16g, %.16g};'
331363
% (obj_name, obj.real, obj.imag))
364+
sizes["number_overhead"] += 12
332365
else:
333366
raise FreezeError(self, 'freezing of object %r is not implemented' % (obj,))
334367

@@ -338,8 +371,10 @@ def freeze(self, parent_name):
338371
print('STATIC const mp_rom_obj_t const_table_data_%s[%u] = {'
339372
% (self.escaped_name, const_table_len))
340373
for qst in self.qstrs:
374+
sizes["const_table_overhead"] += 4
341375
print(' MP_ROM_QSTR(%s),' % global_qstrs[qst].qstr_id)
342376
for i in range(len(self.objs)):
377+
sizes["const_table_overhead"] += 4
343378
if type(self.objs[i]) is float:
344379
print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B')
345380
print(' MP_ROM_PTR(&const_obj_%s_%u),' % (self.escaped_name, i))
@@ -353,6 +388,7 @@ def freeze(self, parent_name):
353388
else:
354389
print(' MP_ROM_PTR(&const_obj_%s_%u),' % (self.escaped_name, i))
355390
for rc in self.raw_codes:
391+
sizes["const_table_overhead"] += 4
356392
print(' MP_ROM_PTR(&raw_code_%s),' % rc.escaped_name)
357393
print('};')
358394

@@ -376,6 +412,9 @@ def freeze(self, parent_name):
376412
print(' #endif')
377413
print(' },')
378414
print('};')
415+
sizes["raw_code_overhead"] += 16
416+
417+
return sizes
379418

380419
def read_uint(f):
381420
i = 0
@@ -467,6 +506,7 @@ def freeze_mpy(base_qstrs, raw_codes):
467506
new[q.qstr_esc] = (len(new), q.qstr_esc, q.str)
468507
new = sorted(new.values(), key=lambda x: x[0])
469508

509+
print('#include "py/bc0.h"')
470510
print('#include "py/mpconfig.h"')
471511
print('#include "py/objint.h"')
472512
print('#include "py/objstr.h"')
@@ -523,27 +563,45 @@ def freeze_mpy(base_qstrs, raw_codes):
523563
print(' %u, // allocated entries' % len(new))
524564
print(' %u, // used entries' % len(new))
525565
print(' {')
566+
qstr_size = {"metadata": 0, "data": 0}
526567
for _, _, qstr in new:
568+
qstr_size["metadata"] += config.MICROPY_QSTR_BYTES_IN_LEN + config.MICROPY_QSTR_BYTES_IN_HASH
569+
qstr_size["data"] += len(qstr)
527570
print(' %s,'
528571
% qstrutil.make_bytes(config.MICROPY_QSTR_BYTES_IN_LEN, config.MICROPY_QSTR_BYTES_IN_HASH, qstr))
529572
print(' },')
530573
print('};')
531574

575+
sizes = {}
532576
for rc in raw_codes:
533-
rc.freeze(rc.source_file.str.replace('/', '_')[:-3] + '_')
577+
sizes[rc.source_file.str] = rc.freeze(rc.source_file.str.replace('/', '_')[:-3] + '_')
534578

535579
print()
536580
print('const char mp_frozen_mpy_names[] = {')
581+
qstr_size["filenames"] = 1
537582
for rc in raw_codes:
538583
module_name = rc.source_file.str
539584
print('"%s\\0"' % module_name)
585+
qstr_size["filenames"] += len(module_name) + 1
540586
print('"\\0"};')
541587

542588
print('const mp_raw_code_t *const mp_frozen_mpy_content[] = {')
543589
for rc in raw_codes:
544590
print(' &raw_code_%s,' % rc.escaped_name)
591+
size = sizes[rc.source_file.str]
592+
print(' // Total size:', sum(size.values()))
593+
for k in size:
594+
print(" // {} {}".format(k, size[k]))
545595
print('};')
546596

597+
print()
598+
print('// Total size:', sum([sum(x.values()) for x in sizes.values()]) + sum(qstr_size.values()))
599+
for k in size:
600+
total = sum([x[k] for x in sizes.values()])
601+
print("// {} {}".format(k, total))
602+
for k in qstr_size:
603+
print("// qstr {} {}".format(k, qstr_size[k]))
604+
547605
def main():
548606
import argparse
549607
cmd_parser = argparse.ArgumentParser(description='A tool to work with MicroPython .mpy files.')

0 commit comments

Comments
 (0)