1 /* 2 * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 This test case to test the following: 26 27 GetCurrentThreadCpuTime 28 GetThreadCpuTime 29 GetTime 30 */ 31 32 #define VARIANCE (0.10) 33 #define VARIANCE_PERCENT (VARIANCE * 100.0) 34 35 #include <stdio.h> 36 #include <string.h> 37 #include "jvmti.h" 38 #include "agent_common.h" 39 40 #include "jni_tools.h" 41 42 extern "C" { 43 44 #define JVMTI_ERROR_CHECK_DURING_ONLOAD(str,res) if ( res != JVMTI_ERROR_NONE) { printf("Fatal error: %s - %d\n", str, res); return JNI_ERR; } 45 46 #define JVMTI_ERROR_CHECK_RETURN(str,res) if ( res != JVMTI_ERROR_NONE) { printf("Error: %s - %d\n", str, res); return; } 47 48 #define JVMTI_ERROR_CHECK(str,res) if ( res != JVMTI_ERROR_NONE) { printf("Error: %s - %d\n", str, res); } 49 50 #define THREADS_LIMIT 200 51 52 53 jvmtiEnv *jvmti; 54 jint iGlobalStatus = 0; 55 jthread susp_thrd[THREADS_LIMIT]; 56 static jvmtiEventCallbacks callbacks; 57 static jvmtiCapabilities capabilities; 58 jrawMonitorID jraw_monitor[20]; 59 jlong initial_time; 60 61 struct ThreadInfo { 62 jint iterationCount; 63 jlong currThreadTime; 64 jlong threadTime; 65 jweak ref; 66 } thread_info[THREADS_LIMIT]; 67 68 int printdump = 1; 69 70 71 void debug_printf(const char *fmt, ...) { 72 va_list args; 73 74 va_start(args, fmt); 75 if (printdump) { 76 vprintf(fmt, args); 77 } 78 va_end(args); 79 } 80 81 void JNICALL vmInit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) { 82 jvmtiError err; 83 char buffer[32]; 84 85 debug_printf("VMInit event\n"); 86 87 debug_printf("jvmti GetTime \n"); 88 err = jvmti_env->GetTime(&initial_time); 89 JVMTI_ERROR_CHECK("GetTime", err); 90 debug_printf(" Initial time: %s ns\n", 91 jlong_to_string(initial_time, buffer)); 92 } 93 94 void JNICALL vmExit(jvmtiEnv *jvmti_env, JNIEnv *env) { 95 debug_printf("VMDeath event\n"); 96 } 97 98 99 void init_callbacks() { 100 memset((void *)&callbacks, 0, sizeof(jvmtiEventCallbacks)); 101 callbacks.VMInit = vmInit; 102 callbacks.VMDeath = vmExit; 103 } 104 105 106 #ifdef STATIC_BUILD 107 JNIEXPORT jint JNICALL Agent_OnLoad_JvmtiTest(JavaVM *jvm, char *options, void *reserved) { 108 return Agent_Initialize(jvm, options, reserved); 109 } 110 JNIEXPORT jint JNICALL Agent_OnAttach_JvmtiTest(JavaVM *jvm, char *options, void *reserved) { 111 return Agent_Initialize(jvm, options, reserved); 112 } 113 JNIEXPORT jint JNI_OnLoad_JvmtiTest(JavaVM *jvm, char *options, void *reserved) { 114 return JNI_VERSION_1_8; 115 } 116 #endif 117 jint Agent_Initialize(JavaVM * jvm, char *options, void *reserved) { 118 jint res; 119 jvmtiError err; 120 121 if (options && strlen(options) > 0) { 122 if (strstr(options, "printdump")) { 123 printdump = 1; 124 } 125 } 126 127 res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); 128 if (res < 0) { 129 printf("Wrong result of a valid call to GetEnv!\n"); 130 return JNI_ERR; 131 } 132 133 134 /* Add capabilities */ 135 memset(&capabilities, 0, sizeof(jvmtiCapabilities)); 136 capabilities.can_get_current_thread_cpu_time = 1; 137 capabilities.can_get_thread_cpu_time = 1; 138 err = jvmti->AddCapabilities(&capabilities); 139 JVMTI_ERROR_CHECK_DURING_ONLOAD("(AddCapabilities)", err); 140 141 /* Enable events */ 142 init_callbacks(); 143 res = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 144 JVMTI_ERROR_CHECK_DURING_ONLOAD("SetEventCallbacks returned error", res); 145 146 res = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL); 147 JVMTI_ERROR_CHECK_DURING_ONLOAD("SetEventNotificationMode for VM_INIT returned error", res); 148 149 res = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL); 150 JVMTI_ERROR_CHECK_DURING_ONLOAD("SetEventNotificationMode for vm death event returned error", res); 151 152 return JNI_OK; 153 } 154 155 156 JNIEXPORT jint JNICALL 157 Java_nsk_jvmti_unit_timers_JvmtiTest_GetResult(JNIEnv * env, jclass cls) { 158 return iGlobalStatus; 159 } 160 161 #define milli(x) ((x)/(1000L * 1000L)) 162 163 JNIEXPORT void JNICALL 164 Java_nsk_jvmti_unit_timers_JvmtiTest_RegisterCompletedThread(JNIEnv * env, 165 jclass cls, jthread thread, jint threadNumber, jint iterationCount) { 166 jvmtiError ret; 167 jlong curr; 168 169 debug_printf("jvmti GetCurrentThreadCpuTime \n"); 170 ret = jvmti->GetCurrentThreadCpuTime(&curr); 171 JVMTI_ERROR_CHECK_RETURN("GetCurrentThreadCpuTime", ret); 172 173 thread_info[threadNumber].iterationCount = iterationCount; 174 thread_info[threadNumber].currThreadTime = curr; 175 thread_info[threadNumber].ref = env->NewWeakGlobalRef(thread); 176 } 177 178 static void print_timerinfo(jvmtiTimerInfo* timerInfo) { 179 char buffer[32]; 180 const char* timerKind; 181 switch(timerInfo->kind) { 182 case JVMTI_TIMER_USER_CPU: 183 timerKind = "JVMTI_TIMER_USER_CPU"; 184 break; 185 case JVMTI_TIMER_TOTAL_CPU: 186 timerKind = "JVMTI_TIMER_TOTAL_CPU"; 187 break; 188 case JVMTI_TIMER_ELAPSED: 189 timerKind = "JVMTI_TIMER_ELAPSED_CPU"; 190 break; 191 default: 192 timerKind = "<unknown>"; 193 break; 194 } 195 debug_printf(" Max = %s [%s %s] kind = %s\n", 196 jlong_to_string(timerInfo->max_value, buffer), 197 timerInfo->may_skip_forward? "skip-forward" : "stable", 198 timerInfo->may_skip_backward? "skip-backward" : "stable", 199 timerKind); 200 } 201 202 JNIEXPORT void JNICALL 203 Java_nsk_jvmti_unit_timers_JvmtiTest_Analyze(JNIEnv * env, jclass cls) { 204 jvmtiError ret; 205 jlong now; 206 jlong etime; 207 jint thrCnt; 208 jvmtiTimerInfo timerInfoCurr; 209 jvmtiTimerInfo timerInfoOther; 210 jvmtiTimerInfo timerInfoTime; 211 jint processor_count; 212 jint totalIter = 0; 213 jlong totalTimeCurr = 0; 214 jlong totalTime = 0; 215 jlong possibleTime; 216 double one_iter_cost; 217 jthread *thrArray; 218 int k; 219 int i; 220 char buffer[32]; 221 222 debug_printf("jvmti GetTime \n"); 223 ret = jvmti->GetTime(&now); 224 JVMTI_ERROR_CHECK_RETURN("GetTime", ret); 225 etime = now - initial_time; 226 debug_printf(" Elapsed time: %s ms\n", 227 jlong_to_string(milli(etime), buffer)); 228 229 debug_printf("jvmti GetCurrentThreadCpuTimerInfo \n"); 230 ret = jvmti->GetCurrentThreadCpuTimerInfo(&timerInfoCurr); 231 JVMTI_ERROR_CHECK_RETURN("GetCurrentThreadCpuTimerInfo", ret); 232 print_timerinfo(&timerInfoCurr); 233 234 debug_printf("jvmti GetThreadCpuTimerInfo \n"); 235 ret = jvmti->GetThreadCpuTimerInfo(&timerInfoOther); 236 JVMTI_ERROR_CHECK_RETURN("GetThreadCpuTimerInfo", ret); 237 print_timerinfo(&timerInfoOther); 238 239 debug_printf("jvmti GetTimerInfo \n"); 240 ret = jvmti->GetTimerInfo(&timerInfoTime); 241 JVMTI_ERROR_CHECK_RETURN("GetTimerInfo", ret); 242 print_timerinfo(&timerInfoTime); 243 244 debug_printf("jvmti GetAvailableProcessors \n"); 245 ret = jvmti->GetAvailableProcessors(&processor_count); 246 JVMTI_ERROR_CHECK_RETURN("GetAvailableProcessors", ret); 247 debug_printf(" processor_count = %d\n", processor_count); 248 249 debug_printf("jvmti GetAllThreads \n"); 250 ret = jvmti->GetAllThreads(&thrCnt, &thrArray); 251 JVMTI_ERROR_CHECK_RETURN("GetAllThreads", ret); 252 253 for (k = 0; k < thrCnt; ++k) { 254 jlong oth; 255 jthread thread; 256 257 thread = thrArray[k]; 258 ret = jvmti->GetThreadCpuTime(thread, &oth); 259 JVMTI_ERROR_CHECK_RETURN("GetThreadCpuTime", ret); 260 261 for (i = 1; i < THREADS_LIMIT; ++i) { 262 jweak tref = thread_info[i].ref; 263 if (tref != 0) { 264 if (env->IsSameObject(thread, tref)) { 265 thread_info[i].threadTime = oth; 266 break; 267 } 268 } 269 } 270 if (i == THREADS_LIMIT) { 271 jvmtiThreadInfo info; 272 info.name = (char*) "*retrieval error*"; 273 ret = jvmti->GetThreadInfo(thread, &info); 274 JVMTI_ERROR_CHECK("GetThreadInfo %d \n", ret); 275 276 debug_printf("non-test thread: %s - %s ms\n", info.name, 277 jlong_to_string(milli(oth), buffer)); 278 } 279 } 280 for (i = 1; i < THREADS_LIMIT; ++i) { 281 jweak tref = thread_info[i].ref; 282 if (tref != 0) { 283 totalIter += thread_info[i].iterationCount; 284 totalTimeCurr += thread_info[i].currThreadTime; 285 totalTime += thread_info[i].threadTime; 286 } 287 } 288 possibleTime = etime * processor_count; 289 debug_printf("Totals -- \n"); 290 debug_printf(" Iter = %d\n", totalIter); 291 debug_printf(" Total GetThreadCpuTime = %s ns", jlong_to_string(totalTime, buffer)); 292 debug_printf(" %s ms\n", jlong_to_string(milli(totalTime), buffer)); 293 debug_printf(" Total GetCurrentThreadCpuTimerInfo = %s ns", jlong_to_string(totalTimeCurr, buffer)); 294 debug_printf(" %s ms\n", jlong_to_string(milli(totalTimeCurr), buffer)); 295 debug_printf(" GetTime = %s ns", jlong_to_string(etime, buffer)); 296 debug_printf(" %s ms\n", jlong_to_string(milli(etime), buffer)); 297 debug_printf(" GetTime * processor_count = %s ns", jlong_to_string(possibleTime, buffer)); 298 debug_printf(" %s ms\n", jlong_to_string(milli(possibleTime), buffer)); 299 if (totalTime <= possibleTime) { 300 debug_printf("Pass: ttime <= possible_time\n"); 301 } else { 302 printf("FAIL: ttime > possible_time\n"); 303 iGlobalStatus = 2; 304 } 305 if (totalTimeCurr <= totalTime) { 306 debug_printf("Pass: ttime_curr <= ttime\n"); 307 } else { 308 printf("FAIL: ttime_curr > ttime\n"); 309 iGlobalStatus = 2; 310 } 311 if (totalTimeCurr >= totalTime*(1-VARIANCE)) { 312 debug_printf("Pass: ttime_curr >= %2.0f%% of ttime\n", 100.0 - VARIANCE_PERCENT); 313 } else { 314 printf("FAIL: ttime_curr < %2.0f%% of ttime\n", 100.0 - VARIANCE_PERCENT); 315 iGlobalStatus = 2; 316 } 317 one_iter_cost = (double)totalTime / totalIter; 318 debug_printf("CURRENT: total time returned by \"GetCurrentThreadCpuTime\".\n"); 319 debug_printf("OTHER: total time returned by \"GetThreadCpuTime\".\n"); 320 debug_printf("EXPECT: the expected time if TestThread.run() had a proportional cost across all threads.\n"); 321 debug_printf("%% DIFF: how much \"Expect\" is off by.\n"); 322 debug_printf("THREAD ITERATIONS CURRENT OTHER EXPECT % DIFF\n"); 323 for (i = 1; i < THREADS_LIMIT; ++i) { 324 jweak tref = thread_info[i].ref; 325 if (tref != 0) { 326 jint ic = thread_info[i].iterationCount; 327 jlong ctt = thread_info[i].currThreadTime; 328 jlong tt = thread_info[i].threadTime; 329 double expt = ic * one_iter_cost; 330 double var = 100.0 * ((double)tt - expt) / expt; 331 debug_printf("%6d %10d %5s ms", i, ic, 332 jlong_to_string(milli(ctt), buffer)); 333 debug_printf(" %5s ms %5.0f ms %7.1f%%\n", 334 jlong_to_string(milli(tt), buffer), milli(expt), var); 335 if (ctt <= tt) { 336 debug_printf("Pass: currThreadTime <= threadTime\n"); 337 } else { 338 printf("FAIL: currThreadTime > threadTime\n"); 339 iGlobalStatus = 2; 340 } 341 { 342 int passed = ctt >= tt*(1-VARIANCE); 343 #ifdef _WIN32 344 // On Windows the timer is only accurate to within 15ms. This sometimes triggers 345 // failures if the expected max variance is close to or below 15ms. So we don't 346 // fail in this case. 347 if (!passed && milli(tt - ctt) <= 15) { 348 printf("Passing due to special consideration on Windows for 15ms timer accuracy\n"); 349 passed = 1; 350 } 351 #endif 352 if (passed) { 353 debug_printf("Pass: currThreadTime(" JLONG_FORMAT ") >= %2.0f%% of threadTime(" JLONG_FORMAT ")\n", 354 ctt, 100.0 - VARIANCE_PERCENT, tt); 355 } else { 356 printf("FAIL: currThreadTime(" JLONG_FORMAT ") < %2.0f%% of threadTime(" JLONG_FORMAT ")\n", 357 ctt, 100.0 - VARIANCE_PERCENT, tt); 358 iGlobalStatus = 2; 359 } 360 } 361 } 362 } 363 } 364 365 366 }