Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Debug is the new Release

Debug is the new Release

A talk at pycon china about the unexpected benefits of slow languages like Python.

Armin Ronacher

September 21, 2019
Tweet

More Decks by Armin Ronacher

Other Decks in Programming

Transcript

  1. 1. developer experience matters 2. the ability to debug matters

    3. debugging does not stop when shipping a release
  2. Python 3.7.4 (default, Jul 9 2019, 18:13:23) [Clang 10.0.1 (clang-1001.0.46.4)]

    on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> a_variable = 'Hello World!' >>> sys._getframe().f_locals['a_variable'] 'Hello World!'
  3. >>> import dis >>> >>> def add_numbers(a, b): ... return

    a + b ... >>> dis.dis(add_numbers) 2 0 LOAD_FAST 0 (a) 2 LOAD_FAST 1 (b) 4 BINARY_ADD 6 RETURN_VALUE
  4. while ... { switch (...) { case TARGET(LOAD_FAST): { PyObject

    *value = GETLOCAL(oparg); if (value == NULL) { format_exc_check_arg(tstate, PyExc_UnboundLocalError, UNBOUNDLOCAL_ERROR_MSG, PyTuple_GetItem(co->co_varnames, oparg)); goto error; } Py_INCREF(value); PUSH(value); FAST_DISPATCH(); } }
  5. case TARGET(BINARY_ADD): { PyObject *right = POP(); PyObject *left =

    TOP(); PyObject *sum; if (PyUnicode_CheckExact(left) && PyUnicode_CheckExact(right)) { sum = unicode_concatenate(tstate, left, right, f, next_instr); } else { sum = PyNumber_Add(left, right); Py_DECREF(left); } Py_DECREF(right); SET_TOP(sum); if (sum == NULL) goto error; DISPATCH(); }
  6. import sys def failing_func(): raise Exception('Oh noes') def catching_func(): try:

    failing_func() except Exception: pass def stacktrace_making_func(): try: failing_func() except Exception: sys.exc_info()
  7. mitsuhiko at argus in /tmp $ python -mtimeit -s 'from

    test import catching_func as x' 'x()' 1000000 loops, best of 3: 1.34 usec per loop mitsuhiko at argus in /tmp $ python -mtimeit -s 'from test import stacktrace_making_func as x' 'x()' 1000000 loops, best of 3: 1.44 usec per loop 7% Slower
  8. JIT

  9. function throwingFunc() { throw new Error('Oh noes'); } function catchingFunc()

    { try { throwingFunc(); } catch (err) {} } function stacktraceMakingFunc() { try { throwingFunc(); } catch (err) { return err.stack; } }
  10. catching x 160,895 ops/sec ±2.30% (60 runs sampled) stacktrace making

    x 26,495 ops/sec ±1.98% (86 runs sampled) 83% Slower
  11. OT

  12. 0 libsystem_kernel.dylib 0x00007fff61bc6c2a 0x7fff61bc6000 + 3114 1 CoreFoundation 0x00007fff349f505e 0x7fff349b9000

    + 245854 2 CoreFoundation 0x00007fff349f45ad 0x7fff349b9000 + 243117 3 CoreFoundation 0x00007fff349f3ce4 0x7fff349b9000 + 240868 4 HIToolbox 0x00007fff33c8d895 0x7fff33c83000 + 43157 5 HIToolbox 0x00007fff33c8d5cb 0x7fff33c83000 + 42443 6 HIToolbox 0x00007fff33c8d348 0x7fff33c83000 + 41800 7 AppKit 0x00007fff31f4a95b 0x7fff31f30000 + 108891 8 AppKit 0x00007fff31f496fa 0x7fff31f30000 + 104186 9 AppKit 0x00007fff31f4375d 0x7fff31f30000 + 79709 10 YetAnotherMac 0x0000000108b7092b 0x10864e000 + 5384491 11 YetAnotherMac 0x0000000108b702a6 a_function_here + 64 12 libdyld.dylib 0x00007fff61a8e085 start + 0 13 YetanotherMac 0x00000000000ea004 main (main.m:16)
  13. 1. debuggability incurs runtime cost 2. JIT/AOT optimizations break down

    3. If you want debug functionality in production, percentage performance loss matters
  14. >>> import sys >>> sys._getframe().f_locals {'__annotations__': {}, '__builtins__': <module 'builtins'

    (built-in)>, '__cached__': None, '__doc__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x1090d55d0>, '__name__': '__main__', '__package__': None, '__spec__': None, 'sys': <module 'sys' (built-in)>}
  15. >>> try: ... 1/0 ... except Exception as e: ...

    e.__traceback__ ... <traceback object at 0x1093559b0>
  16. you can also attach a debugger, run some code and

    start a reverse python shell on a running process