| 1 | #!/usr/bin/env python2
 | 
| 2 | """
 | 
| 3 | container_types.py
 | 
| 4 | """
 | 
| 5 | from __future__ import print_function
 | 
| 6 | 
 | 
| 7 | import os
 | 
| 8 | from mycpp import mylib
 | 
| 9 | from mycpp.mylib import log
 | 
| 10 | 
 | 
| 11 | from typing import List, Tuple
 | 
| 12 | 
 | 
| 13 | 
 | 
| 14 | def IfDemo(i):
 | 
| 15 |     # type: (int) -> None
 | 
| 16 | 
 | 
| 17 |     if i == 1:
 | 
| 18 |         print('one')
 | 
| 19 |     elif i == 2:
 | 
| 20 |         print('two')
 | 
| 21 |     elif i == 3:
 | 
| 22 |         print('three')
 | 
| 23 |     elif i == 4:
 | 
| 24 |         pass  # no-op
 | 
| 25 |     else:
 | 
| 26 |         print('other number')
 | 
| 27 | 
 | 
| 28 | 
 | 
| 29 | class ParseError(Exception):
 | 
| 30 | 
 | 
| 31 |     def __init__(self, reason):
 | 
| 32 |         # type: (str) -> None
 | 
| 33 |         self.reason = reason
 | 
| 34 | 
 | 
| 35 | 
 | 
| 36 | def f(s):
 | 
| 37 |     # type: (str) -> str
 | 
| 38 | 
 | 
| 39 |     if s[0] == 'f':
 | 
| 40 |         raise ParseError('started with f')
 | 
| 41 |     return s
 | 
| 42 | 
 | 
| 43 | 
 | 
| 44 | def ExceptDemo():
 | 
| 45 |     # type: () -> None
 | 
| 46 | 
 | 
| 47 |     result = ''
 | 
| 48 |     tmp = ['foo', 'bar']
 | 
| 49 |     for prog in tmp:
 | 
| 50 |         try:
 | 
| 51 |             result = f(prog)
 | 
| 52 |         except ParseError as e:
 | 
| 53 |             log('error: %s', e.reason)
 | 
| 54 |             continue
 | 
| 55 |         log('result = %s', result)
 | 
| 56 | 
 | 
| 57 | 
 | 
| 58 | def run_tests():
 | 
| 59 |     # type: () -> None
 | 
| 60 | 
 | 
| 61 |     tmp = [1, 2, 3, 4, 5]
 | 
| 62 |     for i in tmp:
 | 
| 63 |         IfDemo(i)
 | 
| 64 | 
 | 
| 65 |     log('')
 | 
| 66 |     ExceptDemo()
 | 
| 67 | 
 | 
| 68 | 
 | 
| 69 | def run_benchmarks():
 | 
| 70 |     # type: () -> None
 | 
| 71 | 
 | 
| 72 |     # BUG: we only get 8191 exceptions instead of 100,000?  I think this must be
 | 
| 73 |     # because of 'throw Alloc<ParseError>?  TODO: Should exceptions throw by
 | 
| 74 |     # value?
 | 
| 75 |     n = 100000
 | 
| 76 | 
 | 
| 77 |     # C++ exceptions are slower than Python!  Woah.
 | 
| 78 | 
 | 
| 79 |     result = ''
 | 
| 80 |     num_exceptions = 0
 | 
| 81 |     i = 0
 | 
| 82 | 
 | 
| 83 |     # Even one failure makes C++ slower!  Otherwise it's faster.
 | 
| 84 |     cases = ['fail', 'ok', 'ok', 'ok']
 | 
| 85 | 
 | 
| 86 |     # 870 ms in C++, 366 ms in Python
 | 
| 87 |     #cases = ['fail', 'fail', 'fail', 'fail']
 | 
| 88 | 
 | 
| 89 |     # 26 ms in C++, 70 ms in Python
 | 
| 90 |     # OK it is inverted!  Exceptions are really expensive.
 | 
| 91 |     #cases = ['ok', 'ok', 'ok', 'ok']
 | 
| 92 | 
 | 
| 93 |     while i < n:
 | 
| 94 |         for prog in cases:
 | 
| 95 |             try:
 | 
| 96 |                 result = f(prog)
 | 
| 97 |             except ParseError as e:
 | 
| 98 |                 num_exceptions += 1
 | 
| 99 |                 continue
 | 
| 100 |         i += 1
 | 
| 101 | 
 | 
| 102 |         mylib.MaybeCollect()  # manual GC point
 | 
| 103 | 
 | 
| 104 |     log('num_exceptions = %d', num_exceptions)
 | 
| 105 |     log('Ran %d iterations of try/except', n)
 | 
| 106 | 
 | 
| 107 | 
 | 
| 108 | if __name__ == '__main__':
 | 
| 109 |     if os.getenv('BENCHMARK'):
 | 
| 110 |         log('Benchmarking...')
 | 
| 111 |         run_benchmarks()
 | 
| 112 |     else:
 | 
| 113 |         run_tests()
 |