Commit 1e44fb23 authored by Pierre Augier's avatar Pierre Augier
Browse files

Fix ipynb test + more backend choice

parent d30a649b9a00
......@@ -3,10 +3,10 @@ clean:
rm -rf __cython__ __numba__ __pythran__ __python__
all:
TRANSONIC_BACKEND="pythran" transonic -np *.py
TRANSONIC_BACKEND="python" transonic -np *.py
TRANSONIC_BACKEND="cython" transonic -np *.py
TRANSONIC_BACKEND="numba" transonic -np *.py
transonic -b pythran -nc *.py
transonic -b python -nc *.py
transonic -b cython -nc *.py
transonic -b numba -nc *.py
meld_pythran:
meld __pythran__ saved__backend__/pythran
......
%% Cell type:code id: tags:
``` python
# Note that this has no effect on coverage :-(
from pathlib import Path
from time import sleep
from transonic.justintime import path_jit, modules, make_hex
from transonic.backends import backends
from transonic.config import backend_default
from transonic.justintime import modules, make_hex
from transonic.util import can_import_accelerator
from transonic import jit, Type
backend = backends[backend_default]
path_jit = backend.jit.path_base
compiler_importable = can_import_accelerator()
src = """T = Type(float, str)
@jit
def test(a: T):
return "hello", a"""
hex_src = make_hex(src)
module_name = "__ipython__" + hex_src
path_dir = path_jit / module_name
paths = path_dir.glob("*")
for path in paths:
path.unlink()
hex_src
T = Type(float, str)
@jit
def test(a: T):
return "hello", a
if compiler_importable:
key, mod = list(modules.items())[0]
cjit = mod.jit_functions["test"]
cjit.compiling
test(1.)
if compiler_importable:
cjit.compiling
# if pythran:
# assert key == module_name, (key, module_name)
if compiler_importable:
for _ in range(100):
test(1.)
sleep(0.1)
if not cjit.compiling:
break
if compiler_importable:
cjit.compiling
test(1.)
test("world")
```
%%%% Output: stream
INFO  Schedule pythranization of file /home/pierre/.transonic/pythran/__jit__/__ipython__0ab66fcdc148f8e4aa8857fd83de3374/test.py
INFO  Schedule pythranization of file /home/pierre/.transonic/pythran/__jit__/__ipython__889772ca85990a579df84a832376093a/test.py
%%%% Output: stream
compile extension
%%%% Output: execute_result
('hello', 'world')
......
......@@ -23,7 +23,7 @@ Function calls
Boosted functions support function calls, including imported functions from
a Python file in the same directory!
.. literalinclude:: classic_include.py
.. literalinclude:: classic_func_using_func.py
Note that no Pythran signatures or annotations are needed for functions called
in boosted functions.
import numpy as np
from transonic import jit, boost
from mod1 import func_import
@boost
class MyClass2:
def __init__(self):
self.attr0 = self.attr1 = 1
@jit()
def myfunc(self, arg):
return self.attr1 + self.attr0 + np.abs(arg) + func_import()
def check(self):
assert self.myfunc(1) == 4
import numpy as np
const = 1
def func_import():
return const + np.pi - np.pi
all:
TRANSONIC_BACKEND="pythran" transonic add.py
TRANSONIC_BACKEND="numba" transonic add.py
TRANSONIC_BACKEND="cython" transonic add.py
transonic -b pythran add.py
transonic -b numba add.py
transonic -b cython add.py
bench:
TRANSONIC_NO_REPLACE=1 python add.py
......
......@@ -28,7 +28,7 @@ With Transonic, one can easily use Pythran for methods:
Function calls in methods are supported!
.. literalinclude:: methods_with_include.py
.. literalinclude:: methods_using_function.py
We can also use the :code:`jit` decorator for methods!
......
import numpy as np
from transonic import boost
def mylog(arr):
return np.log(arr)
# transonic def func(float[][], float[][])
# transonic def func(int[][], float[][])
@boost
def func(a, b):
return (a * mylog(b)).max()
"""
Not yet implemented...
Many things can be expressed in Pythran specifications (see
https://pythran.readthedocs.io/en/latest/MANUAL.html#concerning-pythran-specifications),
in particular stride arrays and partial shapes...
We could also express these concepts in strings, mainly following Pythran...
"""
from transonic import boost, Type, NDim, Shape, Array
T = Type(int, float)
# here the shape of the array is only defined with the ShapeVar
A = Array[T, Shape("[3, :]", "[3, :, :]", "[::, ::]", "[::, ::, ::]")]
@boost
def compute(a: A, b: A, c: T):
return a + b
# if there is a NDimVar, we can use the ellipsis
A1 = Array[T, NDim(1, 3), Shape("[3, ...]", "[::, ...]")]
@boost
def compute1(a: A1, b: A1, c: T):
return c * (a + b)
......@@ -5,14 +5,14 @@ NAMEJIT=row_sum_jit.py
all: pythran cython other
pythran:
TRANSONIC_BACKEND="pythran" transonic $(NAME) -pf "-march=native -DUSE_XSIMD"
transonic $(NAME) -b pythran -pf "-march=native -DUSE_XSIMD"
cython:
TRANSONIC_BACKEND="cython" transonic $(NAME)
transonic $(NAME) -b cython
other:
TRANSONIC_BACKEND="numba" transonic $(NAME)
TRANSONIC_BACKEND="python" transonic $(NAME)
transonic $(NAME) -b numba
transonic $(NAME) -b python
clean:
rm -rf __cython__ __python__ __numba__ __pythran__
......
......@@ -252,7 +252,7 @@ class Transonic:
sys.executable,
"-m",
"transonic.run",
"-np",
"-nc",
str(path_mod),
]
)
......
......@@ -24,9 +24,11 @@ Internal API
"""
from pathlib import Path
from typing import Iterable, Optional
from typing import Iterable
import inspect
from transonic.config import backend_default
from transonic.util import get_module_name
from .py import PythonBackend
from .pythran import PythranBackend
......@@ -40,12 +42,16 @@ backends = dict(
python=PythonBackend(),
)
backend_default_modules = {}
def set_backend_for_this_module(backend_name):
raise NotImplementedError
backend_name = backend_name.lower()
frame = inspect.stack()[1]
module_name = get_module_name(frame)
if backend_name not in backends.keys():
raise ValueError(f"Bad backend value ({backend_name})")
backend_default_modules[module_name] = backend_name
def get_backend_name_module(module_name):
......
......@@ -51,7 +51,7 @@ def run():
return
if args.clear_cache:
clear_cached_extensions(args.clear_cache, force=args.force)
clear_cached_extensions(args.clear_cache, args.force, args.backend)
return
if args.verbose is None:
......@@ -82,14 +82,14 @@ def run():
logger.error(f"No input file found (args.path = {args.path})")
sys.exit(1)
backend = backends[backend_default]
backend = backends[args.backend]
backend.make_backend_files(paths, force=args.force)
if not can_import_accelerator() or args.no_pythran:
if not can_import_accelerator() or args.no_compile:
return
# find pythran files not already compiled
backends_paths = {backend_name: [] for backend_name in backends}
backends_paths = []
for path in paths:
path = Path(path)
......@@ -98,10 +98,10 @@ def run():
backend.name_ext_from_path_backend(backend_path)
)
if backend_path.exists() and has_to_build(ext_path, backend_path):
backends_paths[backend.name].append(backend_path)
backends_paths.append(backend_path)
backend.compile_extensions(
backends_paths[backend.name],
backends_paths,
str_pythran_flags=args.pythran_flags,
parallel=True,
force=args.force,
......@@ -121,7 +121,7 @@ def parse_args():
parser.add_argument(
"-f",
"--force",
help="write the file even if it is up-to-date",
help="proceed even if the files seem up-to-date",
action="store_true",
)
......@@ -132,9 +132,17 @@ def parse_args():
parser.add_argument("-v", "--verbose", help="verbose mode", action="count")
parser.add_argument(
"-np",
"--no-pythran",
help="do not compile the Pythran files with Pythran",
"-b",
"--backend",
help=("Backend (pythran, cython, numba or python)"),
type=str,
default=backend_default,
)
parser.add_argument(
"-nc",
"--no-compile",
help="do not compile the Pythran/Cython/... files",
action="store_true",
)
......
......@@ -23,14 +23,14 @@ def test_create_pythran_files():
rmtree(path_dir_out)
if os.name != "nt":
sys.argv = f"transonic -np {path_data_tests / '*.py'}".split()
sys.argv = f"transonic -nc {path_data_tests / '*.py'}".split()
run()
sys.argv = f"transonic -np {path_data_tests}".split()
sys.argv = f"transonic -nc {path_data_tests}".split()
run()
paths = tuple(path_data_tests.glob("*.py*"))
sys.argv = ["transonic", "-np"] + [str(path) for path in paths]
sys.argv = ["transonic", "-nc"] + [str(path) for path in paths]
run()
# At this point, we can compare the produced files with saved files.
......@@ -98,7 +98,7 @@ def test_create_trans_classic():
rmtree(path_dir_out)
path_file = path_data_tests / "classic.py"
sys.argv = f"transonic -np {path_file}".split()
sys.argv = f"transonic -nc {path_file}".split()
run()
print("after first build")
......@@ -122,5 +122,5 @@ def test_create_trans_classic():
sys.argv = f"transonic {path_file}".split()
run()
sys.argv = f"transonic -np {path_file_pythran}".split()
sys.argv = f"transonic -nc {path_file_pythran}".split()
run()
......@@ -343,7 +343,7 @@ def query_yes_no(question: str, default: str = None, force: bool = False):
print('Please respond with "y" or "n".')
def clear_cached_extensions(module_name: str, force: bool = False):
def clear_cached_extensions(module_name: str, force: bool, backend: str):
"""Delete the cached extensions related to a module
"""
......@@ -351,7 +351,7 @@ def clear_cached_extensions(module_name: str, force: bool = False):
from transonic.backends import backends
from transonic import mpi
backend = backends[backend_default]
backend = backends[backend]
path_jit = mpi.Path(backend.jit.path_base)
if module_name.endswith(".py"):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment