diff options
-rw-r--r-- | py/emitglue.c | 6 | ||||
-rw-r--r-- | py/misc.h | 2 | ||||
-rw-r--r-- | py/mpconfig.h | 33 | ||||
-rw-r--r-- | py/parse.c | 12 | ||||
-rwxr-xr-x | py/py-version.sh | 3 | ||||
-rw-r--r-- | py/scope.c | 6 | ||||
-rw-r--r-- | py/showbc.c | 2 | ||||
-rw-r--r-- | tests/bench/bench.py | 10 | ||||
-rw-r--r-- | tests/bench/loop_count-1-range.py | 7 | ||||
-rw-r--r-- | tests/bench/loop_count-2-range_iter.py | 7 | ||||
-rw-r--r-- | tests/bench/loop_count-3-while_up.py | 8 | ||||
-rw-r--r-- | tests/bench/loop_count-4-while_down_gt.py | 7 | ||||
-rw-r--r-- | tests/bench/loop_count-5-while_down_ne.py | 7 | ||||
-rw-r--r-- | tests/bench/var-1-constant.py | 8 | ||||
-rw-r--r-- | tests/bench/var-2-global.py | 10 | ||||
-rw-r--r-- | tests/bench/var-3-local.py | 10 | ||||
-rw-r--r-- | tests/bench/var-4-arg.py | 9 | ||||
-rw-r--r-- | tests/bench/var-5-class-attr.py | 11 | ||||
-rw-r--r-- | tests/bench/var-6-instance-attr.py | 14 | ||||
-rw-r--r-- | tests/bench/var-7-instance-meth.py | 17 | ||||
-rwxr-xr-x | tests/run-bench-tests | 97 | ||||
-rw-r--r-- | unix/main.c | 7 |
22 files changed, 279 insertions, 14 deletions
diff --git a/py/emitglue.c b/py/emitglue.c index 231e32ac2..ed3b385d9 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -96,9 +96,11 @@ void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, uint DEBUG_printf(" %02x", code[i]); } DEBUG_printf("\n"); -#if MICROPY_DEBUG_PRINTERS - mp_byte_code_print(code, len); #endif +#if MICROPY_DEBUG_PRINTERS + if (mp_verbose_flag > 0) { + mp_byte_code_print(code, len); + } #endif } @@ -156,4 +156,6 @@ void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap); // Debugging helpers int DEBUG_printf(const char *fmt, ...); +extern uint mp_verbose_flag; + #endif // _INCLUDED_MINILIB_H diff --git a/py/mpconfig.h b/py/mpconfig.h index 78147609c..435140dc7 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -34,6 +34,39 @@ // values below. /*****************************************************************************/ +/* Memory allocation policy */ + +// Initial amount for parse rule stack +#ifndef MP_ALLOC_PARSE_RULE_INIT +#define MP_ALLOC_PARSE_RULE_INIT (64) +#endif + +// Increment for parse rule stack +#ifndef MP_ALLOC_PARSE_RULE_INC +#define MP_ALLOC_PARSE_RULE_INC (16) +#endif + +// Initial amount for parse result stack +#ifndef MP_ALLOC_PARSE_RESULT_INIT +#define MP_ALLOC_PARSE_RESULT_INIT (32) +#endif + +// Increment for parse result stack +#ifndef MP_ALLOC_PARSE_RESULT_INC +#define MP_ALLOC_PARSE_RESULT_INC (16) +#endif + +// Initial amount for ids in a scope +#ifndef MP_ALLOC_SCOPE_ID_INIT +#define MP_ALLOC_SCOPE_ID_INIT (4) +#endif + +// Increment for ids in a scope +#ifndef MP_ALLOC_SCOPE_ID_INC +#define MP_ALLOC_SCOPE_ID_INC (6) +#endif + +/*****************************************************************************/ /* Micro Python emitters */ // Whether to emit CPython byte codes (for debugging/testing) diff --git a/py/parse.c b/py/parse.c index 13b137fb3..f512eea3b 100644 --- a/py/parse.c +++ b/py/parse.c @@ -134,13 +134,13 @@ STATIC void push_rule(parser_t *parser, int src_line, const rule_t *rule, int ar return; } if (parser->rule_stack_top >= parser->rule_stack_alloc) { - rule_stack_t *rs = m_renew_maybe(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc * 2); + rule_stack_t *rs = m_renew_maybe(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MP_ALLOC_PARSE_RULE_INC); if (rs == NULL) { memory_error(parser); return; } parser->rule_stack = rs; - parser->rule_stack_alloc *= 2; + parser->rule_stack_alloc += MP_ALLOC_PARSE_RULE_INC; } rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++]; rs->src_line = src_line; @@ -263,13 +263,13 @@ STATIC void push_result_node(parser_t *parser, mp_parse_node_t pn) { return; } if (parser->result_stack_top >= parser->result_stack_alloc) { - mp_parse_node_t *pn = m_renew_maybe(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc * 2); + mp_parse_node_t *pn = m_renew_maybe(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc + MP_ALLOC_PARSE_RESULT_INC); if (pn == NULL) { memory_error(parser); return; } parser->result_stack = pn; - parser->result_stack_alloc *= 2; + parser->result_stack_alloc += MP_ALLOC_PARSE_RESULT_INC; } parser->result_stack[parser->result_stack_top++] = pn; } @@ -350,11 +350,11 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p parser->had_memory_error = false; - parser->rule_stack_alloc = 64; + parser->rule_stack_alloc = MP_ALLOC_PARSE_RULE_INIT; parser->rule_stack_top = 0; parser->rule_stack = m_new(rule_stack_t, parser->rule_stack_alloc); - parser->result_stack_alloc = 64; + parser->result_stack_alloc = MP_ALLOC_PARSE_RESULT_INIT; parser->result_stack_top = 0; parser->result_stack = m_new(mp_parse_node_t, parser->result_stack_alloc); diff --git a/py/py-version.sh b/py/py-version.sh index 42474ef6a..daa25489e 100755 --- a/py/py-version.sh +++ b/py/py-version.sh @@ -1,6 +1,7 @@ #!/bin/bash -git_tag="$(git describe --dirty || echo unknown)" +# Note: git describe doesn't work if no tag is available +git_tag="$(git describe --dirty 2> /dev/null || git rev-parse --short HEAD)" git_hash="$(git rev-parse --short HEAD 2> /dev/null || echo unknown)" git_files_are_clean=1 # Check if there are any modified files. diff --git a/py/scope.c b/py/scope.c index 8d3f7bada..ab29af78a 100644 --- a/py/scope.c +++ b/py/scope.c @@ -71,7 +71,7 @@ scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, uint } scope->raw_code = mp_emit_glue_new_raw_code(); scope->emit_options = emit_options; - scope->id_info_alloc = 8; + scope->id_info_alloc = MP_ALLOC_SCOPE_ID_INIT; scope->id_info = m_new(id_info_t, scope->id_info_alloc); return scope; @@ -92,8 +92,8 @@ id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, bool *added) { // make sure we have enough memory if (scope->id_info_len >= scope->id_info_alloc) { - scope->id_info = m_renew(id_info_t, scope->id_info, scope->id_info_alloc, scope->id_info_alloc * 2); - scope->id_info_alloc *= 2; + scope->id_info = m_renew(id_info_t, scope->id_info, scope->id_info_alloc, scope->id_info_alloc + MP_ALLOC_SCOPE_ID_INC); + scope->id_info_alloc += MP_ALLOC_SCOPE_ID_INC; } // add new id to end of array of all ids; this seems to match CPython diff --git a/py/showbc.c b/py/showbc.c index ccb703f26..d8ab4be07 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -89,7 +89,7 @@ void mp_byte_code_print(const byte *ip, int len) { { qstr source_file = code_info[4] | (code_info[5] << 8) | (code_info[6] << 16) | (code_info[7] << 24); qstr block_name = code_info[8] | (code_info[9] << 8) | (code_info[10] << 16) | (code_info[11] << 24); - printf("File %s, block %s\n", qstr_str(source_file), qstr_str(block_name)); + printf("File %s, block '%s'\n", qstr_str(source_file), qstr_str(block_name)); machine_int_t bc = (code_info + code_info_size) - ip; machine_uint_t source_line = 1; printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); diff --git a/tests/bench/bench.py b/tests/bench/bench.py new file mode 100644 index 000000000..0cd40a93f --- /dev/null +++ b/tests/bench/bench.py @@ -0,0 +1,10 @@ +import time + + +ITERS = 20000000 + +def run(f): + t = time.time() + f(ITERS) + t = time.time() - t + print(t) diff --git a/tests/bench/loop_count-1-range.py b/tests/bench/loop_count-1-range.py new file mode 100644 index 000000000..e22adf6cb --- /dev/null +++ b/tests/bench/loop_count-1-range.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + for i in range(num): + pass + +bench.run(test) diff --git a/tests/bench/loop_count-2-range_iter.py b/tests/bench/loop_count-2-range_iter.py new file mode 100644 index 000000000..fe4a3857e --- /dev/null +++ b/tests/bench/loop_count-2-range_iter.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + for i in iter(range(num)): + pass + +bench.run(test) diff --git a/tests/bench/loop_count-3-while_up.py b/tests/bench/loop_count-3-while_up.py new file mode 100644 index 000000000..1ab8054a0 --- /dev/null +++ b/tests/bench/loop_count-3-while_up.py @@ -0,0 +1,8 @@ +import bench + +def test(num): + i = 0 + while i < num: + i += 1 + +bench.run(test) diff --git a/tests/bench/loop_count-4-while_down_gt.py b/tests/bench/loop_count-4-while_down_gt.py new file mode 100644 index 000000000..de8dee2ca --- /dev/null +++ b/tests/bench/loop_count-4-while_down_gt.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + while num > 0: + num -= 1 + +bench.run(test) diff --git a/tests/bench/loop_count-5-while_down_ne.py b/tests/bench/loop_count-5-while_down_ne.py new file mode 100644 index 000000000..b9a1af414 --- /dev/null +++ b/tests/bench/loop_count-5-while_down_ne.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + while num != 0: + num -= 1 + +bench.run(test) diff --git a/tests/bench/var-1-constant.py b/tests/bench/var-1-constant.py new file mode 100644 index 000000000..eec977909 --- /dev/null +++ b/tests/bench/var-1-constant.py @@ -0,0 +1,8 @@ +import bench + +def test(num): + i = 0 + while i < 20000000: + i += 1 + +bench.run(test) diff --git a/tests/bench/var-2-global.py b/tests/bench/var-2-global.py new file mode 100644 index 000000000..5758ad61a --- /dev/null +++ b/tests/bench/var-2-global.py @@ -0,0 +1,10 @@ +import bench + +ITERS = 20000000 + +def test(num): + i = 0 + while i < ITERS: + i += 1 + +bench.run(test) diff --git a/tests/bench/var-3-local.py b/tests/bench/var-3-local.py new file mode 100644 index 000000000..124b48429 --- /dev/null +++ b/tests/bench/var-3-local.py @@ -0,0 +1,10 @@ +import bench + + +def test(num): + ITERS = 20000000 + i = 0 + while i < ITERS: + i += 1 + +bench.run(test) diff --git a/tests/bench/var-4-arg.py b/tests/bench/var-4-arg.py new file mode 100644 index 000000000..cf050c58f --- /dev/null +++ b/tests/bench/var-4-arg.py @@ -0,0 +1,9 @@ +import bench + + +def test(num): + i = 0 + while i < num: + i += 1 + +bench.run(lambda n:test(20000000)) diff --git a/tests/bench/var-5-class-attr.py b/tests/bench/var-5-class-attr.py new file mode 100644 index 000000000..02ae874ac --- /dev/null +++ b/tests/bench/var-5-class-attr.py @@ -0,0 +1,11 @@ +import bench + +class Foo: + num = 20000000 + +def test(num): + i = 0 + while i < Foo.num: + i += 1 + +bench.run(test) diff --git a/tests/bench/var-6-instance-attr.py b/tests/bench/var-6-instance-attr.py new file mode 100644 index 000000000..787ed870f --- /dev/null +++ b/tests/bench/var-6-instance-attr.py @@ -0,0 +1,14 @@ +import bench + +class Foo: + + def __init__(self): + self.num = 20000000 + +def test(num): + o = Foo() + i = 0 + while i < o.num: + i += 1 + +bench.run(test) diff --git a/tests/bench/var-7-instance-meth.py b/tests/bench/var-7-instance-meth.py new file mode 100644 index 000000000..f9d463f40 --- /dev/null +++ b/tests/bench/var-7-instance-meth.py @@ -0,0 +1,17 @@ +import bench + +class Foo: + + def __init__(self): + self._num = 20000000 + + def num(self): + return self._num + +def test(num): + o = Foo() + i = 0 + while i < o.num(): + i += 1 + +bench.run(test) diff --git a/tests/run-bench-tests b/tests/run-bench-tests new file mode 100755 index 000000000..59074bb87 --- /dev/null +++ b/tests/run-bench-tests @@ -0,0 +1,97 @@ +#! /usr/bin/env python3 + +import os +import subprocess +import sys +import argparse +import re +from glob import glob +from collections import defaultdict + +# Tests require at least CPython 3.3. If your default python3 executable +# is of lower version, you can point MICROPY_CPYTHON3 environment var +# to the correct executable. +if os.name == 'nt': + CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3.exe') + MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../windows/micropython.exe') +else: + CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3') + MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../unix/micropython') + +def run_tests(pyb, test_dict): + test_count = 0 + testcase_count = 0 + + for base_test, tests in test_dict.items(): + print(base_test + ":") + for test_file in tests: + + # run Micro Python + if pyb is None: + # run on PC + try: + output_mupy = subprocess.check_output([MICROPYTHON, '-X', 'emit=bytecode', test_file[0]]) + except subprocess.CalledProcessError: + output_mupy = b'CRASH' + else: + # run on pyboard + pyb.enter_raw_repl() + try: + output_mupy = pyb.execfile(test_file).replace(b'\r\n', b'\n') + except pyboard.PyboardError: + output_mupy = b'CRASH' + + output_mupy = float(output_mupy.strip()) + test_file[1] = output_mupy + testcase_count += 1 + + test_count += 1 + baseline = None + for t in tests: + if baseline is None: + baseline = t[1] + print(" %.3fs (%+06.2f%%) %s" % (t[1], (t[1] * 100 / baseline) - 100, t[0])) + + print("{} tests performed ({} individual testcases)".format(test_count, testcase_count)) + + # all tests succeeded + return True + +def main(): + cmd_parser = argparse.ArgumentParser(description='Run tests for Micro Python.') + cmd_parser.add_argument('--pyboard', action='store_true', help='run the tests on the pyboard') + cmd_parser.add_argument('files', nargs='*', help='input test files') + args = cmd_parser.parse_args() + + # Note pyboard support is copied over from run-tests, not testes, and likely needs revamping + if args.pyboard: + import pyboard + pyb = pyboard.Pyboard('/dev/ttyACM0') + pyb.enter_raw_repl() + else: + pyb = None + + if len(args.files) == 0: + if pyb is None: + # run PC tests + test_dirs = ('bench',) + else: + # run pyboard tests + test_dirs = ('basics', 'float', 'pyb') + tests = sorted(test_file for test_files in (glob('{}/*.py'.format(dir)) for dir in test_dirs) for test_file in test_files) + else: + # tests explicitly given + tests = sorted(args.files) + + test_dict = defaultdict(lambda: []) + for t in tests: + m = re.match(r"(.+?)-(.+)\.py", t) + if not m: + continue + test_dict[m.group(1)].append([t, None]) + + if not run_tests(pyb, test_dict): + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/unix/main.c b/unix/main.c index d66a68d78..a7e4a907e 100644 --- a/unix/main.c +++ b/unix/main.c @@ -58,6 +58,7 @@ // Command line options, with their defaults bool compile_only = false; uint emit_opt = MP_EMIT_OPT_NONE; +uint mp_verbose_flag; #if MICROPY_ENABLE_GC // Heap size of GC heap (if enabled) @@ -205,7 +206,9 @@ STATIC void do_str(const char *str) { int usage(char **argv) { printf( -"usage: %s [-X <opt>] [-c <command>] [<filename>]\n" +"usage: %s [<opts>] [-X <implopt>] [-c <command>] [<filename>]\n" +"Options:\n" +"-v : verbose (trace various operations); can be multiple\n" "\n" "Implementation specific options:\n", argv[0] ); @@ -371,6 +374,8 @@ int main(int argc, char **argv) { a += 1; } else if (strcmp(argv[a], "-X") == 0) { a += 1; + } else if (strcmp(argv[a], "-v") == 0) { + mp_verbose_flag++; } else { return usage(argv); } |