Has anyone every called dtrace in a perl script? I don''t care about instrumenting perl at all. What I want to do is make a script that calls a dtrace script, does a bunch of things, kills dtrace and returns. Right now I''m trying to fork and call dtrace. However, when I try to send SIGINT to the child it doesn''t kill dtrace... Any ideas? I think dtrace may not even be fully started before SIGINT is called, but I''m not sure how to coordinate the two. Here''s my code: #!/usr/bin/perl print "Welcome to the script\n"; my $pid = fork(); if(not defined $pid){ #fork failed print ''Fork failed on resources :(\n''; }elsif ($pid==0) { #In child process print "Starting DTrace\n"; exec("dtrace -s pageTrace.d > traceOut.txt"); print "DTrace finished\n"; } else { #In parent process print "do work\n"; #Stop the DTrace process kill(''SIGINT'',$pid); } #Done print "Script finished\n"; Thanks! -- This message posted from opensolaris.org
On 20 Feb 2008, at 20:53, David Meisner wrote:> print "Starting DTrace\n"; > exec("dtrace -s pageTrace.d > traceOut.txt"); > print "DTrace finished\n";It probably has nothing to do with your problem - but exec never returns so the second message will never appear. If you want to do something after dtrace use system() and then later exit() instead. You must make sure that the forked process doesn''t fall off the end of its conditional and execute a second copy of the main program. You can easily forkbomb yourself like that. -- Andy Armstrong, Hexten
David Meisner wrote: > Here''s my code: > > > #!/usr/bin/perl > > print "Welcome to the script\n"; > > my $pid = fork(); > > if(not defined $pid){ > > #fork failed > print ''Fork failed on resources :(\n''; > > }elsif ($pid==0) { > > #In child process > > print "Starting DTrace\n"; > exec("dtrace -s pageTrace.d > traceOut.txt"); > print "DTrace finished\n"; My perl is a bit rusty, but exec is not going to return. Ever. I might fail, but if it succeeds then it never returns. The following print will only be executed in error. > > } else { > > #In parent process > > print "do work\n"; > > #Stop the DTrace process > kill(''SIGINT'',$pid); You''re racing to this signal. The aforementioned exec may or may not have executed. You might kill the child process while it is still perl. The child process may have even completed and returned already. You are obviously calling dtrace because you want it to do something. Is there a reason you can''t have dtrace exit all by it''s lonesome? Perhaps the solution would be easier if you provided and outline of the dtrace script you want to use. donour
> Has anyone every called dtrace in a perl script? I don''t care about instrumenting perl at all. What I want to do is make a script that calls a dtrace script, does a bunch of things, kills dtrace and returns. Right now I''m trying to fork and call dtrace. However, when I try to send SIGINT to the child it doesn''t kill dtrace... Any ideas? I think dtrace may not even be fully started before SIGINT is called, but I''m not sure how to coordinate the two.Here is an example that worked for me sub get_dtrace_data { local *DTRACE; # Collect some DTrace data. my $collect_time = DCOLLECTTIME . ''s''; my $time_ns = DCOLLECTTIME * NANOSEC; ###################################################################### # DTrace Blob # # The profile provider tick probe is used to time the script. The tick probe may # fire before the specified interval if someone else had it enable, so make sure # that the required interval have actually passed. If the tick probe fires too # early, use a backup 1-sec tick probe to check whether it is time to bail out. # my $dtrace = <<END_OF_DTRACE; /usr/sbin/dtrace -n '' #pragma D option quiet /* record the script start time */ dtrace:::BEGIN { start = timestamp; } ... your script here /* Exit when collection time expires */ profile:::tick-$collect_time, profile:::tick-1s /timestamp - start >= $time_ns/ { exit(0); } END { print something } '' END_OF_DTRACE # # End of DTrace blob ###################################################################### # # Now run the DTrace script above and get the last line of the output. # Convert it to the { pid, tid, count } triplet. # open(DTRACE,"$dtrace |") || warn(-1, "can not start dtrace: $!\n"); my $migration_data = (); # Collect data generated by DTrace while (<DTRACE>) { chomp; # Trim end of line next unless $_; # Skip empty lines # Extract device name, device instance and CPU ID. # We are done with DTrace close(DTRACE) or warn(-1, "can not complete dtrace: $!\n"); return $_; }
Yeah I thought that may be happening. What I''m trying to do is run a set off commands and just watch virtual memory probes (write them to a file). I don''t really want to stop until I''m all done and I guess I haven''t really thought through how many time I''ll call the commands. Is there a way to do it without thinking about the calls apriori? -- This message posted from opensolaris.org
OK well here''s my solution. And yes I realize this is a terrible TERRIBLE hack. But nothing else has worked so far.... Also this clearly won''t work with another instance of dtrace running. #!/usr/bin/perl print "Welcome to the script\n"; #Make sure DTrace isn''t running `pkill dtrace`; my $pid = fork(); if(not defined $pid){ #fork failed print ''Fork failed on resources :(\n''; }elsif ($pid==0) { #In child process print "Starting DTrace\n"; exec(''dtrace -s pageTrace.d > traceOut.txt''); } else { #In parent process print "Waiting for DTrace to start\n"; $dtraceRunning = 0; while(!$dtraceRunning){ $dtraceRunning = `ps -A|grep dtrace`; sleep(1); } print $dtraceRunning."\n"; print "Doing stuffn"; #Stop the DTrace process `pkill dtrace`; } #Done print "Script finished\n"; -- This message posted from opensolaris.org
On 20 Feb 2008, at 22:33, David Meisner wrote:> OK well here''s my solution. And yes I realize this is a terrible > TERRIBLE hack. But nothing else has worked so far.... Also this > clearly won''t work with another instance of dtrace running. > > #!/usr/bin/perl > > print "Welcome to the script\n"; > > > #Make sure DTrace isn''t running > `pkill dtrace`; > > my $pid = fork(); > > if(not defined $pid){ > > #fork failed > print ''Fork failed on resources :(\n''; > > }elsif ($pid==0) { > > #In child process > > print "Starting DTrace\n"; > exec(''dtrace -s pageTrace.d > traceOut.txt''); > > } else { > > #In parent process > > print "Waiting for DTrace to start\n"; > > $dtraceRunning = 0; > while(!$dtraceRunning){ > $dtraceRunning = `ps -A|grep dtrace`; > sleep(1); > } > > print $dtraceRunning."\n"; > > print "Doing stuffn"; > > > #Stop the DTrace process > `pkill dtrace`;Why are you killing dtrace after it stopped running anyway? I originally assumed you were trying to kill a dtrace script that didn''t terminate. Can you clarify: do you want the Perl program to wait for dtrace to terminate or not? -- Andy Armstrong, Hexten
On 20 Feb 2008, at 22:42, David Meisner wrote:> The first kill is just a safe guard. After that I kill it because > the script doesn''t terminate by itself. This works, its just not > pretty.OK, I''m still missing something. The dtrace script terminates without intervention, right? Is there any reason why you can''t just system(''dtrace -s pageTrace.d > traceOut.txt''); I''m not sure why you''re forking. If you /do/ need to fork the parent process should probably wait for the child to terminate using waitpid() so that it gets to reap the child correctly. But more context would be good please :) -- Andy Armstrong, Hexten
On 20 Feb 2008, at 22:50, David Meisner wrote:> ok, the dtrace script will not terminate by itself. Furthermore, > system will not return until the dtrace finishes, which it won''t by > itself. So I''m forking so I can run commands while the script is > running and then kill it later. Does that make sense?Yes :) The problem is that when you use an IO redirection in the argument to exec Perl has to use /bin/sh to run the command you give it - and it''s /bin/sh that handles the redirection. So you end up with perl \- sh \- dtrace But the PID you have is for sh. When you ask sh nicely to exit (SIGINT) it doesn''t want to because it''s running another process (dtrace). So you could either find the PID of the dtrace process and kill that or send SIGKILL to sh which causes it to kill the dtrace process. This works for me using one of the resource kit examples: #!/usr/bin/perl use strict; use warnings; my $pid = fork; die "Fork failed ($!)\n" unless defined $pid; exec ''examples/pl_flow.d > flow.log'' unless $pid; for ( 1 .. 3 ) { print "Waiting...\n"; sleep 1; } kill 9, $pid; 1 while 0 < waitpid -1, 0; It uses SIGKILL and then waits for both the child processes to die (waitpid) before itself exiting. -- Andy Armstrong, Hexten
On 20 Feb 2008, at 23:19, Andy Armstrong wrote:> This works for me using one of the resource kit examples:No it doesn''t - it fails to kill the dtrace process. Sorry. So you need to find the PID of dtrace and send SIGINT to that directly. -- Andy Armstrong, Hexten
On 20 Feb 2008, at 23:22, Andy Armstrong wrote:> No it doesn''t - it fails to kill the dtrace process. Sorry. > > So you need to find the PID of dtrace and send SIGINT to that > directly.Or just cheat and do the IO redirection in Perl :) #!/usr/bin/perl use strict; use warnings; my $pid = fork; die "Fork failed ($!)\n" unless defined $pid; unless ( $pid ) { open my $log, ''>'', ''flow.log'' or die "Can''t write log ($!)\n"; open my $dt, ''-|'', ''examples/pl_flow.d'' or die "Can''t run dtrace ($!)\n"; print $log $_ while <$dt>; exit; } for ( 1 .. 3 ) { print "Waiting...\n"; sleep 1; } kill 9, $pid; 1 while 0 < waitpid -1, 0; -- Andy Armstrong, Hexten