Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8308614

Enabling JVMTI ClassLoad event slows down vthread creation by factor 10

XMLWordPrintable

    • b27
    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      Linux x64
      OpenJDK Runtime Environment (build 21-ea+23-1988)
      OpenJDK 64-Bit Server VM (build 21-ea+23-1988, mixed mode, sharing)

      A DESCRIPTION OF THE PROBLEM :
      Enabling class load or similar events slows down vthread creation by factor 10 compared to just enabling JVMTI, even when no classes are loaded anymore. Enabling JVMTI alone is only a factor two compared to running without JVMTI. Adding or not adding the can_support_virtual_threads capability does not matter.

      Some timing with the attached sample:

      $JAVA_HOME/bin/java VThreadClassLoad
      duration: 1205 ms

      LD_LIBRARY_PATH=. $JAVA_HOME/bin/java -agentlib:VThreadClassLoad=noevent VThreadClassLoad
      vthread capability added
      class load event not enabled
      duration: 2506 ms

      LD_LIBRARY_PATH=. $JAVA_HOME/bin/java -agentlib:VThreadClassLoad VThreadClassLoad
      vthread capability added
      class load event enabled
      duration: 36212 ms

      LD_LIBRARY_PATH=. $JAVA_HOME/bin/java -agentlib:VThreadClassLoad=nocap VThreadClassLoad
      vthread capability not added
      class load event enabled
      duration: 36043 ms

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      With the attached sample and JAVA_HOME set to a JDK 21:

      g++ -shared -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -fPIC VThreadClassLoad.cpp -o libVThreadClassLoad.so
      $JAVA_HOME/bin/javac VThreadClassLoad.java

      LD_LIBRARY_PATH=. $JAVA_HOME/bin/java -agentlib:VThreadClassLoad VThreadClassLoad




      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Timings roughly similar to just enabling JVMTI
      ACTUAL -
      Timings more than 10 times slower than just enabling JVMTI

      ---------- BEGIN SOURCE ----------
      VThreadClassLoad.java ------------------------------------------
      import java.time.Duration;
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;

      public class VThreadClassLoad {
          public static void main(String[] args) {
              for (int i=0; i<3; i++) {
                  work(); // warmup
              }
              long startTime = System.nanoTime();
              work();
              System.out.println("duration: " + Duration.ofNanos(System.nanoTime() - startTime).toMillis() + " ms");
          }

          private static void work() {
              try (ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor()) {
                  for (int i = 0; i < 10_000_000; i++) {
                      executorService.execute(() -> {});
                  }
              }
          }
      }
      ------------------------------------------------------
      VThreadClassLoad.cpp -----------------------------
      #include <jvmti.h>
      #include <cstdlib>
      #include <cstring>
      #include <vector>

      namespace {
          jvmtiEnv *jvmti = nullptr;

          void checkJvmti(int code, const char* message) {
              if (code != JVMTI_ERROR_NONE) {
                  printf("Error %s: %d\n", message, code);
                  abort();
              }
          }

          void JNICALL classLoad(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, jclass klass) {
          }
      }

      extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
          if (vm->GetEnv(reinterpret_cast<void **>(&jvmti), JVMTI_VERSION) != JNI_OK || !jvmti) {
              printf("Could not initialize JVMTI\n");
              abort();
          }
          if (options && strstr(options, "nocap")) {
              printf("vthread capability not added\n");
      } else {
      jvmtiCapabilities capabilities;
      memset(&capabilities, 0, sizeof(capabilities));
      capabilities.can_support_virtual_threads = 1;
      checkJvmti(jvmti->AddCapabilities(&capabilities), "adding capabilities");
              printf("vthread capability added\n");
      }

          if (options && strstr(options, "noevent")) {
              printf("class load event not enabled\n");
          } else {
              jvmtiEventCallbacks callbacks;
              memset(&callbacks, 0, sizeof(callbacks));
              callbacks.ClassLoad = &classLoad;
              checkJvmti(jvmti->SetEventCallbacks(&callbacks, (jint)sizeof(callbacks)), "setting callbacks");
              checkJvmti(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, nullptr), "enabling class load event");
              printf("class load event enabled\n");
          }
          fflush(stdout);
          return JVMTI_ERROR_NONE;
      }
      ---------------------------------------

      ---------- END SOURCE ----------

      FREQUENCY : always


            sspitsyn Serguei Spitsyn
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            8 Start watching this issue

              Created:
              Updated:
              Resolved: