[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