I was hanging out on the perl developer''s IRC channel today, and the topic of providing dtrace support for perl came up, specifically how to provide a ustack helper. I''d already read John Levon''s blog post on how he did this for python (http://blogs.sun.com/levon/entry/python_and_dtrace_in_build), and I saw the following comment from Bryan: "Unfortunately, ustack helpers are impossible for environments like Ruby and Perl, so Python and Java (and PHP if the helper were ever integrated) may stand alone for quite some time to come..." I assume this is because of the difficulty of unwinding the interpreter stacks of Perl and Ruby - I don''t know about Ruby, but Perl doesn''t use the C stack for holding the Perl-level stack, it maintains its own stack (in fact, several of them). I''m wondering if the following scheme might be a solution. If the perl interpreter detects it is running under dtrace it builds a ''shadow'' stack which it adjusts on each interpreter frame entry/exit - basically a simple array containing perl source file name, line number and subroutine name. The D stack helper becomes simple - it just reads the info from the shadow stack, rather than having to try to untangle the real interpreter stack. The other problem is that the code which calls the ustack helper (http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/uts/common/dtrace/dtrace.c#5306) calls the helper once for each C stack frame - and in perl there is no direct relationship between the number of C stack frames and the number of interpreter stack frames. We would need to be able to iterate depending on the number of interpreter stack frames, not the number of C stack frames. My first thought would be to add a new D primitive - astack (application stack). This would take one argument, which would be 1 on the first call, and 0 on subsequent calls. The astack helper would return a string on each call, as per ustack, and return null to indicate that it had finished. To prevent endless loops, a maximum number of iterations would be enforced (via a D pragma?) The only other wrinkle (pointed out by John Levon) is dealing with threads - we would need a separate shadow stack for each thread, which means the code that maintains the shadow stacks needs some way of sharing a value (ideally a 0-based index) with the stack helper code. And I don''t know enough about dtrace to fully understand how the per-thread D variable ''self'' is allocated, or if it is accessible from userland. Is there any merit in this idea, or have I missed some glaring problem? -- Alan Burlison --
> I was hanging out on the perl developer''s IRC channel today, and the > topic of providing dtrace support for perl came up, specifically how to > provide a ustack helper. I''d already read John Levon''s blog post on how > he did this for python > (http://blogs.sun.com/levon/entry/python_and_dtrace_in_build), and I saw > the following comment from Bryan: > > "Unfortunately, ustack helpers are impossible for environments like Ruby > and Perl, so Python and Java (and PHP if the helper were ever > integrated) may stand alone for quite some time to come..." > > I assume this is because of the difficulty of unwinding the interpreter > stacks of Perl and Ruby - I don''t know about Ruby, but Perl doesn''t use > the C stack for holding the Perl-level stack, it maintains its own stack > (in fact, several of them). > > I''m wondering if the following scheme might be a solution. > > If the perl interpreter detects it is running under dtrace [ ... ]That''s the essence of the problem (or at least a substantial component of it) -- and the reason for my assertion that ustack helpers are currently impossible for environments like Perl: Perl isn''t "running under DTrace" when one often wishes to use a ustack helper, and the Perl interpreter has no way of knowing that DTrace is running. Indeed, many DTrace enablings where ustack is particularly useful are using low-level instrumentation like: dtrace -n io:::start''{@[ustack(20, 8192)] = count()}''> it builds a > ''shadow'' stack which it adjusts on each interpreter frame entry/exit - > basically a simple array containing perl source file name, line number > and subroutine name. The D stack helper becomes simple - it just reads > the info from the shadow stack, rather than having to try to untangle > the real interpreter stack.This doesn''t sound like a helper -- it sounds like an is-enabled probe that builds the stack and passes it as a string argument.> The other problem is that the code which calls the ustack helper > (http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/uts/common/dtrace/dtrace.c#5306) > calls the helper once for each C stack frame - and in perl there is no > direct relationship between the number of C stack frames and the number > of interpreter stack frames. We would need to be able to iterate > depending on the number of interpreter stack frames, not the number of C > stack frames.Yes, that would be the other problem. ;)> My first thought would be to add a new D primitive - astack (application > stack). This would take one argument, which would be 1 on the first > call, and 0 on subsequent calls. The astack helper would return a string > on each call, as per ustack, and return null to indicate that it had > finished. To prevent endless loops, a maximum number of iterations would > be enforced (via a D pragma?)There are no looping primitives in D; for a ustack helper, the iteration logic is in DTrace, not the helper.> The only other wrinkle (pointed out by John Levon) is dealing with > threads - we would need a separate shadow stack for each thread, which > means the code that maintains the shadow stacks needs some way of > sharing a value (ideally a 0-based index) with the stack helper code.And that would be another problem. ;)> And I don''t know enough about dtrace to fully understand how the > per-thread D variable ''self'' is allocated, or if it is accessible from > userland.It''s effectively an alias for an associative array keyed by the thread identifier, and no, it''s not accessible from userland.> Is there any merit in this idea, or have I missed some glaring problem?You mean yet _another_ glaring problem? ;) I really think the better route here is to have an is-enabled probe on, say, Perl function entry and return that collects a stack. This will allow one to get some of the benefit of the ustack helper (and indeed, all of the benefit if one is debugging Perl exclusively), without having to pay the substantial cost that a ustack helper must pay to execute in arbitrary context -- especially because Perl likely can''t get a stack trace in arbitrary context anyway. If nothing else, an is-enabled probe would be a good start -- and for that matter, it would be good to first focus on getting some useful probes either integrated into Perl (ideally) or at least integrated into the OpenSolaris distribution of Perl... - Bryan -------------------------------------------------------------------------- Bryan Cantrill, Solaris Kernel Development. http://blogs.sun.com/bmc
Bryan Cantrill wrote:>> If the perl interpreter detects it is running under dtrace [ ... ] > > That''s the essence of the problem (or at least a substantial component > of it) -- and the reason for my assertion that ustack helpers are currently > impossible for environments like Perl: Perl isn''t "running under DTrace" > when one often wishes to use a ustack helper, and the Perl interpreter > has no way of knowing that DTrace is running. Indeed, many DTrace enablings > where ustack is particularly useful are using low-level instrumentation > like: > > dtrace -n io:::start''{@[ustack(20, 8192)] = count()}''Yeah, I see what you are saying - the shadow stack would need to be built by perl in userland, but you don''t know in advance when a D script (at some arbitrary point in the kernel) is going to require it - an you can''t magically reach across and get it built after the fact. This is unlike a process stack.>> it builds a >> ''shadow'' stack which it adjusts on each interpreter frame entry/exit - >> basically a simple array containing perl source file name, line number >> and subroutine name. The D stack helper becomes simple - it just reads >> the info from the shadow stack, rather than having to try to untangle >> the real interpreter stack. > > This doesn''t sound like a helper -- it sounds like an is-enabled probe > that builds the stack and passes it as a string argument.Yes.>> My first thought would be to add a new D primitive - astack (application >> stack). This would take one argument, which would be 1 on the first >> call, and 0 on subsequent calls. The astack helper would return a string >> on each call, as per ustack, and return null to indicate that it had >> finished. To prevent endless loops, a maximum number of iterations would >> be enforced (via a D pragma?) > > There are no looping primitives in D; for a ustack helper, the iteration > logic is in DTrace, not the helper.Yes, I know, which is why the proposal was for DTrace to do the iteration, subject to some sort of bound.> I really think the better route here is to have an is-enabled probe on, > say, Perl function entry and return that collects a stack. This will allow > one to get some of the benefit of the ustack helper (and indeed, all of the > benefit if one is debugging Perl exclusively), without having to pay the > substantial cost that a ustack helper must pay to execute in arbitrary > context -- especially because Perl likely can''t get a stack trace in > arbitrary context anyway. If nothing else, an is-enabled probe would be > a good start -- and for that matter, it would be good to first focus on > getting some useful probes either integrated into Perl (ideally) or at > least integrated into the OpenSolaris distribution of Perl...The OSX perl maintainer has already done some of this (just the entry/exit probes I think), based on my prototype of quite some time ago. The perl gatekeeper is interested in getting it integrated into perl proper. The stack trace thing is the obvious missing bit. Ah well, it was just a thought... -- Alan Burlison --
> > I really think the better route here is to have an is-enabled probe on, > > say, Perl function entry and return that collects a stack. This will allow > > one to get some of the benefit of the ustack helper (and indeed, all of the > > benefit if one is debugging Perl exclusively), without having to pay the > > substantial cost that a ustack helper must pay to execute in arbitrary > > context -- especially because Perl likely can''t get a stack trace in > > arbitrary context anyway. If nothing else, an is-enabled probe would be > > a good start -- and for that matter, it would be good to first focus on > > getting some useful probes either integrated into Perl (ideally) or at > > least integrated into the OpenSolaris distribution of Perl... > > The OSX perl maintainer has already done some of this (just the > entry/exit probes I think), based on my prototype of quite some time > ago. The perl gatekeeper is interested in getting it integrated into > perl proper. The stack trace thing is the obvious missing bit. > > Ah well, it was just a thought...And I think it''s a good thought -- I just think that a ustack helper is the wrong path. I would add an additional probe -- function-entry-stack or something -- that fires after function-entry and gives you a full string stack backtrace as an argument. This would have the added bonus that (with some slightly gross string manipulation) one could use them in predicates -- something we can''t do with ustack today. Incidentally, I think we''re going to see more of this (is-enabled probes with language-specific semantics), especially as users of higher-level languages wish to use DTrace to get at/aggregate on function arguments... - Bryan -------------------------------------------------------------------------- Bryan Cantrill, Solaris Kernel Development. http://blogs.sun.com/bmc