-
Notifications
You must be signed in to change notification settings - Fork 49
/
cores.rb
127 lines (112 loc) · 3.17 KB
/
cores.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
module Picky
Infinity = 1.0/0
# Handles processing over multiple cores.
#
class Cores # :nodoc:all
# Pass it an ary.
#
# ary = (1..10).to_a
# forked ary, :max => 5 do |element|
#
# end
#
# Options include:
# * max: Maximum # of processors to use. Default is all it can get.
# * amount: An exactly defined amount of processors to use.
# * randomly: Whether to use random order or not.
#
def self.forked elements, options = {}, &block
return if elements.empty?
raise "Block argument needed when running Cores.forked" unless block_given?
# Note: Not using a generator because Enumerator#each
# is exhibiting problems in some Rubies on some OSs
# (see e.g. http://redmine.ruby-lang.org/issues/5003).
#
elements = elements.dup
elements = elements.sort_by { rand } if options[:randomly]
# Get the maximum number of processors.
#
max = max_processors options
# Decide whether to use forking.
#
if fork?(max)
processing = 0
loop do
while processing < max
# Get the next element
#
element = elements.shift
break unless element
processing += 1
# Fork and yield.
#
Process.fork do
sleep 0.05*processing
block.call element
end
end
# Block and wait for any child to finish.
#
begin
Process.wait 0
rescue Errno::ECHILD => e
break
ensure
processing -= 1
end
end
else
elements.each &block
end
end
# Do not fork if there is just one processor,
# or as in Windows, if there isn't the
# possibility of forking.
#
def self.fork? max_processors
max_processors > 1 && Process.respond_to?(:fork)
end
# Return the number of maximum usable processors.
#
# Options
# max: The maximum amount of cores used.
#
def self.max_processors options = {}
options[:amount] || [number_of_cores, (options[:max] || Infinity)].min
end
# Gets the number of cores depending on OS.
#
def self.number_of_cores
extract_cores_for actual_platform
end
# Extracts the platform os from the platform.
#
# Note: Could also use 'rbconfig'.
#
def self.actual_platform
matched = platform.match(/-\b([a-z]*)/)
matched && matched[1]
end
# Returns a mapping
# os_name => lambda_which_returns_a_number_of_cores
#
@@number_of_cores = {
'darwin' => lambda { `system_profiler SPHardwareDataType | grep -i 'Total Number [oO]f Cores'`.gsub(/[^\d]/, '') },
'linux' => lambda { `grep -ci ^processor /proc/cpuinfo` }
}
def self.os_to_core_mapping
@@number_of_cores
end
# Extracts the number of cores for the given os name.
#
# Note: Default is 1.
#
def self.extract_cores_for os
code_to_execute = os_to_core_mapping[os]
code_to_execute && code_to_execute.call.to_i || 1
end
def self.platform
RUBY_PLATFORM
end
end
end