class Concurrent::Utility::ProcessorCounter
@!visibility private
def available_processor_count
def available_processor_count cpu_count = processor_count.to_f quota = cpu_quota return cpu_count if quota.nil? # cgroup cpus quotas have no limits, so they can be set to higher than the # real count of cores. if quota > cpu_count cpu_count else quota end end
def compute_cpu_quota
def compute_cpu_quota if RbConfig::CONFIG["target_os"].include?("linux") if File.exist?("/sys/fs/cgroup/cpu.max") # cgroups v2: https://docs.kernel.org/admin-guide/cgroup-v2.html#cpu-interface-files cpu_max = File.read("/sys/fs/cgroup/cpu.max") return nil if cpu_max.start_with?("max ") # no limit max, period = cpu_max.split.map(&:to_f) max / period elsif File.exist?("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us") # cgroups v1: https://kernel.googlesource.com/pub/scm/linux/kernel/git/glommer/memcg/+/cpu_stat/Documentation/cgroups/cpu.txt max = File.read("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us").to_i # If the cpu.cfs_quota_us is -1, cgroup does not adhere to any CPU time restrictions # https://docs.kernel.org/scheduler/sched-bwc.html#management return nil if max <= 0 period = File.read("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us").to_f max / period end end end
def compute_cpu_shares
def compute_cpu_shares if RbConfig::CONFIG["target_os"].include?("linux") if File.exist?("/sys/fs/cgroup/cpu.weight") # cgroups v2: https://docs.kernel.org/admin-guide/cgroup-v2.html#cpu-interface-files # Ref: https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2254-cgroup-v2#phase-1-convert-from-cgroups-v1-settings-to-v2 weight = File.read("/sys/fs/cgroup/cpu.weight").to_f ((((weight - 1) * 262142) / 9999) + 2) / 1024 elsif File.exist?("/sys/fs/cgroup/cpu/cpu.shares") # cgroups v1: https://kernel.googlesource.com/pub/scm/linux/kernel/git/glommer/memcg/+/cpu_stat/Documentation/cgroups/cpu.txt File.read("/sys/fs/cgroup/cpu/cpu.shares").to_f / 1024 end end end
def compute_physical_processor_count
def compute_physical_processor_count ppc = case RbConfig::CONFIG["target_os"] when /darwin\d\d/ IO.popen("/usr/sbin/sysctl -n hw.physicalcpu", &:read).to_i when /linux/ cores = {} # unique physical ID / core ID combinations phy = 0 IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln| if ln.start_with?("physical") phy = ln[/\d+/] elsif ln.start_with?("core") cid = phy + ":" + ln[/\d+/] cores[cid] = true if not cores[cid] end end cores.count when /mswin|mingw/ # Get-CimInstance introduced in PowerShell 3 or earlier: https://learn.microsoft.com/en-us/previous-versions/powershell/module/cimcmdlets/get-ciminstance?view=powershell-3.0 result = run('powershell -command "Get-CimInstance -ClassName Win32_Processor -Property NumberOfCores | Select-Object -Property NumberOfCores"') if !result || $?.exitstatus != 0 # fallback to deprecated wmic for older systems result = run("wmic cpu get NumberOfCores") end if !result || $?.exitstatus != 0 # Bail out if both commands returned something unexpected processor_count else # powershell: "\nNumberOfCores\n-------------\n 4\n\n\n" # wmic: "NumberOfCores \n\n4 \n\n\n\n" result.scan(/\d+/).map(&:to_i).reduce(:+) end else processor_count end # fall back to logical count if physical info is invalid ppc > 0 ? ppc : processor_count rescue return 1 end
def compute_processor_count
def compute_processor_count if Concurrent.on_jruby? java.lang.Runtime.getRuntime.availableProcessors else Etc.nprocessors end end
def cpu_quota
def cpu_quota @cpu_quota.value end
def cpu_shares
def cpu_shares @cpu_shares.value end
def initialize
def initialize @processor_count = Delay.new { compute_processor_count } @physical_processor_count = Delay.new { compute_physical_processor_count } @cpu_quota = Delay.new { compute_cpu_quota } @cpu_shares = Delay.new { compute_cpu_shares } end
def physical_processor_count
def physical_processor_count @physical_processor_count.value end
def processor_count
def processor_count @processor_count.value end
def run(command)
def run(command) IO.popen(command, &:read) rescue Errno::ENOENT end