• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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