1) Speed.
We are getting slower (though we're getting MUCH more feature
complete). While speed is not our number 1 priority (in fact, it's
pretty
much at the bottom of the barrel), having a zippier
tcl.pbc will improve development, as we can run the test suite faster.
(this is mainly tcl's test suite I'm talking about here.)
The problem here is that we don't know exactly where our bottlenecks
are,
where best to concentrate our optimizations. Parrot provides opcode
level
profiling, but a more helpful report for me would be based on parrot
subroutines. e.g. how much time was spent calling '__script' in the
'_tcl'
namespace? (per invocation, how many invocations, etc.)
2) implementing [trace] (http://www.tcl.tk/man/tcl8.5/TclCmd/trace.htm).
[trace] provides a way to run code before or after invocation of sub.
[1]
There's even a facility to run something before or
after each line (of Tcl) in a sub. While it would be possible to
implement
the basic functionality by wrapping existing subs in other subs,
I'm not sure that would help with
[trace info], which provides a way to report on all the traces that are
currently set. (We could hack this into a hidden global, as we do for
tcl's
ability to report on a function declaration: but that's a hack that
I'd like
to undo at some point).
...
So I was looking at these two items today and realized (as the clever
reader already has) that if there is a parrot-level way to handle
setting [traces] for parrot subroutines, then implementing #1 becomes a
simple matter of programming: walk the namespaces you're interested in
to find all the subs, and add enter/exit traces to them that keep
track of
the invocation time, and then report on program exit what you've found.
In fact, I could use partcl itself to do my own benchmarking if this
mechanism was in place.
At runtime, it would be nice to be able to declare the hooks to call pre
and post sub invocation. I propose [2] we call these:
trace_sub $P1, $P2, $I3
where $P1 is the original sub, $P2 is our invokable sub that we call
before or after, and $I3 is a parameter indicating enter, leave, etc.
$P2 here would be passed two parameters, the name of the sub that it was
being invoked on behalf of, and the type of operation that is occurring
(enter, leave, etc.)
Would also be nice to be able to declare these at compile time,
something like:
.HLL tcl, 'tcl_group'
.sub joe
.param string proc_name
.param int operation
if operation == .TRACE_ENTER goto enter
print "leaving "
goto done
enter:
print "entering "
done:
print "ing "
say proc_name
.end
.sub bob :enter joe :leave joe
say "whoa."
.end
Which would, when invoking bob(), print:
entering tcl::bob
whoa.
leaving tcl::bob
(with appropriate handwaving as to how a fully qualified procedure name
with namespace stringifies).
Thoughts? If this seems a reasonable approach, I can spec out more
opcodes,
PIR sugar, etc., to handle all the subroutine related tracing
required by
Tcl.
[1] Note that [trace] also does variable tracing for set/get/hash
access.
I think the mechanism for sub-based tracing and variable based
tracing is
going to be different, so I'm not addressing the variable based one here
(not to mention I don't need that for benchmarking).
[2] Repaint bikeshed as necessary.
--
Will "Coke" Coleda
wi...@coleda.com
Isn't that more a matter of setting a flag on the wrapping/tracing
routine than it is of whether the wrapping thing is a subroutine?
> (We could hack this into a hidden global, as we do for tcl's
> ability to report on a function declaration: but that's a hack that
> I'd like to undo at some point).
Yes, let's avoid the hidden globals.
[...]
> Thoughts? If this seems a reasonable approach, I can spec out more opcodes,
> PIR sugar, etc., to handle all the subroutine related tracing required by
> Tcl.
I like the idea. Write up a more complete proposal and we'll all review
it. A few thoughts:
- The same mechanism could be used to implement Perl 6 sub wrapping, so
keep that in mind as you're thinking through the implementation options.
Names like "trace_sub" may be too specific to one particular use.
- Runtime addition of traces/wrappers will be more important than adding
them at compile-time, considering that they're likely to be mostly used
for layering debugging/profiling/etc checks over existing code, and in
the debugger. So much more important, that I'd consider skipping the
compile-time syntax.
- I like the Perl 6 way of specifying the point in the wrapping sub
where the wrapped sub should be called better than setting up
conditionals based on an argument for the operation type. So, something
like:
.sub joe
.param pmc wrapped_sub
.param pmc orig_args
.local string proc_name
proc_name = wrapped_sub.name()
print "entering "
say proc_name
invoke_wrapped wrapped_sub, orig_args
print "leaving "
say proc_name
.end
.sub bob :wrap joe
say "whoa."
.end
(That also means you can monkey around with the args before passing them
on to the wrapped sub.)
- It should be possible both to put multiple wrappers/traces on a
subroutine, and to put wrappers around other wrappers. So these are all
possible:
.sub joe
#...
.end
.sub bob :wrap joe
#...
.end
.sub phil :wrap joe
#...
.end
.sub dave :wrap phil
#...
.end
Allison
maybe that'll help.
~jerry
so, the idea would then be:
.sub joe :wrap('bob')
.param pmc args
say "calling bob..."
invoke_wrapped args
say "returned from bob"
.end
.sub bob
say "this is bob"
.end
which outputs:
calling bob....
this is bob
returned from bob
This way, the original sub is not touched, and you just 'add' the
wrapper function.
my 2c.