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 }