[PATCH 0 of 3] Add support for dtrace compatible sdt probes on GNU/Linux

serguei.spitsyn at oracle.com serguei.spitsyn at oracle.com
Wed Jul 18 11:57:15 PDT 2012


On 7/18/12 11:41 AM, serguei.spitsyn at oracle.com wrote:
> On 7/18/12 10:23 AM, Mark Wielaard wrote:
>> On Wed, Jul 18, 2012 at 10:10:43AM -0700,serguei.spitsyn at oracle.com  wrote:
>>> This work includes investigation to find proper linux machine,
>>> installation of the systemTap, building and testing, and so,
>>> needs some engineering resources.
>> I can do that, the patch has already been included in various
>> distros so it shouldn't be a problem. Just let me know what you
>> need.
>>
>>> Also, it needs a new unit test and submitting a CCC request.
>>> You only can help by providing a test for the patch.
>> Sure, I was looking for existing dtrace tests to see if I can
>> match them. Do you have a good example I can follow?
>>
>> Thanks,
>>
>> Mark
>
> Normally a dtrace test needs 4 parts:
>   java test program, d-script, shell script and README
>
> All automated dtrace tests usually depend on the SQE testbase 
> environment:
>    .cfg file, testbase libraries and testbase build system
>
> So that, I do not have a simple standalone test for the HotSpot probes.
> But I can provide an example (just make a correction on this kind of 
> dependency).
>
> The test ThreadLifecycle001 includes ThreadLifecycle.d,

Need to complete the sentence above:
   The test ThreadLifecycle001 includes ThreadLifecycle.d, 
ThreadLifecycle001.cfg,
   ThreadLifecycle001.java, ThreadLifecycle001.pl and 
ThreadLifecycle001.README


Thanks,
Serguei

>
>
> Please, see below and let me know if you have any questions.
> I can send you more examples if needed.
>
> Thanks,
> Serguei
>
>
> % cat ThreadLifecycle.d
>
> #!/usr/sbin/dtrace -Zs
>
> #pragma D option quiet
> #pragma D option destructive
>
> /* %W% %G%
>  * Copyright %G% Sun Microsystems, Inc.
>  */
>
> /*
>  * The script trace hotspot:::thread-start and hotspot:::thread-stop 
> events.
>  */
>
> self char *str_ptr;
> self string thread_name;
>
> :::BEGIN {
>     TEST_NAME = "Thread lifecycle";
>     TEST_PASS = 1;
>
>     EXIT_CODE_PASS = 0;
>     EXIT_CODE_FAIL = 1;
>
>     printf("BEGIN %s probes testing\n\n", TEST_NAME);
> }
>
> /*
>  * hotspot:::thread-start, hotspot:::thread-stop probe arguments:
>  *  arg0: char*,        thread name passed as UTF8 string
>  *  arg1: uintptr_t,    thread name length
>  *  arg2: uintptr_t,    Java thread id
>  *  arg3: uintptr_t,    native/OS thread id
>  *  arg4: uintptr_t,    is a daemon or not
>  */
>
> /* Check is_daemon is correct */
> hotspot$target:::thread-start,
> hotspot$target:::thread-stop
> / arg4 > 1 /
> {
>     TEST_PASS = 0;
>
>     printf("FAIL: wrong is_daemon=%u is passed in %s\n",
>         arg4, probename);
> }
>
> hotspot$target:::thread-start
> {
>     THREAD_START_CNT ++;
> }
>
> hotspot$target:::thread-stop
> {
>     THREAD_STOP_CNT ++;
> }
>
> hotspot$target:::thread-start,
> hotspot$target:::thread-stop
> {
>     /* Yes, we copy for one byte more from user space. This is 
> temporal solution till support for
>      * not-null terminated strings will be donein DTRACE
>      */
>     self->str_ptr = (char*) copyin(arg0, arg1+1);
>     self->str_ptr[arg1] = '\0';
>     self->thread_name = (string) self->str_ptr;
>
>     printf("\nPROBE ARGS: %s:\n", probename);
>     printf("PROBE ARGS:   arg0=%p (thread name pointer)\n", arg0);
>     printf("PROBE ARGS:   arg1=%u (thread name length)\n", arg1);
>     printf("PROBE ARGS:   arg2=%u (Java thread id)\n", arg2);
>     printf("PROBE ARGS:   arg3=%u (native/OS id)\n", arg3);
>     printf("PROBE ARGS:   arg4=%u (is daemon)\n", arg4);
>
>     /* this output will be used by Perl script */
>     printf("%s: id=%u, is_daemon=%u, name=%s\n",
>             probename, arg2, arg4, self->thread_name);
> }
>
> /* check exit status of traced java process */
> syscall::rexit:entry
> /pid == $target && arg0 != 0 && arg0 != 95 /
> {
>     printf("\n");
>     printf("ERROR: java process failed with status=%d\n", arg0);
>     TEST_PASS = 0;
> }
>
> syscall::rexit:entry
> /pid == $target && !THREAD_START_CNT/
> {
>     printf("ERROR: no 'thread-start' probes were fired\n");
>     TEST_PASS = 0;
> }
>
> syscall::rexit:entry
> /pid == $target && !THREAD_STOP_CNT/
> {
>     printf("ERROR: no 'thread-stop' probes were fired\n");
>     TEST_PASS = 0;
> }
>
> syscall::rexit:entry
> /pid == $target && !TEST_PASS/
> {
>     printf("FAIL\n");
>     exit(EXIT_CODE_FAIL);
> }
>
> syscall::rexit:entry
> /pid == $target && TEST_PASS/
> {
>     printf("PASS\n");
>     exit(EXIT_CODE_PASS);
> }
>
> :::END {
>     printf("\nEND %s tracing\n", TEST_NAME);
> }
>
>
> sspitsyn at hsdev-10 more *.* | cat
> ::::::::::::::
> ThreadLifecycle001.cfg
> ::::::::::::::
> # %W% %G%
> # Copyright %G% Sun Microsystems, Inc.
>
>
> DSCRIPT=${TESTBASE}/src/dtrace/share/dscripts/hotspot/ThreadLifecycle.d
>
> EXECUTE_CLASS=dtrace.hotspot.ThreadLifecycle.ThreadLifecycle001.ThreadLifecycle001
>
> export DSCRIPT
> export JAVA
> export JAVA_OPTS
> export TESTDIR
> export TEST_ARGS
> export EXECUTE_CLASS
> export TESTBASE
> export TESTARGS
>
> DTRACE_RESULTS_ANALYZER_SCRIPT=${TESTBASE}/src/dtrace/hotspot/ThreadLifecycle/ThreadLifecycle001/ThreadLifecycle001.pl
> export DTRACE_RESULTS_ANALYZER_SCRIPT
>
> TONGA_EXECUTE=$PERL ${TESTBASE}/src/dtrace/share/run_dtrace.pl
>
>
> ::::::::::::::
> ThreadLifecycle001.java
> ::::::::::::::
> /* %W% %G%
>  * Copyright %G% Sun Microsystems, Inc.
>  */
>
> package dtrace.hotspot.ThreadLifecycle.ThreadLifecycle001;
>
> import java.lang.*;
>
> class NewThread extends Thread
> {
>     volatile private boolean stop = false;
>     private boolean started = false;
>
>     public NewThread(ThreadGroup group, String name)
>     {
>         super(group, name);
>     }
>
>     public void run()
>     {
>         synchronized(this) { started = true; }
>
>         while (!stop)
>         {
>             for (int i=0; i<100; i++);
>         }
>     }
>
>
>     synchronized public boolean isStarted()
>     {
>         return started;
>     }
>
>     public void terminate()
>     {
>         stop = true;
>     }
> }
>
>
> public class ThreadLifecycle001
> {
>     public static void main(String[] args)
>     {
>         System.out.println("ThreadLifecycle001 test");
>
>         // create and start NewThread
>         ThreadGroup newGroup = new ThreadGroup("newGroup");
>         NewThread newThread = new NewThread(newGroup, "NewThread");
>         newThread.start();
>
>         ThreadGroup parentGroup = Thread.currentThread().getThreadGroup();
>         if (parentGroup == null)
>             return;
>
>         while (parentGroup.getParent() != null)
>         {
>             parentGroup = parentGroup.getParent();
>         }
>
>         // wait if newThread is not yet started
>         while (!newThread.isStarted())
>         {
>             for (int i = 0; i < 100; i++);
>         }
>
>         System.out.println();
>         listThreads(parentGroup);
>
>         newThread.terminate();
>         try
>         {
>             newThread.join();
>         }
>         catch(InterruptedException ex) {}
>     }
>
>     static void listThreads(ThreadGroup currentGroup)
>     {
>         int threadCount = currentGroup.activeCount();
>         Thread listOfThreads[] = new Thread[threadCount];
>
>         currentGroup.enumerate(listOfThreads, true);
>         for (int i = 0; i < threadCount; i++)
>         {
>             System.out.println(
>                 "Thread: id=" + listOfThreads[i].getId() +
>                 ", is_daemon=" + (listOfThreads[i].isDaemon() ? "1" : 
> "0") +
>                 ", name=" + listOfThreads[i].getName() +
>                 ", groupName=" + 
> listOfThreads[i].getThreadGroup().getName() );
>         }
>     }
> }
>
>
> ::::::::::::::
> ThreadLifecycle001.pl
> ::::::::::::::
> # %W% %G%
> # Copyright %G% Sun Microsystems, Inc.
> #
> # Implement analyze_dtrace_results_proc function for 
> ThreadLifecycle001 test.
> #
>
> sub analyze_dtrace_results_proc($$$)
> {
>     my ($dtrace_log_filename, $java_log_filename, $args) = @_;
>
>     my $test_fail = 0;
>     my %java_threads = ();          # threads started according to 
> Java log file
>     my %dtrace_start_threads = ();  # threads started according to 
> hotspot:::thread-start probes
>     my %dtrace_stop_threads = ();  # threads started according to 
> hotspot:::thread-start probes
>
>     if ( &read_java_log($java_log_filename, \%java_threads) ||
>          &read_dtrace_log($dtrace_log_filename, 
> \%dtrace_start_threads, \%dtrace_stop_threads) )
>     {
>         return 1;
>     }
>
>     # Check that all probes have been fired
>     foreach (keys %java_threads)
>     {
>         unless (exists $dtrace_start_threads{$_}) {
>             print STDOUT "ERROR: no 'thread-start' probe was fired for 
> thread: $_\n";
>             $test_fail = 1;
>         }
>
>         unless (exists $dtrace_stop_threads{$_}) {
>             print STDOUT "ERROR: no 'thread-stop' probe was fired for 
> thread: $_\n";
>             $test_fail = 1;
>         }
>     }
>
>     # check that 'thread-start' probes have been fired exactly 1 time 
> for each thread
>     foreach (keys %dtrace_start_threads) {
>         if ($dtrace_start_threads{$_} > 1) {
>             print STDOUT "ERROR: 'thread-start' probe for '$_' fired " .
>                 $dtrace_start_threads{$_} . " (>1) times\n";
>             $test_fail = 1;
>         }
>     }
>
>     # check that 'thread-stop' probes have been fired exactly 1 time 
> for each thread
>     foreach (keys %dtrace_stop_threads) {
>         if ($dtrace_stop_threads{$_} > 1) {
>             print STDOUT "ERROR: 'thread-stop' probe for '$_' fired " .
>                 $dtrace_stop_threads{$_} . " (>1) times\n";
>             $test_fail = 1;
>         }
>     }
>
>     return $test_fail;
> }
>
> sub read_java_log($$)
> {
>     my ($java_log_filename, $java_threads) = @_;
>
>     unless (open(IN, "<$java_log_filename"))
>     {
>         print STDOUT "Failed to read $java_log_filename: $!\n";
>         return 1;
>     }
>
>     while(my $str = <IN>)
>     {
>         $str =~ s/\r*\n//;
>
>         if ($str =~ s/^Thread: //)
>         {
>             # thread group name is not passed in dtrace probes, so 
> delete it
>             $str =~ s/, groupName=.*$//;
>
>             $java_threads->{$str} ++;
>         }
>     }
>
>     close(IN);
>     return 0;
> }
>
> sub read_dtrace_log($$$)
> {
>     my ($dtrace_log_filename, $dtrace_start_threads, 
> $dtrace_stop_threads) = @_;
>
>     unless (open(IN, "<$dtrace_log_filename"))
>     {
>         print STDOUT "Failed to read $java_log_filename: $!\n";
>         return 1;
>     }
>
>     my $probe_name;
>     while(my $str = <IN>)
>     {
>         $str =~ s/\r*\n//;
>
>         if ($str =~ s/^thread-start: //)
>         {
>             $dtrace_start_threads->{$str} ++;
>         }
>         elsif ($str =~ s/^thread-stop: //)
>         {
>             $dtrace_stop_threads->{$str} ++;
>         }
>     }
>
>     close(IN);
>     return 0;
> }
>
> 1;
>
> ::::::::::::::
> ThreadLifecycle001.README
> ::::::::::::::
> %W% %G%
> Copyright %G% Sun Microsystems, Inc.
>
> DESCRIPTION
>
>     The test exercise hotspot:::thread-start and hotspot:::thread-stop 
> Dtrace probes functionality.
>
>     The test do:
>     - run ThreadLifecycle001 java programm which dumps information abould
>       all running threads in VM.
>     - check if:
>       - for each Java thread thread-start and thread-stop probes are 
> fired the same time
>       - input probe's arguments are passed correctly
>         (attempt to print them doesn't cause the error)
>       - no any Dtrace errors are thrown
>
> COMMENTS
>
> AUTHOR
>  . . .
>
>
>
>


-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/serviceability-dev/attachments/20120718/03c0bad3/attachment-0001.html 


More information about the serviceability-dev mailing list