For Programmers: Free Programming Magazines  


Home > Archive > Tcl > June 2006 > Solved: ::errorStack in pure Tcl (was Re: Subst'ed ::errorInfo)









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Solved: ::errorStack in pure Tcl (was Re: Subst'ed ::errorInfo)
Alex

2006-06-24, 8:23 am


I've just written:

> I'd have *loved* to do this entirely in Tcl by attaching a write trace
> to errorInfo itself, however this subtly fails. I filed a bug report on
> this years ago, but somebody explained that this failure was a security
> *feature*.


Well, at some point in Tcl's history this limitation was removed, or at
least weakened.
The following code solves the whole problem in pure Tcl:

set ::errorLevel -1
set ::errorStack {}
trace add variable ::errorInfo write {
set __n [info level]
if {($__n>0)&&($__n!=$::errorLevel)} {
set ::errorLevel $__n
set __l [info level 0]
lappend ::errorStack $__l
}
list}

(the check on the level is here to avoid duplicate entries since there
are 4 writes per level)
For example, with the following error-raising code:

proc f x {g $x$x}
proc g x {h $x$x}
proc h x {error yo}
f [expr rand()]

I get back in ::errorStack:

{h 0.8329711886280.8329711886280.8329711886280.832971188628}
{g 0.8329711886280.832971188628}
{f 0.832971188628}

Hope this helps. It'll help me at least :-)

-Alex

David N. Welton

2006-06-24, 8:23 am

Alex wrote:

> (the check on the level is here to avoid duplicate entries since there
> are 4 writes per level)
> For example, with the following error-raising code:
>
> proc f x {g $x$x}
> proc g x {h $x$x}
> proc h x {error yo}
> f [expr rand()]
>
> I get back in ::errorStack:
>
> {h 0.8329711886280.8329711886280.8329711886280.832971188628}
> {g 0.8329711886280.832971188628}
> {f 0.832971188628}
>
> Hope this helps. It'll help me at least :-)


Hey, nice code:-) It would be to see this polished up (a few tests
and or docs) and placed in tcllib.

--
David N. Welton
- http://www.dedasys.com/davidw/

Linux, Open Source Consulting
- http://www.dedasys.com/
Donal K. Fellows

2006-06-24, 8:23 am

Alex wrote:
> Well, at some point in Tcl's history this limitation was removed, or at
> least weakened.


I think you have Don Porter to thank there. He's done much work to make
Tcl's error handling much better.

> The following code solves the whole problem in pure Tcl:
> set ::errorLevel -1
> set ::errorStack {}
> trace add variable ::errorInfo write {
> set __n [info level]
> if {($__n>0)&&($__n!=$::errorLevel)} {
> set ::errorLevel $__n
> set __l [info level 0]
> lappend ::errorStack $__l
> }
> list}


Neat. With 8.5 it should be possible to make that information part of
the error context options (like the errorInfo trace itself and other
data like the line number of the error) so that the data is passed
around to whoever really needs to handle it, though older code will
still likely throw that data away. (No, this is not a backport-able
feature as it depended on some fairly complex internal changes.)

Other things to possibly capture is the list of variables in scope at
each level of the stack, or what the current namespace is.

Donal.
Don Porter

2006-06-24, 8:23 am

Alex wrote:
> The following code solves the whole problem in pure Tcl:
>
> set ::errorLevel -1
> set ::errorStack {}
> trace add variable ::errorInfo write {
> set __n [info level]
> if {($__n>0)&&($__n!=$::errorLevel)} {
> set ::errorLevel $__n
> set __l [info level 0]
> lappend ::errorStack $__l
> }
> list}


Please clarify exactly what version of Tcl this works in.

--
| Don Porter Mathematical and Computational Sciences Division |
| donald.porter@nist.gov Information Technology Laboratory |
| http://math.nist.gov/~DPorter/ NIST |
|_______________________________________
_______________________________|
Alex

2006-06-24, 8:23 am


Don Porter wrote:
> Alex wrote:
>
> Please clarify exactly what version of Tcl this works in.


Somewhere between 8.4.5 and 8.4.13. I'll try other versions asap.

Specifically, the way it fails for versions <=8.4.5 is that
- the building up of ::errorStack works
- but there is a nasty side-effect on ::errorInfo which is
"collapsed" to only its two extremities:

yo
while executing
"f [expr rand()]"

instead of:

yo
while executing
"error yo"
(procedure "h" line 1)
invoked from within
"h $x$x"
(procedure "g" line 1)
invoked from within
"g $x$x"
(procedure "f" line 1)
invoked from within
"f [expr rand()]"

-Alex

Jeff Hobbs

2006-06-24, 7:05 pm

Alex wrote:
> Donal K. Fellows wrote:
>
> Wow !!!
>
> Thanks to both Don's for these impressive news. I say news because none
> of these optimizations are there on my 8.3.5 on Fedora 1 (I work in
> environments constrained by the availability of device drivers):
>
> % info patchlevel
> 8.3.5
> % string length $x
> 108025344
> % time {string match *PAPIPO* $x}
> 5211760 microseconds per iteration
> % time {regexp {PAPIPO} $x}
> 1358667 microseconds per iteration
>
> But on 8.4.13, you win :-)
>
> It's fascinating to see that, just like C compilers, the Tcl bytecode
> compiler is now an optimizing compiler, and just like with C and asm,
> the old programmer I am must recognize that most of his craft is now
> wasted, or even counter-productive. Sigh...
> Sunny side: Tcl is damn fast these days !


