Menu

#593 TIP #348: Substituted errorStack

TIP Implementation
closed-accepted
None
9
2010-04-05
2009-09-27
No

Here is a crude but functional implementation of TIP #348.
The variable ::errorStack, comes to life when defined (which is not the case by default, to avoid any performance hit).
While unwinding, it is populated by substituted argslists as described in the TIP.
It is automatically reset (to the empty list) whenever ::errorInfo is. (But this leaves it enabled. To disable it, unset it.)

(Among crudities: uses ::errorStack instead of ::tcl::errorStack, doesn't pay attention to code style, no test cases.
Also, it inserts two fields in the private interp structure, right in the middle, not at the end. ABI hazard, don't forget to 'make clean' after applying ;-)

Discussion

1 2 3 > >> (Page 1 of 3)
  • Alexandre Ferrieux

    First slight improvement: explicitly skip iPtr->rootFramePtr, like in [info level $n], since the root frame will always have argc==0. This removes the parasitic {} always found at the end of ::errorStack, and also an extra one generated by [tailcall] and [coroutine].

    Next improvements planned:

    (1) make the on/off switch more efficient by using a linked boolean var rather than the existence of ::errorStack which costs a hash lookup when negative.

    (2) make the list building slightly more efficient by using a backbone of Tcl_Obj as Cons'es (linked list), and turning it into a Tcl list only in a read trace attached to ::errorStack (instead of directly lappending as is currently the case. This construction is wasted in caught, expected exception handling where the errorStack is not used).

    (3) proper ::tcl namespace + test cases.

     
  • Alexandre Ferrieux

    Mostly done.
    - now the var is ::tcl::errorStack and the flag is ::tcl::useErrorStack
    - zero overhead when ::tcl::useErrorStack is 0 (default)
    - uses a read trace to postpone var machinery until real use
    - uses an optimized in-place lappend/reset to keep the list intrep as much as possible (just as fast as the linked list approach IMO)
    TBD: test cases.

     
  • Alexandre Ferrieux

    Complete with test cases now.

     
  • Alexandre Ferrieux

    Andreas' fix

     
  • Alexandre Ferrieux

    API remodelled after jenglish's suggestions

     
  • Alexandre Ferrieux

    Attaching a new patch, errorstack2.patch, fulfilling Joe's request of [info errostack ?interp?] and [dict get $d -errostack].
    I left the ::tcl::useErrorStack control variable for perf measurements:
    0 --> pristine HEAD
    1 --> just [info errorstack]
    2 ---> adds options dict entry -errorstack

    Note the implementation still uses ckalloc-based Tcl_NewListObj for argslist, pending proof that optimization is needed.
    Here are the figures:

    Case: Ten-fold catch ladder use=0 -> 74.7924 microseconds per iteration
    Case: Ten-fold catch ladder use=1 -> 76.7888 microseconds per iteration
    Case: Ten-fold catch ladder use=2 -> 77.1977 microseconds per iteration
    Case: Single Catch with opt dict use=0 -> 19.2613 microseconds per iteration
    Case: Single Catch with opt dict use=1 -> 19.7608 microseconds per iteration
    Case: Single Catch with opt dict use=2 -> 20.2815 microseconds per iteration

    with code:

    for {set i 1} {$i<10} {incr i} {
    proc f$i x "f[expr {$i+1}] \$x"
    }
    proc f10 x {error F10:$x}

    proc boo {} {error BOO}

    proc catchloop {} {
    for {set i 0} {$i<100000} {incr i} {
    if {[catch boo m d]} continue
    }
    }

    foreach {mm ss} {
    "Ten-fold catch ladder" {catch {f1 12}}
    "Single Catch with opt dict" {catch boo m d}
    } {

    foreach v {0 1 2} {
    set ::tcl::useErrorStack $v
    puts "Case: $mm use=$v -> [time $ss 10000]"
    }
    }

     
  • Alexandre Ferrieux

    Add faster "flatlist" mode

     
  • Alexandre Ferrieux

    Extended patch adds bit value 4 as "flat list", ie errorstack is built as
    2 foo bar 1 baz 2 gnu gnats
    instead of
    {foo bar} baz {gnu gnats}
    Hence:
    use=0 : pristine
    use=1 : info errorstack
    use=2 : + dict
    use=5 : 1 + flatlist
    use=6 : 2 + flatlist

    Timings below:
    Case: Ten-fold catch ladder use=0 -> 101.3854 microseconds per iteration
    Case: Ten-fold catch ladder use=1 -> 106.2653 microseconds per iteration
    Case: Ten-fold catch ladder use=2 -> 106.8439 microseconds per iteration
    Case: Ten-fold catch ladder use=5 -> 103.5229 microseconds per iteration
    Case: Ten-fold catch ladder use=6 -> 103.7669 microseconds per iteration
    Case: Single Catch with opt dict use=0 -> 25.814 microseconds per iteration
    Case: Single Catch with opt dict use=1 -> 26.2905 microseconds per iteration
    Case: Single Catch with opt dict use=2 -> 27.0002 microseconds per iteration
    Case: Single Catch with opt dict use=5 -> 26.0665 microseconds per iteration
    Case: Single Catch with opt dict use=6 -> 26.783 microseconds per iteration

    Conclusion: while the gain for a tight catch loop is negligible, for a ten-fold catch ladder building a long errorstack it is substantial: the flatlist roughly divides the overhead by three.

    However, the flatlist is a bit less convenient for the programmer.
    It could be postprocessed into a nested list in [info errorstack] but not int the options dict...

     
  • Alexandre Ferrieux

    Restricted to chosen variant

     
  • Alexandre Ferrieux

    Patch now restricted as per Joe's recommendations on tclcore:
    - always on
    - non-flat list
    - with options dict
    Test suite now needs fixes wherever the options dict was checked in extenso...

     
  • Alexandre Ferrieux

    Complete with fixed tests

     
  • Alexandre Ferrieux

    Test suite now fixed. Thanks to -match glob :)

     
  • Alexandre Ferrieux

    Daniel's fix

     
  • Alexandre Ferrieux

    Manpages

     
  • Alexandre Ferrieux

    Added documentatoin in catch.n and info.n.

     
  • Don Porter

    Don Porter - 2009-12-15
    • priority: 5 --> 9
    • assigned_to: msofer --> dgp
     
  • Alexandre Ferrieux

    Updated to HEAD

     
  • Alexandre Ferrieux

    Patch updated to HEAD.

     
  • Alexandre Ferrieux

    Updated to HEAD + Don's updates

     
  • Alexandre Ferrieux

    Patch re-updated to HEAD, and now includes two updates suggested by dgp:
    (a) restriction of -errorstack dict option to TCL_ERROR cases
    (b) simplification of the internal [lappend] used

     
  • Don Porter

    Don Porter - 2010-03-17

    -errorstack is like -errorcode in that
    it wants a list argument. This patch
    suffers from the same bug as 2383005.
    Both bugs should be fixed.

     
  • Don Porter

    Don Porter - 2010-03-17

    Need to examine whether
    Tcl_SaveInterpState and friends
    need to give the -errorstack dict
    entry any special treatment like
    errorInfo and errorCode receive,
    or whether it's fully covered by
    the returnOpts dict.

     
  • Don Porter

    Don Porter - 2010-03-17

    TclProcessReturn() does not appear
    to have anything in it to pull a -errorstack
    value out of the options dict to be stored
    in the iPtr->errorstack field.

     
  • Alexandre Ferrieux

    No, -errorstack is just a readonly optsDict member. Even Joe, who asked for it in the first place, didn't ask for a [return -errorstack]. Personally I believe(d) that restricting ourselves to [info/interp errorstack] is(was) even better, but I yielded.

    Question1: do you think that a read-only optsDict member is out of question ?
    Question2: where's your preference between:
    (a) a read-write opt
    (b) no opt, just [info/interp errorstack]
    ?

     
  • Don Porter

    Don Porter - 2010-03-17

    um, that's novel. :)

    I might be convinced to make this
    one special, but in that case I don't
    think the right thing to do with
    [return -errorstack] is to just let it
    silently fail. If we are to disallow it,
    raise an error.

    I was wondering myself about
    whether [info errostack] would be
    sufficient. The issue appears to
    come down to whether or not
    the value of -errorstack ought to
    be considered part of the "state"
    of the interp -- those values saved
    and restored by Tcl_*InterpState()
    and cable to be [catch]-ed and
    re-raised by [return -options]. Since
    you call -errorstack a sister of -errorinfo,
    my first assumption is that it is part of
    that state, and needs to be part of that
    save/restore capability, and for that reason
    needs to be writable via the [return] command.

     
1 2 3 > >> (Page 1 of 3)
MongoDB Logo MongoDB