diff -r fd16c54261b3 -r 90ce3da70b43 jdk/test/demo/jvmti/Context.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/demo/jvmti/Context.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,183 @@ +/* + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* + * + * Sample target application for jvmti demos + * + * java Context [threadCount [iterationCount [sleepContention]]] + * Default: java Context 5 10 0 + * + * threadCount Number of threads + * iterationCount Total turns taken for all threads + * sleepContention Time for main thread to sleep while holding lock + * (creates monitor contention on all other threads) + * + */ + +/* Used to sync up turns and keep track of who's turn it is */ +final class TurnChecker { + int thread_index; + TurnChecker(int thread_index) { + this.thread_index = thread_index; + } +} + +/* Creates a bunch of threads that sequentially take turns */ +public final class Context extends Thread { + /* Used to track threads */ + private static long startTime; + private static TurnChecker turn = new TurnChecker(-1); + private static int total_turns_taken; + + /* Used for each Context thread */ + private final int thread_count; + private final int thread_index; + private final int thread_turns; + + /* Main program */ + public static void main(String[] argv) throws InterruptedException { + int default_thread_count = 5; + int default_thread_turns = 10; + int default_contention_sleep = 0; + int expected_turns_taken; + long sleepTime = 10L; + + /* Override defaults */ + if ( argv.length >= 1 ) { + default_thread_count = Integer.parseInt(argv[0]); + } + if ( argv.length >= 2 ) { + expected_turns_taken = Integer.parseInt(argv[1]); + default_thread_turns = expected_turns_taken/default_thread_count; + } + expected_turns_taken = default_thread_count*default_thread_turns; + if ( argv.length >= 3 ) { + default_contention_sleep = Integer.parseInt(argv[2]); + } + + System.out.println("Context started with " + + default_thread_count + " threads and " + + default_thread_turns + " turns per thread"); + + /* Get all threads running (they will block until we set turn) */ + for (int i = 0; i < default_thread_count; i++) { + new Context(default_thread_count, i, default_thread_turns).start(); + } + + /* Sleep to make sure thread_index 0 make it to the wait call */ + System.out.println("Context sleeping, so threads will start wait"); + Thread.yield(); + Thread.sleep(sleepTime); + + /* Save start time */ + startTime = System.currentTimeMillis(); + + /* This triggers the starting of taking turns */ + synchronized (turn) { + turn.thread_index = 0; + turn.notifyAll(); + } + System.out.println("Context sleeping, so threads can run"); + Thread.yield(); + Thread.sleep(sleepTime); + + /* Wait for threads to finish (after everyone has had their turns) */ + while ( true ) { + boolean done; + done = false; + synchronized (turn) { + if ( total_turns_taken == expected_turns_taken ) { + done = true; + } + /* Create some monitor contention by sleeping with lock */ + if ( default_contention_sleep > 0 ) { + System.out.println("Context sleeping, to create contention"); + Thread.yield(); + Thread.sleep((long)default_contention_sleep); + } + } + if ( done ) + break; + System.out.println("Context sleeping, so threads will complete"); + Thread.sleep(sleepTime); + } + + long endTime = System.currentTimeMillis(); + long totalTime = endTime - startTime; + + System.out.println("Total time (milliseconds): " + totalTime); + System.out.println("Milliseconds per thread: " + + ((double)totalTime / (default_thread_count))); + + System.out.println("Context completed"); + System.exit(0); + } + + /* Thread object to run */ + Context(int thread_count, int thread_index, int thread_turns) { + this.thread_count = thread_count; + this.thread_index = thread_index; + this.thread_turns = thread_turns; + } + + /* Main for thread */ + public void run() { + int next_thread_index = (thread_index + 1) % thread_count; + int turns_taken = 0; + + try { + + /* Loop until we make sure we get all our turns */ + for (int i = 0; i < thread_turns * thread_count; i++) { + synchronized (turn) { + /* Keep waiting for our turn */ + while (turn.thread_index != thread_index) + turn.wait(); + /* MY TURN! Each thread gets thread_turns */ + total_turns_taken++; + turns_taken++; + System.out.println("Turn #" + total_turns_taken + + " taken by thread " + thread_index + + ", " + turns_taken + + " turns taken by this thread"); + /* Give next thread a turn */ + turn.thread_index = next_thread_index; + turn.notifyAll(); + } + /* If we've had all our turns, break out of this loop */ + if ( thread_turns == turns_taken ) { + break; + } + } + } catch (InterruptedException intEx) { /* skip */ } + + /* Make sure we got all our turns */ + if ( thread_turns != turns_taken ) { + System.out.println("ERROR: thread got " + turns_taken + + " turns, expected " + thread_turns); + System.exit(1); + } + } +}