From: Donal K. F. <don...@ma...> - 2012-11-21 10:57:54
|
On 21/11/2012 02:27, Karl Lehenbauer wrote: > From talking to numerous people who understand the issues a lot better > than I do, there are some features of Tcl that, while useful, have an > unfortunate side effect of preventing speedup techniques that would > otherwise be straightforward. While right now I'm cleaning out alligators from a different part of the swamp (64-bit Tcl was in a *bad* state), there are a number of really good ideas around. To be clear though, 10x *requires* native code generation; nothing else stands a chance of getting to that level. That's a major challenge (and if we do it, those of us with vaguely academic careers will probably want to write a paper on it for the wider world; the level of type inference required will be rather higher than is normal for programming languages). > One of the issues is _variable traces_, that since each reference to a > variable might cause code to be executed to produce the value, it > inhibits variable caching inside proc execution which would be a big > win. At the Tcl 2012 conference we discussed ways of declaring that > you're not going to use variable tracing, like a pragma > no-variable-tracing or something. > > If that's helpful, it works for me. Also I gather it's an issue for > execution tracing as well. One of the things that has been discussed in the past is automatically proving additional safety constraints, such as trace-freedom. I think it turns out to be relatively possible for local variables; one of the reasons I did a big push for bytecoding in 8.6 was that it makes this sort of analysis much easier. What I'm hoping to do is to detect when we can safely switch to a faster compilation mode without any code changes on the users' side. > I also was told by a different person that _upvar_ is problematic. If I > understand it it is because the coder can use upvar to muck with a > variable that the interpreter would also be trying to cache and the > interpreter wouldn't know I was doing it because the code to do it could > be generated on the fly and passed to eval. > > While upvar is such a common usage pattern for us that I could hardly > live without it, what we use it for 99% of the time is to access a > variable by reference where the caller has passed the variable or array > name as an argument. There are four known fully-sane :-) use-cases of [upvar]: upvar 1 - Couple to variable in caller (common) upvar 0 - Local alias to variable (used heavily in the http package) upvar #0 - Couple to global/namespace variable (but [global] and [variable] are more common) upvar #1 - Couple to coroutine-specific variable (i.e., not seen in code before 8.6) Anything else is a case we can ignore. > Recognizing that call-by-reference via upvar is a place where we kind of > lose people, anyway, I have been toying with the idea of providing some > syntax in proc arguments to say that the variable is by reference, so > instead of writing > > proc handle_flightplan_update {rowArrayName} { > upvar $rowArrayName row > > switch $row(status) ... > } > > You might write > > proc handle_flightplan_update {*row} { > > switch $row(status) ... > } > > (Someone I proposed this to suggested ampersand instead of asterisk, but > whatever.) Sounds very sensible. Saves me from having to propose it. :-) > This would say "I'm operating on the variable whose name was passed." > It would be just the same as upvar except as envisioned when used this > way there would be no way to find out the name of the variable passed as > known by the caller -- you'd have to use info level to dig it out. > > And by using this style I'm promising I'm not going to use upvar to go > rummaging around after call arguments through a side channel. That > doesn't strike me as quite right, but somehow I can make a promise that > I'm not going to use upvar, or the bytecode compiler can even know I > didn't use it because it knows from compiling the proc that I didn't. > > Of course someone could make up something and call eval on it that could > mess the variable underneath the bytecode interpreter's caches. So I > don't know what you do about that. Maybe recognize that eval is not > invoked, which isn't needed as often as it used to be, anyway, since we > have the {*} thing. Right now, the problem cases of [eval] (and [uplevel 0]!) are quite easily detectable at compile time. Even better, they're rare; dropping the optimization level in response to them is A-OK. Easy to do too. :-) > I'm not expert on the language issues that features optimization > difficult, but I believe if we can come up with ways to, for instance, > get the same result as upvar for 95+% of the times it's used in order to > get a big performance win, then I'm eager to see that, and likewise for > similar issues provide mostly the same capability in a way that allows > for greater performance, then look hard at doing that. Yes. I'm particularly interested in optimizing cases that will help a lot of Tclers' code, and that means focusing on the practices that exist and not just what's easy. It might even be possible to do something better with [uplevel 1] (enabling much better code in custom looping constructs, a fairly common practice); a few of us were discussing that on Saturday and it's at least possible in theory as long as we're calling into a context that can do the compilation for us. It's still definitely at the "wouldn't it be cool if..." stage though, whereas we're much closer to C generation for simple bytecode. 2x faster is evolutionary. 10x faster is revolutionary. Donal. |