Discussions like these always make it appropriate to reference
http://wiki.tcl.tk/1611 for benchmark comparisons.

A lot of performance improvements went into 8.4 in different phases of
focus. It started off primarily by seeing lots of user scripts come
through my email that were using "old" syntax, like 'string match' in
place of 'string equal' (which was added in 8.1.1), regexp usage all
over where no special RE matching was needed, etc. So I went about
figuring out various improvements to text comparisons.

The basic part was getting common 'string' subcommands byte compiled.
That actually helped, with the addition of extra checks that improved
'stirng equal'.

Then, check out "STR match" (lines 470..480). I examined and
subsequently rewrote the core string match algorithm for 8.4 that
provides up to 10x performance improvement on larger matches.

After doing that, armed with a leaner and meaner basic string matcher
(and too afraid to poke into the real RE guts ;) ), I looked at how it
could be applied for the over-use of 'regexp'. This led to a regexp
compile command that preparses for static string search (converting to
'string equal' or 'string match' as noted), as well as a runtime regexp
string check that does something similar.

In any case, that's a short history of 8.3->8.4 string parsing
improvements (many others assisted in other parts of making 8.4 better
of course).

Jeff
Jeff Hobbs

2006-06-24, 7:05 pm

Uwe Klein wrote:
> Donal K. Fellows wrote:
>
> Does this magic apply to regexps as
> in
> [switch -regexp ..]
> and
> [expect -re ..]


switch only got byte-compiled in 8.5, and it hasn't been pushed to
handle these optimizations. Looking at the code, it could certainly be
improved on this front. Feel free to file a report so that this rather
easy optimization idea isn't lost.

As to expect, it runs on its own code base. It can't byte-compile
anything, but there are several things that could be done to improve its
performance with respect to its string matching handling.

Jeff
Donal K. Fellows

2006-06-26, 4:21 am

Jeff Hobbs wrote:
> switch only got byte-compiled in 8.5, and it hasn't been pushed to
> handle these optimizations. Looking at the code, it could certainly be
> improved on this front. Feel free to file a report so that this rather
> easy optimization idea isn't lost.


And as the author of the [switch] compiler, I can say definitively that
I'm unlikely to work on doing better handling of the RE case. That code
is already very complex; it's the longest compiler function. Only the
expression compiler is larger, and that's several files of parser, etc.

But as an outline of what to do, you need to add detection of the RE
case in the option parsing, add a separate complexity filter to detect
if all the REs are "simple" (in the same sense of simplicity that the
[regexp] compiler knows) immediately before starting to emit code (bail
with TCL_ERROR otherwise) and emit the correct matching opcodes in the
body generator. Extra points for detecting whether you're in the domain
of pure exact matching REs and switching to the jump-table emitter in
that case. :-)

Donal.
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com