Skip to content

Commit

Permalink
Remove logger, and compare performance.
Browse files Browse the repository at this point in the history
  • Loading branch information
jcguu95 committed Mar 20, 2024
1 parent 87272da commit 02fe154
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 32 deletions.
56 changes: 28 additions & 28 deletions impls/python-compile/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
_consts = {} # TODO Can I make this non-global? It feels a bit leaky. I may have to make COMPILE a closure for this.

def compile_symbol (ast, env, prefix):
logger.debug(f"Compiling AST:\n{ast}\n")
#logger.debug(f"Compiling AST:\n{ast}\n")
assert(types._symbol_Q(ast))
compiled_strings = \
[f"""
Expand All @@ -14,7 +14,7 @@ def _{prefix} ():
# consts = []
def {prefix} (env):
result = env.get("{ast}")
logger.debug(f"result: {{result}}")
#logger.debug(f"result: {{result}}")
return result
return {prefix}
"""]
Expand All @@ -37,7 +37,7 @@ def {prefix} (env):
# The design of this compiler makes sure that _{prefix}_0 will
# have been defined before the following code being executed.
def compile_def (ast, env, prefix):
logger.debug(f"Compiling AST:\n{ast}\n")
#logger.debug(f"Compiling AST:\n{ast}\n")
assert(types._symbol_Q(ast[1]))
compiled_strings = COMPILE(ast[2], env, prefix=f"{prefix}_0")
compiled_strings += \
Expand All @@ -47,14 +47,14 @@ def _{prefix} ():
consts = [_{prefix}_0()]
def {prefix} (env):
result = env.set("{ast[1]}", consts[0](env))
logger.debug(f"result: {{result}}")
#logger.debug(f"result: {{result}}")
return result
return {prefix}
"""]
return compiled_strings

def compile_let (ast, env, prefix):
logger.debug(f"Compiling AST:\n{ast}\n")
#logger.debug(f"Compiling AST:\n{ast}\n")
compiled_strings = []
for i in range(1, len(ast[1]), 2):
compiled_strings += COMPILE(ast[1][i], env, prefix=f"{prefix}_{(i-1)//2}")
Expand Down Expand Up @@ -87,15 +87,15 @@ def {prefix} (env):
compiled_string += \
f"""
result = consts[{(i+2)//2}](let_env)
logger.debug(f"result: {{result}}")
#logger.debug(f"result: {{result}}")
return result
return {prefix}
"""
compiled_strings += [compiled_string]
return compiled_strings

def compile_do (ast, env, prefix):
logger.debug(f"Compiling AST:\n{ast}\n")
#logger.debug(f"Compiling AST:\n{ast}\n")
compiled_strings = []
for i in range(1, len(ast)):
compiled_strings += COMPILE(ast[i], env, prefix=f"{prefix}_{i-1}")
Expand All @@ -120,15 +120,15 @@ def {prefix} (env):"""
compiled_string += \
f"""
result = consts[{i}](env)
logger.debug(f"result: {{result}}")
#logger.debug(f"result: {{result}}")
return result
return {prefix}
"""
compiled_strings += [compiled_string]
return compiled_strings

def compile_if (ast, env, prefix):
logger.debug(f"Compiling AST:\n{ast}\n")
#logger.debug(f"Compiling AST:\n{ast}\n")
cond_compiled_strings = COMPILE(ast[1], env, prefix=f"{prefix}_0")
if_compiled_strings = COMPILE(ast[2], env, prefix=f"{prefix}_1")
else_compiled_strings = COMPILE(ast[3], env, prefix=f"{prefix}_2")
Expand All @@ -147,15 +147,15 @@ def {prefix} (env):
result = consts[1](env)
else:
result = consts[2](env)
logger.debug(f"result: {{result}}")
#logger.debug(f"result: {{result}}")
return result
return {prefix}
"""
compiled_strings = cond_compiled_strings + if_compiled_strings + else_compiled_strings + [compiled_string]
return compiled_strings

def compile_funcall (ast, env, prefix):
logger.debug(f"Compiling AST:\n{ast}\n")
#logger.debug(f"Compiling AST:\n{ast}\n")
compiled_string = \
f"""
# compile_funcall
Expand All @@ -176,7 +176,7 @@ def {prefix} (env):
compiled_string += " )"
compiled_string += \
f"""
logger.debug(f"result: {{result}}")
#logger.debug(f"result: {{result}}")
return result
return {prefix}
"""
Expand All @@ -186,7 +186,7 @@ def {prefix} (env):
return compiled_strings

def compile_literal (ast, env, prefix):
logger.debug(f"Compiling AST:\n{ast}\n")
#logger.debug(f"Compiling AST:\n{ast}\n")
# Using the global varaible _consts feels buggy, but I think
# and hope it isn't. There must be a way to pass this ast
# into the closure that will be generated by the function
Expand All @@ -202,18 +202,18 @@ def _{prefix} ():
]
def {prefix} (env):
result = consts[0]
logger.debug(f"result: {{result}}")
#logger.debug(f"result: {{result}}")
return result
# Once _{prefix} is called, the ast is embedded into the closure {prefix}, so it's time to quickly remove the link to that ast object.
popped = _consts.pop("{prefix}")
logger.debug(f"popped : {{popped}}")
logger.debug(f"_consts: {{_consts}}")
#logger.debug(f"popped : {{popped}}")
#logger.debug(f"_consts: {{_consts}}")
return {prefix}
"""]
return compiled_strings

def compile_fn (ast, env, prefix):
logger.debug(f"Compiling AST:\n{ast}\n")
#logger.debug(f"Compiling AST:\n{ast}\n")
params, body = ast[1], ast[2]
compiled_string = \
f"""
Expand All @@ -225,23 +225,23 @@ def _{prefix} ():
def {prefix} (env):
def {prefix}_fn (*args):
params, body = {params}, "{str(body)}"
logger.debug(f"params: {{params}}")
logger.debug(f" body : {{body}}")
logger.debug(f" args : {{args}}")
#logger.debug(f"params: {{params}}")
#logger.debug(f" body : {{body}}")
#logger.debug(f" args : {{args}}")
local_env = Env(env, params, types.List(args))
result = consts[0](local_env)
logger.debug(f"result: {{result}}")
#logger.debug(f"result: {{result}}")
return result
result = {prefix}_fn
logger.debug(f"result: {{result}}")
#logger.debug(f"result: {{result}}")
return result
return {prefix}
"""
compiled_strings = COMPILE(body, env, prefix=f"{prefix}_0") + [compiled_string]
return compiled_strings

def compile_hashmap (ast, env, prefix):
logger.debug(f"Compiling AST:\n{ast}\n")
#logger.debug(f"Compiling AST:\n{ast}\n")
assert(types._hash_map_Q(ast))
compiled_string = \
f"""
Expand All @@ -263,7 +263,7 @@ def _{prefix} ():
]
def {prefix} (env):
result = types._hash_map({hashmap_literal_string})
logger.debug(f"result: {{result}}")
#logger.debug(f"result: {{result}}")
return result
return {prefix}
"""
Expand Down Expand Up @@ -298,7 +298,7 @@ def {prefix} (env):
if err:
catch_env = Env(env, ["{ast[2][1]}"], [err])
result = consts[1](catch_env)
logger.debug(f"result: {{result}}")
#logger.debug(f"result: {{result}}")
return result
return {prefix}
"""
Expand Down Expand Up @@ -339,15 +339,15 @@ def macroexpand (ast, env):
count, unexpanded_ast = 0, ast
while is_macro_call(ast, env):
count += 1
logger.debug(f"Macro Expansion\n> AST:\n{ast}\n")
#logger.debug(f"Macro Expansion\n> AST:\n{ast}\n")
macro_fn = env.get(ast[0])
ast = macro_fn(*ast[1:])
logger.debug(f"Macro Expansion Finished ({count} fold(s)).\n> New AST:\n{ast}\n> Old AST:\n{unexpanded_ast}\n")
#logger.debug(f"Macro Expansion Finished ({count} fold(s)).\n> New AST:\n{ast}\n> Old AST:\n{unexpanded_ast}\n")
return ast

def COMPILE (ast, env, prefix="blk"):
# env is for macroexpansion
logger.debug(f"Compiling AST:\n{ast}\n")
#logger.debug(f"Compiling AST:\n{ast}\n")
ast = macroexpand(ast, env)
if types._symbol_Q(ast):
compiled_strings = compile_symbol(ast, env, prefix)
Expand Down
30 changes: 26 additions & 4 deletions impls/python-compile/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,40 @@ in `./impls/python/`.
Quickly test them by running:

``` shell
[./mal]$ \
for ((i=2; i<=10; i++)); do
[ $i -eq 10 ] && make "test^python-compile^stepA" || make "test^python-compile^step${i}"
[ $? -ne 0 ] && { echo "Error occurred. Breaking loop."; break; }
done
```

## ~16 Times Faster Than The Interpreted Version

Per the official performance test suite, `python-compile` is near
16 times faster than the interpreted version.

``` shell
[./mal]$ make "perf^python"
----------------------------------------------
Performance test for python:
Running: env STEP=stepA_mal MAL_IMPL=js python_MODE=python ../python/run ../tests/perf1.mal
Elapsed time: 1 msecs
Running: env STEP=stepA_mal MAL_IMPL=js python_MODE=python ../python/run ../tests/perf2.mal
Elapsed time: 4 msecs
Running: env STEP=stepA_mal MAL_IMPL=js python_MODE=python ../python/run ../tests/perf3.mal
iters over 10 seconds: 9311

[./mal]$ make "perf^python-compile"
----------------------------------------------
Performance test for python-compile:
Running: env STEP=stepA_mal MAL_IMPL=js ../python-compile/run ../tests/perf1.mal
Running: env STEP=stepA_mal MAL_IMPL=js ../python-compile/run ../tests/perf2.mal
Running: env STEP=stepA_mal MAL_IMPL=js ../python-compile/run ../tests/perf3.mal
iters over 10 seconds: 148519
```

## TODO

+ **Compile Files and Compare Performance:** Analyze and compare
the performance metrics between the compiled MAL code and the
Python interpreter-based implementation.

+ Document how the design of the compiler.

+ **Clean Up Code and Submit Pull Request:** Review the codebase
Expand Down

0 comments on commit 02fe154

Please sign in to comment.