deadpixi / contracts

An implementation of contracts for Python.
GNU Lesser General Public License v3.0
342 stars 18 forks source link

Poor performance due to namedtuple construction in build_call #20

Open jamescasbon opened 5 years ago

jamescasbon commented 5 years ago

Is this performance to be expected? There seems to be a lot of time spent in building namedtuples...


$ python --version
Python 3.6.6 :: Anaconda, Inc.

$ cat test_dp.py
import sys
from dpcontracts import require

if sys.argv[1] == "dp":
    @require("something about x", lambda args: args.x is not None)
    def hot_method(x):
        pass

else:
    def hot_method(x):
        pass

for i in range(100000):
    hot_method(i)

$ python test_dp.py nodp
python test_dp.py nodp  0.05s user 0.00s system 98% cpu 0.053 total
$ python test_dp.py dp
python test_dp.py dp  29.19s user 0.02s system 99% cpu 29.284 total

# turned down to 10,000 iters...
$ python -m cProfile -stottime test_dp.py dp
         775121 function calls (765029 primitive calls) in 3.144 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  10019/1    2.109    0.000    3.283    3.283 {built-in method builtins.exec}
    10028    0.194    0.000    0.261    0.000 {built-in method builtins.__build_class__}
    10010    0.129    0.000    2.756    0.000 __init__.py:357(namedtuple)
    10000    0.119    0.000    3.221    0.000 dpcontracts.py:437(build_call)
    30110    0.085    0.000    0.085    0.000 {method 'format' of 'str' objects}
    10001    0.078    0.000    0.182    0.000 inspect.py:2095(_signature_from_function)
    10001    0.055    0.000    0.312    0.000 inspect.py:1082(getfullargspec)
    10001    0.040    0.000    0.233    0.000 inspect.py:2176(_signature_from_callable)
    10001    0.039    0.000    0.051    0.000 inspect.py:2725(__init__)
    10000    0.032    0.000    3.260    0.000 dpcontracts.py:502(inner)
jamescasbon commented 5 years ago

From a quick look, it seems like the tuple type only needs to be built on the first call. It can then be reused for further calls. Let me know if you would be interested in a patch.

jamescasbon commented 5 years ago

See pull request #21