Skip to content

Stop including location exception was caught in Failure #12230

@itamarst

Description

@itamarst

About 2/3rds of the time spent in creating Failure objects, and therefore in error handling in Deferred, is constructing Deferred.stack. I would argue this isn't necessary, insofar as Python doesn't include this info, and it's a huge performance hit.

Comparing Python tracebacks to Failure tracebacks

Consider the following script:

from twisted.python.failure import Failure
import sys
import traceback

def f():
    def h():
        1 / 0

    def g():
        h()

    g()

def a():
    try:
        f()
    except:
        if sys.argv[1] == "python":
            print("PYTHON")
            traceback.print_tb(sys.exc_info()[-1], file=sys.stdout)
        else:
            print("TWISTED")
            failure = Failure()
            failure.cleanFailure()
            failure.printTraceback(sys.stdout)

a()

When run:

(py311) itamarst@louverture:~/devel/twisted$ python 12227.py python
PYTHON
  File "/home/itamarst/devel/twisted/12227.py", line 16, in a
    f()
  File "/home/itamarst/devel/twisted/12227.py", line 12, in f
    g()
  File "/home/itamarst/devel/twisted/12227.py", line 10, in g
    h()
  File "/home/itamarst/devel/twisted/12227.py", line 7, in h
    1 / 0
    ~~^~~
(py311) itamarst@louverture:~/devel/twisted$ python 12227.py twisted
TWISTED
Traceback (most recent call last):
  File "/home/itamarst/devel/twisted/12227.py", line 26, in <module>    # <---- only Twisted has this bit!
    a()
--- <exception caught here> ---
  File "/home/itamarst/devel/twisted/12227.py", line 16, in a
    f()
  File "/home/itamarst/devel/twisted/12227.py", line 12, in f
    g()
  File "/home/itamarst/devel/twisted/12227.py", line 10, in g
    h()
  File "/home/itamarst/devel/twisted/12227.py", line 7, in h
    1 / 0
builtins.ZeroDivisionError: division by zero

Notice that Twisted includes where the Failure was created, whereas Python only includes the traceback.

Why omit this? Performance

Two thirds of the time spent in Deferred error handling of Failure (as measured by the relevant benchmark) is tied in creating Deferred.stack.

A compromise

If we want to be extra nice, this extra info can be turned on when Deferred.debug is turned on.

A counterargument

It may be that the info of "where did we catch the exception" is super-helpful. I am not sure I have enough relevant experience in debugging production Twisted applications to have a good opinion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions