linux_stat 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -76,17 +76,23 @@ MARKDOWN, HTML = hash[:markdown], hash[:html]
76
76
 
77
77
  # Print time each method takes unless --no-time or -nt option is passed
78
78
  PRINT_TIME = (MARKDOWN || HTML) ? false : !ARGV.any? { |x| x[/^\-\-no-time$/] || x[/^\-nt$/] }
79
-
80
- %w(--markdown -md --no-time -nt --html -html).each(&ARGV.method(:delete))
79
+ PRINT_TYPE = ARGV.any? { |x| x[/^\-(\-show\-type|t)$/] }
80
+ %w(--markdown -md --no-time -nt --html -html --show-type -t).each(&ARGV.method(:delete))
81
81
 
82
82
  # Run only desired classes / modules
83
83
  constants = LinuxStat.constants
84
84
 
85
+ # Modules to delete from documentation and testing
86
+ %i(
87
+ Nproc
88
+ ).each(&constants.method(:delete))
89
+
85
90
  execute = constants.map(&:downcase).map.with_index { |x, i|
86
91
  constants[i] if ARGV.find { |y| y.downcase.to_sym == x }
87
92
  }.compact
88
93
 
89
94
  execute.replace(constants) if execute.empty?
95
+ HEXAGONS = %W(\u2b22 \u2b23 \u2B53 \u2B1F)
90
96
 
91
97
  execute.sort.each do |c|
92
98
  e = eval("LinuxStat::#{c}")
@@ -138,36 +144,51 @@ execute.sort.each do |c|
138
144
  disp_meth.concat(arg ? "(#{param} = #{arg.inspect})" : "(#{param})")
139
145
 
140
146
  time = Time.now
141
- v = arg ? e.send(meth, arg) : e.send(meth)
147
+ ret = arg ? e.send(meth, arg) : e.send(meth)
142
148
  time2 = Time.now
143
149
  time = time2.-(time).*(1_000_000).round(3)
144
150
 
145
- v = v.inspect
151
+ v = ret.inspect
146
152
  dis = v.length > 253 ? v[0..250].strip + '...'.freeze : v
147
153
 
148
154
  source = e.singleton_method(meth).source_location.to_a
149
- src, src_meth = '', ''
155
+ src, src_meth, src_ret = '', '', ''
150
156
 
151
157
  unless source.empty?
152
- src << " File: #{File.split(source[0])[-1]} | Line: #{source[1]}\n"
153
- src_meth << " Definition: #{IO.foreach(source[0]).first(source[1])[-1].strip}\n"
158
+ src << " File:\t\t#{File.split(source[0])[-1]} | Line: #{source[1]}\n"
159
+ src_meth << " Definition:\t#{IO.foreach(source[0]).first(source[1])[-1].strip}\n"
160
+
161
+ src_ret << " Returns:\t" << case ret
162
+ when Array then 'Array | Empty Array'
163
+ when Complex then 'Complex | nil'
164
+ when Float then 'Float | nil'
165
+ when Hash then 'Hash | Empty Hash'
166
+ when Integer then 'Integer | nil'
167
+ when Rational then 'Rational | nil'
168
+ when String then "String | (Frozen) Empty String"
169
+ when Time then 'Time | nil'
170
+ when true, false then 'True or False | nil'
171
+ when nil then 'nil'
172
+ else ''
173
+ end << ?\n.freeze if PRINT_TYPE
154
174
 
155
175
  if MARKDOWN || HTML
156
176
  src.prepend('#'.freeze)
157
177
  src_meth.prepend('#'.freeze)
178
+ src_ret.prepend(?#.freeze) if PRINT_TYPE
158
179
  else
159
- src.prepend(?\u2B23.freeze)
160
- src_meth.prepend(?\u2B23.freeze)
180
+ src.prepend(HEXAGONS.rotate![0].freeze)
181
+ src_meth.prepend(HEXAGONS.rotate![0].freeze)
182
+ src_ret.prepend(HEXAGONS.rotate![0].freeze) if PRINT_TYPE
161
183
  end
162
184
  end
163
185
 
164
-
165
186
  if MARKDOWN
166
- puts "#{src}#{src_meth}#{e}.#{disp_meth}\n=> #{dis}"
187
+ puts "#{src}#{src_meth}#{src_ret}#{e}.#{disp_meth}\n=> #{dis}"
167
188
  elsif HTML
168
- puts "#{src}#{src_meth}#{e}.#{disp_meth}\n=> #{dis}"
189
+ puts "#{src}#{src_meth}#{src_ret}#{e}.#{disp_meth}\n=> #{dis}"
169
190
  else
170
- puts "\e[1m#{src.colourize}\e[1m#{src_meth.colourize(4)}\e[0m\e[1;38;2;80;80;255m#{e}.#{disp_meth}\e[0m\n=> #{dis}"
191
+ puts "\e[1m#{src.colourize}\e[1m#{src_meth.colourize(6)}\e[1m#{src_ret.colourize(1)}\e[0m\e[1;38;2;80;80;255m#{e}.#{disp_meth}\e[0m\n=> #{dis}"
171
192
  end
172
193
 
173
194
  puts( "(" +
@@ -1,12 +1,14 @@
1
1
  #include <sys/statvfs.h>
2
2
  #include "ruby.h"
3
3
 
4
- #ifdef __GNUC__
4
+ #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
5
5
  #pragma GCC optimize ("O3")
6
6
  #pragma GCC diagnostic warning "-Wall"
7
- #elif __clang__
7
+ #elif defined(__clang__)
8
8
  #pragma clang optimize on
9
9
  #pragma clang diagnostic warning "-Wall"
10
+ #elif defined(__INTEL_COMPILER)
11
+ #pragma intel optimization_level 3
10
12
  #endif
11
13
 
12
14
  static VALUE statfs(VALUE obj, VALUE dir) {
@@ -0,0 +1,11 @@
1
+ require 'mkmf'
2
+
3
+ unless have_const('linux') || RbConfig::CONFIG['arch'].to_s[/linux/]
4
+ abort('Platform is not linux')
5
+ end
6
+
7
+ unless have_header('sched.h') && have_header('ruby.h')
8
+ abort('Missing header')
9
+ end
10
+
11
+ create_makefile 'linux_stat/nproc'
@@ -0,0 +1,31 @@
1
+ #ifndef _GNU_SOURCE
2
+ #define _GNU_SOURCE
3
+ #endif
4
+
5
+ #include <sched.h>
6
+ #include "ruby.h"
7
+
8
+ #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
9
+ #pragma GCC optimize ("O3")
10
+ #pragma GCC diagnostic warning "-Wall"
11
+ #elif defined(__clang__)
12
+ #pragma clang optimize on
13
+ #pragma clang diagnostic warning "-Wall"
14
+ #elif defined(__INTEL_COMPILER)
15
+ #pragma intel optimization_level 3
16
+ #endif
17
+
18
+ static VALUE count_cpu_for_pid(VALUE obj, VALUE pid) {
19
+ cpu_set_t set ;
20
+ CPU_ZERO(&set) ;
21
+ short int stat = sched_getaffinity(FIX2INT(pid), sizeof(set), &set) ;
22
+
23
+ if (stat < 0) return Qnil ;
24
+ return INT2FIX(CPU_COUNT(&set)) ;
25
+ }
26
+
27
+ void Init_nproc() {
28
+ VALUE _linux_stat = rb_define_module("LinuxStat") ;
29
+ VALUE _nproc = rb_define_module_under(_linux_stat, "Nproc") ;
30
+ rb_define_module_function(_nproc, "count_cpu_for_pid", count_cpu_for_pid, 1) ;
31
+ }
@@ -1,12 +1,14 @@
1
1
  #include <unistd.h>
2
2
  #include "ruby.h"
3
3
 
4
- #ifdef __GNUC__
4
+ #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
5
5
  #pragma GCC optimize ("O3")
6
6
  #pragma GCC diagnostic warning "-Wall"
7
- #elif __clang__
7
+ #elif defined(__clang__)
8
8
  #pragma clang optimize on
9
9
  #pragma clang diagnostic warning "-Wall"
10
+ #elif defined(__INTEL_COMPILER)
11
+ #pragma intel optimization_level 3
10
12
  #endif
11
13
 
12
14
  static VALUE getTick(VALUE obj) {
@@ -53,11 +55,11 @@ static VALUE getExprNestMax(VALUE obj) {
53
55
  return INT2FIX(sysconf(_SC_EXPR_NEST_MAX)) ;
54
56
  }
55
57
 
56
- VALUE getProcessorConfigured(VALUE obj) {
58
+ static VALUE getProcessorConfigured(VALUE obj) {
57
59
  return INT2FIX(sysconf(_SC_NPROCESSORS_CONF)) ;
58
60
  }
59
61
 
60
- VALUE getProcessorOnline(VALUE obj) {
62
+ static VALUE getProcessorOnline(VALUE obj) {
61
63
  return INT2FIX(sysconf(_SC_NPROCESSORS_ONLN)) ;
62
64
  }
63
65
 
@@ -1,12 +1,14 @@
1
1
  #include <sys/utsname.h>
2
2
  #include "ruby.h"
3
3
 
4
- #ifdef __GNUC__
4
+ #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
5
5
  #pragma GCC optimize ("O3")
6
6
  #pragma GCC diagnostic warning "-Wall"
7
- #elif __clang__
7
+ #elif defined(__clang__)
8
8
  #pragma clang optimize on
9
9
  #pragma clang diagnostic warning "-Wall"
10
+ #elif defined(__INTEL_COMPILER)
11
+ #pragma intel optimization_level 3
10
12
  #endif
11
13
 
12
14
  static struct utsname buf ;
@@ -23,7 +23,6 @@ require 'linux_stat/prettify_bytes'
23
23
  # But might be required by other module functions in "Dependent Modules" section
24
24
  require "linux_stat/battery"
25
25
  require "linux_stat/bios"
26
- require "linux_stat/cpu"
27
26
  require "linux_stat/memory"
28
27
  require "linux_stat/net"
29
28
  require "linux_stat/process"
@@ -32,6 +31,10 @@ require "linux_stat/swap"
32
31
  # Dependent Modules
33
32
  # Modules that can have reverse dependency
34
33
 
34
+ # LinuxStat::CPU.nproc dependent modules
35
+ require "linux_stat/cpu"
36
+ require "linux_stat/nproc"
37
+
35
38
  # LinuxStat::Uname dependent modules
36
39
  require 'linux_stat/utsname'
37
40
  require "linux_stat/os"
@@ -46,3 +49,6 @@ require "linux_stat/sysconf"
46
49
  require "linux_stat/kernel"
47
50
  require 'linux_stat/user'
48
51
  require "linux_stat/process_info"
52
+
53
+ # A short alias to LinuxStat
54
+ LS = LinuxStat
@@ -98,12 +98,25 @@ module LinuxStat
98
98
  #
99
99
  # If the battery is not present or the information is not available, it will return nil.
100
100
  def charge
101
- return nil unless charge_now_readable?
102
- charge_now = IO.read(File.join(PATH, 'charge_now')).to_i
103
- charge_full = IO.read(File.join(PATH, 'charge_full')).to_i
101
+ @@charge_now_file ||= File.join(PATH, 'charge_now')
102
+ @@charge_full_file ||= File.join(PATH, 'charge_full')
103
+
104
+ @@charge_now_readable ||= File.readable?(@@charge_now_file) && File.readable?(@@charge_full_file)
105
+ return nil unless @@charge_now_readable
106
+
107
+ charge_now = IO.read(@@charge_now_file).to_i
108
+ charge_full = IO.read(@@charge_full_file).to_i
104
109
 
105
110
  percentage = charge_now.*(100).fdiv(charge_full)
106
- percentage = percentage > 100 ? 100.0 : percentage < 0 ? 0.0 : percentage
111
+ percentage > 100 ? 100.0 : percentage < 0 ? 0.0 : percentage
112
+ end
113
+
114
+ def voltage_now
115
+ @@voltage_file ||= File.join(PATH, 'voltage_now'.freeze)
116
+ @@voltage_readable ||= File.readable?(@@voltage_file)
117
+ return nil unless @@voltage_readable
118
+
119
+ IO.read(@@voltage_file, 16).to_f.fdiv(1000000)
107
120
  end
108
121
 
109
122
  private
@@ -122,11 +135,6 @@ module LinuxStat
122
135
  def status_readable?
123
136
  @@status_readable ||= File.readable?(File.join(PATH, 'status'))
124
137
  end
125
-
126
- def charge_now_readable?
127
- @@charge_now_readable ||= File.readable?(File.join(PATH, 'charge_now')) &&
128
- File.readable?(File.join(PATH, 'charge_full'))
129
- end
130
138
  end
131
139
  end
132
140
  end
@@ -14,16 +14,18 @@ module LinuxStat
14
14
  #
15
15
  # And the consecutive ones are the real core usages.
16
16
  #
17
- # On a system with 4 threads, the output will be like::
18
- # {0=>84.38, 1=>100.0, 2=>50.0, 3=>87.5, 4=>87.5}
17
+ # For example, on a system with 4 threads:
18
+ # LinuxStat::CPU.stat
19
+ #
20
+ # => {0=>84.38, 1=>100.0, 2=>50.0, 3=>87.5, 4=>87.5}
19
21
  #
20
22
  # If the information is not available, it will return an empty Hash
21
23
  def stat(sleep = ticks_to_ms_t5)
22
24
  return {} unless stat?
23
25
 
24
- data = IO.readlines('/proc/stat').select! { |x| x[/^cpu\d*/] }.map! { |x| x.split.map!(&:to_f) }
26
+ data = IO.readlines('/proc/stat'.freeze).select { |x| x[/^cpu\d*/] }.map! { |x| x.split.map!(&:to_f) }
25
27
  sleep(sleep)
26
- data2 = IO.readlines('/proc/stat').select! { |x| x[/^cpu\d*/] }.map! { |x| x.split.map!(&:to_f) }
28
+ data2 = IO.readlines('/proc/stat'.freeze).select { |x| x[/^cpu\d*/] }.map! { |x| x.split.map!(&:to_f) }
27
29
 
28
30
  # On devices like android, the core count can change anytime (hotplugging).
29
31
  # I had crashes on Termux.
@@ -39,12 +41,10 @@ module LinuxStat
39
41
  idle_then, idle_now = idle + iowait, idle2 + iowait2
40
42
  totald = idle_now.+(user2 + nice2 + sys2 + irq2 + softirq2 + steal2) - idle_then.+(user + nice + sys + irq + softirq + steal)
41
43
 
42
- res = totald.-(idle_now - idle_then).fdiv(totald).*(100).round(2).abs
43
- res = 0.0 if res.nan?
44
+ res = totald.-(idle_now - idle_then).fdiv(totald).abs.*(100)
45
+ res = res.nan? ? 0.0 : res > 100 ? 100.0 : res.round(2)
44
46
 
45
- h.merge!(
46
- x => res
47
- )
47
+ h.merge!( x => res )
48
48
  end
49
49
  end
50
50
 
@@ -72,31 +72,63 @@ module LinuxStat
72
72
 
73
73
  idle_then, idle_now = idle + iowait, idle2 + iowait2
74
74
  totald = idle_now.+(user2 + nice2 + sys2 + irq2 + softirq2 + steal2) - idle_then.+(user + nice + sys + irq + softirq + steal)
75
- totald.-(idle_now - idle_then).fdiv(totald).*(100).round(2).abs
75
+
76
+ u = totald.-(idle_now - idle_then).fdiv(totald).abs.*(100)
77
+ u > 100 ? 100.0 : u.round(2)
78
+ end
79
+
80
+ ##
81
+ # Returns the total number of CPU available for the sysetm.
82
+ #
83
+ # It returns an Integer.
84
+ #
85
+ # If the information isn't available, it will return an empty Array.
86
+ def count
87
+ @@cpu_count ||= LinuxStat::Sysconf.processor_configured
76
88
  end
77
89
 
78
90
  ##
79
- # Returns the total number of CPU threads online now.
91
+ # Returns the total number of CPU online in the sysetm.
80
92
  #
81
- # This value can change while a CPU is offline, due to kernel's hotplugging feature.
93
+ # It opens /sys/devices/system/cpu/offline and
94
+ # performs various job to get one Ruby array.
82
95
  #
83
- # If the information isn't available, it will return 0.
96
+ # If the information isn't available, it will return an empty Array.
84
97
  def online
85
- # Let's rely on sysconf(_SC_NPROCESSORS_CONF), which is 100x faster than
86
- # counting online cpu from /sys/devices/system/cpu
98
+ @@online_file ||= '/sys/devices/system/cpu/online'.freeze
99
+ @@online_readable ||= File.readable?(@@online_file)
100
+ return [] unless @@online_readable
101
+
102
+ ret = []
103
+ IO.read(@@online_file).split(?,.freeze).each { |x|
104
+ x.strip!
105
+ c = x.split(?-.freeze).map(&:to_i)
106
+ ret.concat(c.length == 2 ? Range.new(*c).to_a : c)
107
+ }
87
108
 
88
- LinuxStat::Sysconf.processor_configured
109
+ ret
89
110
  end
90
111
 
91
112
  ##
92
- # Returns the total number of CPU threads configured for the sysetm.
113
+ # Returns the total number of CPU offline in the sysetm.
93
114
  #
94
- # If the information isn't available, it will return 0.
95
- def count
96
- # Let's rely on sysconf(_SC_NPROCESSORS_ONLN), which is 100x faster than running:
97
- # IO.read('/sys/devices/system/cpu/online')[-2].to_i + 1
115
+ # It opens /sys/devices/system/cpu/offline and
116
+ # performs various job to get one Ruby array.
117
+ #
118
+ # If the information isn't available, it will return an empty Array.
119
+ def offline
120
+ @@offline_file ||= '/sys/devices/system/cpu/offline'.freeze
121
+ @@offline_readable ||= File.readable?(@@offline_file)
122
+ return [] unless @@offline_readable
123
+
124
+ ret = []
125
+ IO.read(@@offline_file).split(?,.freeze).each { |x|
126
+ x.strip!
127
+ c = x.split(?-.freeze).map(&:to_i)
128
+ ret.concat(c.length == 2 ? Range.new(*c).to_a : c)
129
+ }
98
130
 
99
- LinuxStat::Sysconf.processor_online
131
+ ret
100
132
  end
101
133
 
102
134
  ##
@@ -110,33 +142,115 @@ module LinuxStat
110
142
  end
111
143
 
112
144
  ##
113
- # Returns an array with current core frequencies corresponding to the usages.
145
+ # Returns a Hash with current core frequencies corresponding to the CPUs.
114
146
  #
115
- # If the information isn't available, it will return an empty array.
147
+ # For example:
148
+ # LinuxStat::CPU.cur_freq
149
+ #
150
+ # => {"cpu0"=>1999990, "cpu1"=>2000042, "cpu2"=>2000016, "cpu3"=>2000088}
151
+ #
152
+ # If the information isn't available, it will return an empty Hash.
116
153
  def cur_freq
117
- @@cpu_freqs ||= Dir["/sys/devices/system/cpu/cpu[0-9]*/cpufreq/scaling_cur_freq"]
118
- @@cur_freqs_readable ||= @@cpu_freqs.all?(&File.method(:readable?))
154
+ @@cur_f ||= cpus.map { |x|
155
+ [File.split(x)[-1], File.join(x, 'cpufreq/scaling_cur_freq'.freeze)]
156
+ }
119
157
 
120
- if @@cur_freqs_readable
121
- @@cpu_freqs.map { |x| IO.read(x).to_i }
122
- else
123
- []
124
- end
158
+ h = {}
159
+ @@cur_f.each { |id, file|
160
+ h.merge!(id => IO.read(file).to_i) if File.readable?(file)
161
+ }
162
+
163
+ h
164
+ end
165
+
166
+ ##
167
+ # Returns a Hash with max core frequencies corresponding to the CPUs.
168
+ #
169
+ # For example:
170
+ # LinuxStat::CPU.min_freq
171
+ #
172
+ # => {"cpu0"=>2000000, "cpu1"=>2000000, "cpu2"=>2000000, "cpu3"=>2000000}
173
+ #
174
+ # If the information isn't available, it will return an empty Hash.
175
+ def min_freq
176
+ @@min_f ||= cpus.map { |x|
177
+ [File.split(x)[-1], File.join(x, 'cpufreq/scaling_min_freq'.freeze)]
178
+ }
179
+
180
+ h = {}
181
+ @@min_f.each { |id, file|
182
+ h.merge!(id => IO.read(file).to_i) if File.readable?(file)
183
+ }
184
+
185
+ h
125
186
  end
126
187
 
127
188
  ##
128
- # Returns an array with max core frequencies corresponding to the usages.
189
+ # Returns a Hash with max core frequencies corresponding to the CPUs.
129
190
  #
130
- # If the information isn't available, it will return an empty array.
191
+ # For example:
192
+ # LinuxStat::CPU.max_freq
193
+ #
194
+ # => {"cpu0"=>2000000, "cpu1"=>2000000, "cpu2"=>2000000, "cpu3"=>2000000}
195
+ #
196
+ # If the information isn't available, it will return an empty Hash.
131
197
  def max_freq
132
- @@max_freqs ||= Dir["/sys/devices/system/cpu/cpu[0-9]*/cpufreq/scaling_max_freq"]
133
- @@max_freqs_readable ||= @@max_freqs.all?(&File.method(:readable?))
198
+ @@min_f ||= cpus.map { |x|
199
+ [File.split(x)[-1], File.join(x, 'cpufreq/scaling_max_freq'.freeze)]
200
+ }
134
201
 
135
- if @@max_freqs_readable
136
- @@max_freqs.map { |x| IO.read(x).to_i }
137
- else
138
- []
139
- end
202
+ h = {}
203
+ @@min_f.each { |id, file|
204
+ h.merge!(id => IO.read(file).to_i) if File.readable?(file)
205
+ }
206
+
207
+ h
208
+ end
209
+
210
+ ##
211
+ # Returns the corresponding governor of each CPU.
212
+ #
213
+ # The return type is a Hash.
214
+ #
215
+ # For example:
216
+ # LinuxStat::CPU.governor
217
+ #
218
+ # => {"cpu0"=>"powersave", "cpu1"=>"powersave", "cpu2"=>"performance", "cpu3"=>"performance"}
219
+ #
220
+ # If the information isn't available, it will return an empty Hash.
221
+ def governor
222
+ @@scaling_g ||= cpus.map { |x|
223
+ [File.split(x)[-1], File.join(x, 'cpufreq/scaling_governor'.freeze)]
224
+ }
225
+
226
+ h = {}
227
+ @@scaling_g.each { |id, file|
228
+ h.merge!(id => IO.read(file).tap(&:strip!)) if File.readable?(file)
229
+ }
230
+
231
+ h
232
+ end
233
+
234
+ ##
235
+ # Returns an array of governors for each CPU as a Hash.
236
+ #
237
+ # For example:
238
+ # LinuxStat::CPU.available_governors
239
+ #
240
+ # => {"cpu0"=>["performance", "powersave"], "cpu1"=>["performance", "powersave"], "cpu2"=>["performance", "powersave"], "cpu3"=>["performance", "powersave"]}
241
+ #
242
+ # If the information isn't available, it will return an empty Hash.
243
+ def available_governors
244
+ @@scaling_av_g ||= cpus.map { |x|
245
+ [File.split(x)[-1], File.join(x, 'cpufreq/scaling_available_governors'.freeze)]
246
+ }
247
+
248
+ h = {}
249
+ @@scaling_av_g.each { |id, file|
250
+ h.merge!(id => IO.read(file).split.each(&:strip!)) if File.readable?(file)
251
+ }
252
+
253
+ h
140
254
  end
141
255
 
142
256
  alias usages stat
@@ -144,7 +258,7 @@ module LinuxStat
144
258
 
145
259
  private
146
260
  def cpuinfo
147
- File.readable?('/proc/cpuinfo') ? IO.readlines('/proc/cpuinfo') : []
261
+ File.readable?('/proc/cpuinfo') ? IO.readlines('/proc/cpuinfo').freeze : [].freeze
148
262
  end
149
263
 
150
264
  def stat?
@@ -157,6 +271,10 @@ module LinuxStat
157
271
  def ticks_to_ms_t5
158
272
  @@ms_t5 ||= 1.0 / LinuxStat::Sysconf.sc_clk_tck * 5
159
273
  end
274
+
275
+ def cpus
276
+ @@all_cpu = Dir["/sys/devices/system/cpu/cpu[0-9]*/"].sort!.freeze
277
+ end
160
278
  end
161
279
  end
162
280
  end