1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import java.lang.reflect.Field; 18 import java.util.Map; 19 import java.util.concurrent.atomic.AtomicInteger; 20 21 public class Main implements Runnable { 22 static final int NUMBER_OF_THREADS = 5; 23 static volatile int ops_per_thread = 1000; 24 static AtomicInteger operations_completed = new AtomicInteger(0); 25 static int[] progress = new int[NUMBER_OF_THREADS]; 26 static AtomicInteger totalStackFrames = new AtomicInteger(0); 27 static final boolean printStats = false; // True causes test to fail. 28 int index; 29 Main(int i)30 Main(int i) { 31 index = i; 32 } 33 main(String[] args)34 public static void main(String[] args) throws Exception { 35 final Thread[] threads = new Thread[NUMBER_OF_THREADS]; 36 Thread watchdog = new Thread() { 37 public void run() { 38 try { 39 if (printStats) { 40 System.out.println("ops_per_thread = " + ops_per_thread); 41 } 42 Thread.sleep(10_000); 43 if (printStats) { 44 System.out.println("Ops completed after 10 seconds: " + 45 operations_completed.get()); 46 } 47 if (operations_completed.get() < NUMBER_OF_THREADS * ops_per_thread / 2) { 48 // We're in some sort of "go slow" mode, probably gcstress. Finish early. 49 ops_per_thread /= 10; 50 } 51 if (printStats) { 52 System.out.println("ops_per_thread = " + ops_per_thread); 53 } 54 Thread.sleep(200_000); 55 System.out.print("Watchdog timed out: "); 56 for (int i = 0; i < NUMBER_OF_THREADS; ++i) { 57 System.out.print(progress[i] + ", "); 58 } 59 System.out.println(""); 60 System.err.println("Watchdog thread timed out"); 61 System.exit(1); 62 } catch (InterruptedException e) {} 63 } 64 }; 65 watchdog.start(); 66 long start_millis = System.currentTimeMillis(); 67 for (int t = 0; t < threads.length; t++) { 68 threads[t] = new Thread(new Main(t)); 69 threads[t].start(); 70 } 71 for (Thread t : threads) { 72 t.join(); 73 } 74 if (printStats) { 75 long elapsed_millis = System.currentTimeMillis() - start_millis; 76 System.out.println("Captured " + totalStackFrames + " stack frames in " + 77 elapsed_millis + "msecs"); 78 } 79 System.out.println("All joined"); 80 // Do this test after the other part to leave some time for the heap task daemon to start 81 // up. 82 test_getStackTraces(); 83 watchdog.interrupt(); 84 System.out.println("Finishing"); 85 } 86 getHeapTaskDaemon()87 static Thread getHeapTaskDaemon() throws Exception { 88 Field f = ThreadGroup.class.getDeclaredField("systemThreadGroup"); 89 f.setAccessible(true); 90 ThreadGroup systemThreadGroup = (ThreadGroup) f.get(null); 91 92 while (true) { 93 int activeCount = systemThreadGroup.activeCount(); 94 Thread[] array = new Thread[activeCount]; 95 systemThreadGroup.enumerate(array); 96 for (Thread thread : array) { 97 if (thread.getName().equals("HeapTaskDaemon") && 98 thread.getState() != Thread.State.NEW) { 99 return thread; 100 } 101 } 102 // Yield to eventually get the daemon started. 103 Thread.sleep(10); 104 } 105 } 106 test_getStackTraces()107 static void test_getStackTraces() throws Exception { 108 Thread heapDaemon = getHeapTaskDaemon(); 109 110 // Force a GC to ensure the daemon truly started. 111 Runtime.getRuntime().gc(); 112 // Check all the current threads for positive IDs. 113 Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces(); 114 for (Map.Entry<Thread, StackTraceElement[]> pair : map.entrySet()) { 115 Thread thread = pair.getKey(); 116 // Expect empty stack trace since we do not support suspending the GC thread for 117 // obtaining stack traces. See b/28261069. 118 if (thread == heapDaemon) { 119 System.out.println(thread.getName() + " depth " + pair.getValue().length); 120 } 121 } 122 } 123 test_getId()124 public void test_getId() { 125 if (Thread.currentThread().getId() <= 0) { 126 System.out.println("current thread's ID is not positive"); 127 } 128 // Check all the current threads for positive IDs. 129 Map<Thread, StackTraceElement[]> stMap = Thread.getAllStackTraces(); 130 for (Thread thread : stMap.keySet()) { 131 if (thread.getId() <= 0) { 132 System.out.println("thread's ID is not positive: " + thread.getName()); 133 } 134 totalStackFrames.addAndGet(stMap.get(thread).length); 135 } 136 } 137 run()138 public void run() { 139 for (int i = 1; i <= ops_per_thread; ++i) { 140 test_getId(); 141 operations_completed.addAndGet(1); 142 progress[index] = i; 143 } 144 System.out.println("Thread finished"); 145 } 146 } 147