Reputation: 15097
I already found a solution for "Most unixes" via cat /proc/cpuinfo
, but a pure-Ruby solution would be nicer.
Upvotes: 48
Views: 19550
Reputation: 1332
EDIT: Now rails ships with concurrent-ruby as a dependency so it's probably the best solution;
$ gem install concurrent-ruby
$ irb
irb(main):001:0> require 'concurrent'
=> true
irb(main):002:0> Concurrent.processor_count
=> 8
irb(main):003:0> Concurrent.physical_processor_count
=> 4
see http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent.html for more info. Because it does both physical and logical cores, it's better than the inbuilt Etc.nprocessors
.
and here is the previous answer;
$ gem install facter
$ irb
irb(main):001:0> require 'facter'
=> true
irb(main):002:0> puts Facter.value('processors')['count']
4
=> nil
irb(main):003:0>
This facter gem is the best if you want other facts about the system too, it's not platform specific and designed to do this exact thing.
UPDATE: updated to include Nathan Kleyn's tip on the api change.
Upvotes: 46
Reputation: 7270
As of Ruby version 2.2.3, the etc
module in Ruby's stdlib offers an nprocessors
method which returns the number of processors. The caveat to this, is that if ruby is relegated to a subset of CPU cores, Etc.nprocessors
will only return the number of cores that Ruby has access to. Also, as seanlinsley pointed out, this will only return virtual cores instead of physical cores, which may result in a disparity in the expected value.
require 'etc'
p Etc.nprocessors #=> 4
Upvotes: 56
Reputation: 25954
Here is an implementation for Linux, OSX, Windows and BSD: https://gist.github.com/1009994
Source code:
module System
extend self
def cpu_count
return Java::Java.lang.Runtime.getRuntime.availableProcessors if defined? Java::Java
return File.read('/proc/cpuinfo').scan(/^processor\s*:/).size if File.exist? '/proc/cpuinfo'
require 'win32ole'
WIN32OLE.connect("winmgmts://").ExecQuery("select * from Win32_ComputerSystem").NumberOfProcessors
rescue LoadError
Integer `sysctl -n hw.ncpu 2>/dev/null` rescue 1
end
end
System.cpu_count # => 2
Upvotes: 11
Reputation: 2193
In linux you can also use nproc
, which is cleaner that the other subshell-based solutions here. I wanted vagrant to give the same number of CPUs to the virtual machine as the host has. I added this to Vagrantfile
:
vb.cpus = `nproc`.to_i
Upvotes: 4
Reputation: 2900
Combination of @grosser's and @paxdiablo's answer, since on my system (winxp) win32_computersystem doesn't have any processor info; this works though:
require 'win32ole'
wmi = WIN32OLE.connect("winmgmts://")
info = wmi.ExecQuery ("select NumberOfCores from Win32_processor")
puts info.to_enum.first.NumberOfCores
To see what's available on your system, run this from powershell (i used 1.0 in this case):
Get-WmiObject -list
(might want to pipe to grep if you've got cygwin installed)
Upvotes: 0
Reputation: 1476
I tried using Facter
but found it a bit slow. I tried system
gem and found it a lot faster. It is also very easy to use: System::CPU.count
.
Upvotes: 3
Reputation: 389
I found something recently that may have to be taken into consideration. You can deactivate processors (take them offline), and then facter processorcount (plus some of the other methods above) gives the wrong result. You can count processor lines in /proc/cpuinfo, as long as you do it correctly. If you just populate an array with index numbers of the procs, if you have gaps in the procs (as in, procs 0,1,2,10,11,12 are active, all others to 20 say are inactive), it will automatically spring indexes 3-9 into existence (sort of), at least Array#size will report 13 in that case. You would have to do #compact to get the number of active processors. However, if you want total processors, perhaps better is looking at /sys/devices/system/cpu[0-9], and count that up. That will give you the total number of processors, but not how many (or which ones) are active.
Just something to think about. I trying to put through a patch to facter to add an activeprocessorcount and totalprocessorcount fact.
Upvotes: 0
Reputation: 15097
I am currently using this, which covers all os. https://github.com/grosser/parallel/blob/master/lib/parallel.rb#L63
def self.processor_count
case RbConfig::CONFIG['host_os']
when /darwin9/
`hwprefs cpu_count`.to_i
when /darwin/
((`which hwprefs` != '') ? `hwprefs thread_count` : `sysctl -n hw.ncpu`).to_i
when /linux/
`cat /proc/cpuinfo | grep processor | wc -l`.to_i
when /freebsd/
`sysctl -n hw.ncpu`.to_i
when /mswin|mingw/
require 'win32ole'
wmi = WIN32OLE.connect("winmgmts://")
cpu = wmi.ExecQuery("select NumberOfCores from Win32_Processor") # TODO count hyper-threaded in this
cpu.to_enum.first.NumberOfCores
end
end
Upvotes: 31
Reputation: 11
@grosser:
when /linux/ `grep -c processor /proc/cpuinfo`.to_i
http://www.partmaps.org/era/unix/award.html#cat
http://www.partmaps.org/era/unix/award.html#wc
Upvotes: 1
Reputation: 116324
with JRuby you can check it with the following Java code:
Runtime runtime = Runtime.getRuntime();
int numberOfProcessors = runtime.availableProcessors();
Upvotes: 11
Reputation: 881293
Surely if you can cat
it, you can open, read and close it using the standard features of the language without resorting to a system()
-type call.
You may just need to detect what platform you're on dynamically and either:
/proc/cpuinfo
"file" for Linux; orThat last line can use:
require 'win32ole'
wmi = WIN32OLE.connect("winmgmts://")
info = wmi.ExecQuery ("select * from Win32_ComputerSystem")
Then use info's NumberOfProcessors item.
Upvotes: 5