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

Runtime.availableProcessors() ignores Linux taskset command

    Details

    • Subcomponent:
    • Resolved In Build:
      b107
    • CPU:
      x86
    • OS:
      linux, solaris_8

      Backports

        Description

        FULL PRODUCT VERSION :
        java version "1.6.0"
        Java(TM) SE Runtime Environment (build 1.6.0-b105)
        Java HotSpot(TM) 64-Bit Server VM (build 1.6.0-b105, mixed mode)

        ADDITIONAL OS VERSION INFORMATION :
        #1 SMP Tue Aug 29 10:40:40 UTC 2006 x86_64 x86_64 x86_64 GNU/Linux

        A DESCRIPTION OF THE PROBLEM :
        When limiting the available CPUs by Linux 'taskset' command, JVM obeys this limitation but Runtime.availableProcessors() always returns the number of CPUs where the hardware has.


        REPRODUCIBILITY :
        This bug can be reproduced always.

          Issue Links

            Activity

            Hide
            dholmes David Holmes added a comment -
            > I thought that the cpus are numbered 0 to 1023, but the maximum count is 1024.

            I thought so to, but the discussion refers to a 1023 maximum for some reason.

            > Using _SC_NPROCESSORS_CONF instead of _SC_NPROCESSORS_ONLN is quite reasonable, but then there's a new fear - that the former could be a very large integer
            > (who knows how many cpus can be added at runtime?) that was also discussed in the libc-alpha thread.

            My testing on small systems shows that configured and online cpus seem to be the same (in the past I'm sure some platforms used to report some hardwired maximum - 1024 or something, which would be bad as it would force us down the dynamic path.) Further, as all I want to do is count the cpus not create per-cpu data structures (as referenced in the discussion) it is only the CPU_ALLOC that I need to worry about. At one bit per cpu I'm not allocating very much.

            > Adding new hardware (including CPUS) while the system is running is apparently quite common on IBM mainframes - "zero downtime" is an enterprise feature!

            Sure, but it all depends on the details of the architecture (and OS) as to whether that would be considered a change in configured processors, or a change in online processors.

            Anyway one step at a time. Right now we want Docker cpu sets to work correctly. :) Maybe next year we need to worry about 1024+ processors

            Thanks.
            Show
            dholmes David Holmes added a comment - > I thought that the cpus are numbered 0 to 1023, but the maximum count is 1024. I thought so to, but the discussion refers to a 1023 maximum for some reason. > Using _SC_NPROCESSORS_CONF instead of _SC_NPROCESSORS_ONLN is quite reasonable, but then there's a new fear - that the former could be a very large integer > (who knows how many cpus can be added at runtime?) that was also discussed in the libc-alpha thread. My testing on small systems shows that configured and online cpus seem to be the same (in the past I'm sure some platforms used to report some hardwired maximum - 1024 or something, which would be bad as it would force us down the dynamic path.) Further, as all I want to do is count the cpus not create per-cpu data structures (as referenced in the discussion) it is only the CPU_ALLOC that I need to worry about. At one bit per cpu I'm not allocating very much. > Adding new hardware (including CPUS) while the system is running is apparently quite common on IBM mainframes - "zero downtime" is an enterprise feature! Sure, but it all depends on the details of the architecture (and OS) as to whether that would be considered a change in configured processors, or a change in online processors. Anyway one step at a time. Right now we want Docker cpu sets to work correctly. :) Maybe next year we need to worry about 1024+ processors Thanks.
            Hide
            dholmes David Holmes added a comment -
            Here is the new version of the code. I will send out a RFR without the testing code soon.

            // Get the current number of available processors for this process.
            // This value can change at any time during a process's lifetime.
            // sched_getaffinity gives an accurate answer as it accounts for cpusets.
            // If it appears there may be more than 1024 processors then we do a
            // dynamic check - see 6515172 for details.
            // If anything goes wrong we fallback to returning the number of online
            // processors - which can be greater than the number available to the process.
            int os::active_processor_count() {
              cpu_set_t cpus; // can represent at most 1024 (CPU_SETSIZE) processors
              cpu_set_t* cpus_p = &cpus;
              int cpus_size = sizeof(cpu_set_t);

              int configured_cpus = processor_count(); // upper bound on available cpus
              int cpu_count = 0;

              if (configured_cpus >= CPU_SETSIZE || UseNewCode) {
                // kernel may use a mask bigger than cpu_set_t
                log_trace(os)("active_processor_count: using dynamic path - configured processors: %d",
                              configured_cpus);
                cpus_p = CPU_ALLOC(configured_cpus);
                if (cpus_p != NULL && !UseNewCode2) {
                  cpus_size = CPU_ALLOC_SIZE(configured_cpus);
                  // zero it just to be safe
                  CPU_ZERO_S(cpus_size, cpus_p);
                }
                else {
                   // failed to allocate so fallback to online cpus
                   int online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN);
                   log_trace(os)("active_processor_count: "
                                 "CPU_ALLOC failed (%s) - using "
                                 "online processor count: %d",
                                 strerror(errno), online_cpus);
                   return online_cpus;
                }
              }
              else {
                log_trace(os)("active_processor_count: using static path - configured processors: %d",
                              configured_cpus);
              }
                   
              // pid 0 means the current thread - which we have to assume represents the process
              if (sched_getaffinity(0, cpus_size, cpus_p) == 0 && !UseNewCode3) {
                if (cpus_p != &cpus) {
                  cpu_count = CPU_COUNT_S(cpus_size, cpus_p);
                }
                else {
                  cpu_count = CPU_COUNT(cpus_p);
                }
                log_trace(os)("active_processor_count: sched_getaffinity processor count: %d", cpu_count);
              }
              else {
                cpu_count = ::sysconf(_SC_NPROCESSORS_ONLN);
                warning("sched_getaffinity failed (%s)- using online processor count (%d) "
                        "which may exceed available processors", strerror(errno), cpu_count);
              }

              if (cpus_p != &cpus) {
                CPU_FREE(cpus_p);
              }

              assert(cpu_count > 0 && cpu_count <= processor_count(), "sanity check");
              return cpu_count;
            }
            Show
            dholmes David Holmes added a comment - Here is the new version of the code. I will send out a RFR without the testing code soon. // Get the current number of available processors for this process. // This value can change at any time during a process's lifetime. // sched_getaffinity gives an accurate answer as it accounts for cpusets. // If it appears there may be more than 1024 processors then we do a // dynamic check - see 6515172 for details. // If anything goes wrong we fallback to returning the number of online // processors - which can be greater than the number available to the process. int os::active_processor_count() {   cpu_set_t cpus; // can represent at most 1024 (CPU_SETSIZE) processors   cpu_set_t* cpus_p = &cpus;   int cpus_size = sizeof(cpu_set_t);   int configured_cpus = processor_count(); // upper bound on available cpus   int cpu_count = 0;   if (configured_cpus >= CPU_SETSIZE || UseNewCode) {     // kernel may use a mask bigger than cpu_set_t     log_trace(os)("active_processor_count: using dynamic path - configured processors: %d",                   configured_cpus);     cpus_p = CPU_ALLOC(configured_cpus);     if (cpus_p != NULL && !UseNewCode2) {       cpus_size = CPU_ALLOC_SIZE(configured_cpus);       // zero it just to be safe       CPU_ZERO_S(cpus_size, cpus_p);     }     else {        // failed to allocate so fallback to online cpus        int online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN);        log_trace(os)("active_processor_count: "                      "CPU_ALLOC failed (%s) - using "                      "online processor count: %d",                      strerror(errno), online_cpus);        return online_cpus;     }   }   else {     log_trace(os)("active_processor_count: using static path - configured processors: %d",                   configured_cpus);   }           // pid 0 means the current thread - which we have to assume represents the process   if (sched_getaffinity(0, cpus_size, cpus_p) == 0 && !UseNewCode3) {     if (cpus_p != &cpus) {       cpu_count = CPU_COUNT_S(cpus_size, cpus_p);     }     else {       cpu_count = CPU_COUNT(cpus_p);     }     log_trace(os)("active_processor_count: sched_getaffinity processor count: %d", cpu_count);   }   else {     cpu_count = ::sysconf(_SC_NPROCESSORS_ONLN);     warning("sched_getaffinity failed (%s)- using online processor count (%d) "             "which may exceed available processors", strerror(errno), cpu_count);   }   if (cpus_p != &cpus) {     CPU_FREE(cpus_p);   }   assert(cpu_count > 0 && cpu_count <= processor_count(), "sanity check");   return cpu_count; }
            Hide
            hgupdate HG Updates added a comment -
            URL: http://hg.openjdk.java.net/jdk9/hs-rt/hotspot/rev/c5480d4abfe4
            User: dholmes
            Date: 2016-01-29 12:29:24 +0000
            Show
            hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk9/hs-rt/hotspot/rev/c5480d4abfe4 User: dholmes Date: 2016-01-29 12:29:24 +0000
            Hide
            hgupdate HG Updates added a comment -
            URL: http://hg.openjdk.java.net/jdk9/jdk9/hotspot/rev/c5480d4abfe4
            User: lana
            Date: 2016-02-24 20:06:28 +0000
            Show
            hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk9/jdk9/hotspot/rev/c5480d4abfe4 User: lana Date: 2016-02-24 20:06:28 +0000
            Hide
            dholmes David Holmes added a comment -
            This fix also needs the fix for JDK-8161993, which in turn requires JDK-8147910.
            Show
            dholmes David Holmes added a comment - This fix also needs the fix for JDK-8161993 , which in turn requires JDK-8147910 .

              People

              • Assignee:
                dholmes David Holmes
                Reporter:
                ndcosta Nelson Dcosta
              • Votes:
                0 Vote for this issue
                Watchers:
                14 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:
                  Imported:
                  Indexed: