1 /* 2 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 40 41 #include "hprof.h" 42 43 /* This file contains the cpu loop for the option cpu=samples */ 44 45 /* The cpu_loop thread basically waits for gdata->sample_interval millisecs 46 * then wakes up, and for each running thread it gets their stack trace, 47 * and updates the traces with 'hits'. 48 * 49 * No threads are suspended or resumed, and the thread sampling is in the 50 * file hprof_tls.c, which manages all active threads. The sampling 51 * technique (what is sampled) is also in hprof_tls.c. 52 * 53 * No adjustments are made to the pause time or sample interval except 54 * by the user via the interval=n option (default is 10ms). 55 * 56 * This thread can cause havoc when started prematurely or not terminated 57 * properly, see cpu_sample_init() and cpu_term(), and their calls in hprof_init.c. 58 * 59 * The listener loop (hprof_listener.c) can dynamically turn on or off the 60 * sampling of all or selected threads. 61 * 62 */ 63 64 /* Private functions */ 65 66 static void JNICALL 67 cpu_loop_function(jvmtiEnv *jvmti, JNIEnv *env, void *p) 68 { 69 int loop_trip_counter; 70 jboolean cpu_loop_running; 71 72 loop_trip_counter = 0; 73 74 rawMonitorEnter(gdata->cpu_loop_lock); { 75 gdata->cpu_loop_running = JNI_TRUE; 76 cpu_loop_running = gdata->cpu_loop_running; 77 /* Notify cpu_sample_init() that we have started */ 78 rawMonitorNotifyAll(gdata->cpu_loop_lock); 79 } rawMonitorExit(gdata->cpu_loop_lock); 80 81 rawMonitorEnter(gdata->cpu_sample_lock); /* Only waits inside loop let go */ 82 83 while ( cpu_loop_running ) { 84 85 ++loop_trip_counter; 86 87 LOG3("cpu_loop()", "iteration", loop_trip_counter); 88 89 /* If a dump is in progress, we pause sampling. */ 90 rawMonitorEnter(gdata->dump_lock); { 91 if (gdata->dump_in_process) { 92 gdata->pause_cpu_sampling = JNI_TRUE; 93 } 94 } rawMonitorExit(gdata->dump_lock); 95 96 /* Check to see if we need to pause sampling (listener_loop command) */ 97 if (gdata->pause_cpu_sampling) { 98 99 /* 100 * Pause sampling for now. Reset sample controls if 101 * sampling is resumed again. 102 */ 103 104 rawMonitorWait(gdata->cpu_sample_lock, 0); 105 106 rawMonitorEnter(gdata->cpu_loop_lock); { 107 cpu_loop_running = gdata->cpu_loop_running; 108 } rawMonitorExit(gdata->cpu_loop_lock); 109 110 /* Continue the while loop, which will terminate if done. */ 111 continue; 112 } 113 114 /* This is the normal short timed wait before getting a sample */ 115 rawMonitorWait(gdata->cpu_sample_lock, (jlong)gdata->sample_interval); 116 117 /* Make sure we really want to continue */ 118 rawMonitorEnter(gdata->cpu_loop_lock); { 119 cpu_loop_running = gdata->cpu_loop_running; 120 } rawMonitorExit(gdata->cpu_loop_lock); 121 122 /* Break out if we are done */ 123 if ( !cpu_loop_running ) { 124 break; 125 } 126 127 /* 128 * If a dump request came in after we checked at the top of 129 * the while loop, then we catch that fact here. We 130 * don't want to perturb the data that is being dumped so 131 * we just ignore the data from this sampling loop. 132 */ 133 rawMonitorEnter(gdata->dump_lock); { 134 if (gdata->dump_in_process) { 135 gdata->pause_cpu_sampling = JNI_TRUE; 136 } 137 } rawMonitorExit(gdata->dump_lock); 138 139 /* Sample all the threads and update trace costs */ 140 if ( !gdata->pause_cpu_sampling) { 141 tls_sample_all_threads(env); 142 } 143 144 /* Check to see if we need to finish */ 145 rawMonitorEnter(gdata->cpu_loop_lock); { 146 cpu_loop_running = gdata->cpu_loop_running; 147 } rawMonitorExit(gdata->cpu_loop_lock); 148 149 } 150 rawMonitorExit(gdata->cpu_sample_lock); 151 152 rawMonitorEnter(gdata->cpu_loop_lock); { 153 /* Notify cpu_sample_term() that we are done. */ 154 rawMonitorNotifyAll(gdata->cpu_loop_lock); 155 } rawMonitorExit(gdata->cpu_loop_lock); 156 157 LOG2("cpu_loop()", "clean termination"); 158 } 159 160 /* External functions */ 161 162 void 163 cpu_sample_init(JNIEnv *env) 164 { 165 gdata->cpu_sampling = JNI_TRUE; 166 167 /* Create the raw monitors needed */ 168 gdata->cpu_loop_lock = createRawMonitor("HPROF cpu loop lock"); 169 gdata->cpu_sample_lock = createRawMonitor("HPROF cpu sample lock"); 170 171 rawMonitorEnter(gdata->cpu_loop_lock); { 172 createAgentThread(env, "HPROF cpu sampling thread", 173 &cpu_loop_function); 174 /* Wait for cpu_loop_function() to notify us it has started. */ 175 rawMonitorWait(gdata->cpu_loop_lock, 0); 176 } rawMonitorExit(gdata->cpu_loop_lock); 177 } 178 179 void 180 cpu_sample_off(JNIEnv *env, ObjectIndex object_index) 181 { 182 jint count; 183 184 count = 1; 185 if (object_index != 0) { 186 tls_set_sample_status(object_index, 0); 187 count = tls_sum_sample_status(); 188 } 189 if ( count == 0 ) { 190 gdata->pause_cpu_sampling = JNI_TRUE; 191 } else { 192 gdata->pause_cpu_sampling = JNI_FALSE; 193 } 194 } 195 196 void 197 cpu_sample_on(JNIEnv *env, ObjectIndex object_index) 198 { 199 if ( gdata->cpu_loop_lock == NULL ) { 200 cpu_sample_init(env); 201 } 202 203 if (object_index == 0) { 204 gdata->cpu_sampling = JNI_TRUE; 205 gdata->pause_cpu_sampling = JNI_FALSE; 206 } else { 207 jint count; 208 209 tls_set_sample_status(object_index, 1); 210 count = tls_sum_sample_status(); 211 if ( count > 0 ) { 212 gdata->pause_cpu_sampling = JNI_FALSE; 213 } 214 } 215 216 /* Notify the CPU sampling thread that sampling is on */ 217 rawMonitorEnter(gdata->cpu_sample_lock); { 218 rawMonitorNotifyAll(gdata->cpu_sample_lock); 219 } rawMonitorExit(gdata->cpu_sample_lock); 220 221 } 222 223 void 224 cpu_sample_term(JNIEnv *env) 225 { 226 gdata->pause_cpu_sampling = JNI_FALSE; 227 rawMonitorEnter(gdata->cpu_sample_lock); { 228 /* Notify the CPU sampling thread to get out of any sampling Wait */ 229 rawMonitorNotifyAll(gdata->cpu_sample_lock); 230 } rawMonitorExit(gdata->cpu_sample_lock); 231 rawMonitorEnter(gdata->cpu_loop_lock); { 232 if ( gdata->cpu_loop_running ) { 233 gdata->cpu_loop_running = JNI_FALSE; 234 /* Wait for cpu_loop_function() thread to tell us it completed. */ 235 rawMonitorWait(gdata->cpu_loop_lock, 0); 236 } 237 } rawMonitorExit(gdata->cpu_loop_lock); 238 }