JDK-6673124 : Runtime.availableProcessors / os::active_processor_count wrong if unused processor sets exist
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 6u4,7
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris,solaris_10
  • CPU: generic
  • Submitted: 2008-03-09
  • Updated: 2017-05-19
  • Resolved: 2011-03-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7 Other
6u11-revFixed 7Fixed hs11.1Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
The code for active_processor_count, used by Runtime.availableProcessors() is as follows:

int os::active_processor_count() {
  int online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
  pid_t pid = getpid();
  psetid_t pset = PS_NONE;
  // Are we running in a processor set?
  if (pset_bind(PS_QUERY, P_PID, pid, &pset) == 0) {
    if (pset != PS_NONE) {
      uint_t pset_cpus;
      // Query number of cpus in processor set
      if (pset_info(pset, NULL, &pset_cpus, NULL) == 0) {
	assert(pset_cpus > 0 && pset_cpus <= online_cpus, "sanity check");
	_processors_online = pset_cpus;
	return pset_cpus;
      }
    }
  }
  // Otherwise return number of online cpus
  return online_cpus;
}

This code correctly queries if the current process is being executed in a processor set, but incorrectly ignores the possibility that a processor set exists which is not being used by the VM. For example, if a system has active 32 processors and 8 have been dedicated to a processor set (not used by the VM) then the current code will report 32 available processors when it should report 24.

While this is simple to fix (remove the check for (pset != PS_NONE)) there are compatability concerns here because applications which have been tuned based on the incorrect value returned by availableProcessors(), will suddenly behave differently if the correct value is returned. 

Also note that while the code supports processor sets, it does not support pools - something that might need to be addressed in the future.

In the real-time VM we have also discovered that if threads within the VM are bound to specific processor sets (not used by the VM as a whole) then the pset_bind(PS_QUERY, PPID, ...) call can return incorrect results. While not an issue for current HS, it may be an issue if native code tries to manipulate thread bindings directly, or if the VM is embedded in a process that uses processor bindings for threads that attach to the VM.

Finally, the use of the _processors_online global needs to re-examined. It's use seems to be related to a 1.3.1 issue relating to early Solaris versions that are hopefully now anicent history.
A flag will be needed to restore the current broken behaviour to address the compatability issue.
Should be prominently documented in release notes to point out compatibility
issue pointed out above.
Note the comment re pools above is not correct. The code does account for pools correctly because when pools are active sysconf(_SC_NPROCESSORS_ONLN) returns the current number of processors in the processor-set of the pool.

Comments
EVALUATION http://hg.openjdk.java.net/jdk7/hotspot-rt/hotspot/rev/fad66fdcb7fc
06-10-2008

EVALUATION See description section for the fix.
18-09-2008

SUGGESTED FIX Remove the check for PSET_NONE so that pset_info provides either the number of bound cpus in the given processor set, or else the number of unbound cpus on the system. int os::active_processor_count() { int online_cpus = sysconf(_SC_NPROCESSORS_ONLN); pid_t pid = getpid(); psetid_t pset = PS_NONE; // Are we running in a processor set? if (pset_bind(PS_QUERY, P_PID, pid, &pset) == 0) { - if (pset != PS_NONE) { uint_t pset_cpus; // Query number of cpus in processor set if (pset_info(pset, NULL, &pset_cpus, NULL) == 0) { assert(pset_cpus > 0 && pset_cpus <= online_cpus, "sanity check"); _processors_online = pset_cpus; return pset_cpus; } - } } // Otherwise return number of online cpus return online_cpus; }
09-03-2008