| -- TODO: build some generic benchmark harness | |
| [case testBenchmarkTree] | |
| from typing import Optional | |
| class Node: | |
| def __init__(self, value: int) -> None: | |
| self.value = value | |
| self.left = None # type: Optional[Node] | |
| self.right = None # type: Optional[Node] | |
| def sum(self) -> int: | |
| left = 0 | |
| if self.left is not None: | |
| left = self.left.sum() | |
| right = 0 | |
| if self.right is not None: | |
| right = self.right.sum() | |
| return self.value + left + right | |
| def sum_tree(x: Optional[Node]) -> int: | |
| if x is None: | |
| return 0 | |
| return x.value + sum_tree(x.left) + sum_tree(x.right) | |
| def build(n: int) -> Optional[Node]: | |
| if n == 0: | |
| return None | |
| x = Node(n) | |
| x.left = build(n - 1) | |
| x.right = x.left | |
| return x | |
| def bench_sum(x: Optional[Node]) -> None: | |
| for i in range(1000000): | |
| sum_tree(x) | |
| def bench_sum_method(x: Node) -> None: | |
| for i in range(1000000): | |
| x.sum() | |
| [file driver.py] | |
| from typing import Optional | |
| import native | |
| import interpreted | |
| from timeit import timeit | |
| from time import time | |
| import os | |
| def dumb_time(f): | |
| t0 = time() | |
| f() | |
| t1 = time() | |
| return t1 - t0 | |
| def basic_test(m): | |
| tree = m.build(5) | |
| assert(m.sum_tree(tree) == 57) | |
| assert(tree.sum() == 57) | |
| return tree | |
| def test(m): | |
| tree = basic_test(m) | |
| g = {**globals(), **locals()} | |
| sum = timeit('m.sum_tree(tree)', globals=g) | |
| sum2 = timeit('tree.sum()', globals=g) | |
| fsum = dumb_time(lambda: m.bench_sum(tree)) | |
| fsum2 = dumb_time(lambda: m.bench_sum_method(tree)) | |
| build = timeit('m.build(5)', globals=g) | |
| return (sum, sum2, fsum, fsum2, build) | |
| # Basic functionality test | |
| basic_test(native) | |
| # Benchmark if we are benchmarking | |
| if os.environ.get('MYPYC_RUN_BENCH') == '1': | |
| nsum, nsum2, nfsum, nfsum2, nbuild = test(native) | |
| isum, isum2, ifsum, ifsum2, ibuild = test(interpreted) | |
| print(nsum, nsum2, nfsum, nbuild) | |
| print("Sum speedup:", isum/nsum) | |
| print("Sum method speedup:", isum2/nsum2) | |
| print("Sum (fast) speedup:", ifsum/nfsum) | |
| print("Sum (fast) method speedup:", ifsum2/nfsum2) | |
| print("Build speedup:", ibuild/nbuild) | |
| [case testBenchmarkVisitorTree] | |
| from mypy_extensions import trait | |
| from typing import cast, Generic, TypeVar, Any | |
| T = TypeVar('T') | |
| class Tree: | |
| def accept(self, v: 'TreeVisitor[T]') -> T: | |
| pass | |
| class Leaf(Tree): | |
| def accept(self, v: 'TreeVisitor[T]') -> T: | |
| return v.visit_leaf(self) | |
| class Node(Tree): | |
| def __init__(self, value: int, left: Tree, right: Tree) -> None: | |
| self.value = value | |
| self.left = left | |
| self.right = right | |
| def accept(self, v: 'TreeVisitor[T]') -> T: | |
| return v.visit_node(self) | |
| @trait | |
| class TreeVisitor(Generic[T]): | |
| def visit_leaf(self, x: Leaf) -> T: return cast(T, None) | |
| def visit_node(self, x: Node) -> T: return cast(T, None) | |
| class SumVisitor(TreeVisitor[int]): | |
| def sum(self, x: Tree) -> int: | |
| return x.accept(self) | |
| def visit_leaf(self, x: Leaf) -> int: | |
| return 0 | |
| def visit_node(self, x: Node) -> int: | |
| return x.value + self.sum(x.left) + self.sum(x.right) | |
| def equal(x: Tree, y: Tree) -> bool: | |
| return EqualVisitor(x).equal(y) | |
| class EqualVisitor(TreeVisitor[bool]): | |
| def __init__(self, left: Tree) -> None: | |
| self.left = left | |
| def equal(self, right: Tree) -> bool: | |
| return right.accept(self) | |
| def visit_leaf(self, right: Leaf) -> bool: | |
| return isinstance(self.left, Leaf) | |
| def visit_node(self, right: Node) -> bool: | |
| if isinstance(self.left, Node): | |
| # our boolean stuff is crap | |
| if (self.left.value == right.value and equal(self.left.left, right.left) | |
| and equal(self.left.right, right.right)): | |
| return True | |
| return False | |
| def sum_tree(x: Tree) -> int: | |
| return SumVisitor().sum(x) | |
| def build(n: int) -> Tree: | |
| if n == 0: | |
| return Leaf() | |
| return Node(n, build(n - 1), build(n - 1)) | |
| def bench_sum_tree(x: Tree) -> None: | |
| for i in range(100000): | |
| sum_tree(x) | |
| def bench_equal_tree(x: Tree, y: Tree) -> None: | |
| for i in range(100000): | |
| equal(x, y) | |
| [file driver.py] | |
| from typing import Optional | |
| import interpreted | |
| import native | |
| from timeit import timeit | |
| from time import time | |
| import os | |
| import sys | |
| # Side test: some stuff about MROs and generics | |
| if sys.version_info[:3] > (3, 5, 2): | |
| assert tuple(x.__name__ for x in interpreted.SumVisitor.mro()) == ('SumVisitor', 'TreeVisitor', 'Generic', 'object') | |
| assert tuple(x.__name__ for x in native.SumVisitor.mro()) == ('SumVisitor', 'TreeVisitor', 'Generic', 'object') | |
| assert str(native.TreeVisitor[native.T]) == "native.TreeVisitor[~T]" | |
| assert native.TreeVisitor.__name__ == "TreeVisitor" | |
| assert native.SumVisitor.__name__ == "SumVisitor" | |
| def dumb_time(f): | |
| t0 = time() | |
| f() | |
| t1 = time() | |
| return t1 - t0 | |
| def basic_test(m): | |
| tree = m.build(5) | |
| tree2 = m.build(5) | |
| tree2.right.right.right.value = 10 | |
| assert m.sum_tree(tree) == 57 | |
| assert m.equal(tree, tree) | |
| assert not m.equal(tree, tree2) | |
| assert isinstance(native.SumVisitor(), native.TreeVisitor) | |
| return tree | |
| def test(m): | |
| tree = basic_test(m) | |
| g = {**globals(), **locals()} | |
| fsum = dumb_time(lambda: m.bench_sum_tree(tree)) | |
| feq = dumb_time(lambda: m.bench_equal_tree(tree, tree)) | |
| return fsum, feq | |
| basic_test(native) | |
| if os.environ.get('MYPYC_RUN_BENCH') == '1': | |
| nfsum, nfeq = test(native) | |
| ifsum, ifeq = test(interpreted) | |
| print(nfsum) | |
| print("Sum speedup:", ifsum/nfsum) | |
| print("Equal speedup:", ifeq/nfeq) |