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

With dynamic compiler threads the compiler-thread count is not maintained in a thread-safe manner

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P3
    • Resolution: Not an Issue
    • Affects Version/s: 11, 12
    • Fix Version/s: 12
    • Component/s: hotspot
    • Labels:
      None
    • Subcomponent:
    • Introduced In Build:
      b11
    • Introduced In Version:
      11

      Description

      This is the code that updates the compiler thread count:

      static bool can_remove(CompilerThread *ct, bool do_it) {
        assert(UseDynamicNumberOfCompilerThreads, "or shouldn't be here");
        if (!ReduceNumberOfCompilerThreads) return false;

        AbstractCompiler *compiler = ct->compiler();
        int compiler_count = compiler->num_compiler_threads();
        bool c1 = compiler->is_c1();

        // Keep at least 1 compiler thread of each type.
        if (compiler_count < 2) return false;

        // Keep thread alive for at least some time.
        if (ct->idle_time_millis() < (c1 ? 500 : 100)) return false;

        // We only allow the last compiler thread of each type to get removed.
        jobject last_compiler = c1 ? CompileBroker::compiler1_object(compiler_count - 1)
                                   : CompileBroker::compiler2_object(compiler_count - 1);
        if (oopDesc::equals(ct->threadObj(), JNIHandles::resolve_non_null(last_compiler))) {
          if (do_it) {
            assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent.
            compiler->set_num_compiler_threads(compiler_count - 1);
          }
          return true;
        }
        return false;
      }

      We read the count initially with no lock held:

        int compiler_count = compiler->num_compiler_threads();

      we then later update the count with the lock held:

            assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent.
            compiler->set_num_compiler_threads(compiler_count - 1);

      but by this time the local variable "compiler_count" may not contain the current number of compiler threads and so we will set the wrong value. Further the count may also have changed when we use it here:

       jobject last_compiler = c1 ? CompileBroker::compiler1_object(compiler_count - 1)
                                   : CompileBroker::compiler2_object(compiler_count - 1);

      In addition there is logic to try and ensure we always keep at least one compiler thread but this seems to be executed with no locking so multiple threads can execute:

        if (compiler_count < 2) return false;

      and all see a count >=2 but then all continue to exit thus leaving zero compiler threads running.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                mdoerr Martin Doerr
                Reporter:
                dholmes David Holmes
              • Votes:
                0 Vote for this issue
                Watchers:
                3 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: