linux_stat 0.8.0 → 1.0.2

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.
@@ -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
 
@@ -63,40 +63,116 @@ module LinuxStat
63
63
  def total_usage(sleep = ticks_to_ms_t5)
64
64
  return nil unless stat?
65
65
 
66
- data = IO.foreach('/proc/stat').first.split.tap(&:shift).map!(&:to_f)
66
+ data = IO.foreach('/proc/stat'.freeze).first.split.tap(&:shift).map!(&:to_f)
67
67
  sleep(sleep)
68
- data2 = IO.foreach('/proc/stat').first.split.tap(&:shift).map!(&:to_f)
68
+ data2 = IO.foreach('/proc/stat'.freeze).first.split.tap(&:shift).map!(&:to_f)
69
69
 
70
70
  user, nice, sys, idle, iowait, irq, softirq, steal = *data
71
71
  user2, nice2, sys2, idle2, iowait2, irq2, softirq2, steal2 = *data2
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 nil.
86
+ def count
87
+ @@cpu_count ||= LinuxStat::Sysconf.processor_configured
88
+ end
89
+
90
+ ##
91
+ # Returns the total number of CPU online in the sysetm.
92
+ #
93
+ # It first reads /proc/stat, if that fails, it will
94
+ # read /sys/devices/system/cpu/online,
95
+ # if that fails it will open /proc/cpuinfo.
96
+ # If neither of the procedures work, it will get the
97
+ # LinuxStat::Sysconf.processor_online
98
+ #
99
+ # It opens /sys/devices/system/cpu/offline and
100
+ # performs various job to get one Ruby array.
101
+ #
102
+ # If the information isn't available, it will return an empty Array.
103
+ def count_online
104
+ @@cpuinfo_file ||= '/proc/cpuinfo'.freeze
105
+ @@cpuinfo_readable ||= File.readable?(@@cpuinfo_file)
106
+
107
+ @@stat_file ||= '/proc/stat'.freeze
108
+
109
+ # Not much slow, not blazing fast, somewhat reliable
110
+ get_online = online
111
+
112
+ if !get_online.empty?
113
+ get_online.length
114
+ elsif @@cpuinfo_readable
115
+ # Way slower but reliable!
116
+ IO.readlines(@@cpuinfo_file).count { |x| x.strip[/\Aprocessor.*\d*\z/] }
117
+ else
118
+ # Way faster but absolutely unrealiable!
119
+ LinuxStat::Sysconf.processor_online
120
+ end
76
121
  end
77
122
 
78
123
  ##
79
- # Returns the total number of CPU threads online now.
124
+ # Returns the total number of CPU online in the sysetm.
125
+ #
126
+ # It will read /proc/stat to get the info.
80
127
  #
81
- # This value can change while a CPU is offline, due to kernel's hotplugging feature.
128
+ # If the info isn't available, it reads /sys/devices/system/cpu/onfline and
129
+ # performs various job to get one Ruby array.
82
130
  #
83
- # If the information isn't available, it will return 0.
131
+ # If the information isn't available, it will return an empty Array.
84
132
  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
133
+ @@online_file ||= '/sys/devices/system/cpu/online'.freeze
134
+ @@online_readable ||= File.readable?(@@online_file)
135
+
136
+ @@stat_file ||= '/proc/stat'.freeze
137
+
138
+ ret = []
139
+
140
+ if stat?
141
+ IO.readlines(@@stat_file).map { |x|
142
+ v = x.strip[/\Acpu\d*/] &.[](/\d/)
143
+ ret << v.to_i if v
144
+ }
145
+ elsif @@online_readable
146
+ IO.read(@@online_file).split(?,.freeze).each { |x|
147
+ x.strip!
148
+ c = x.split(?-.freeze).map(&:to_i)
149
+ ret.concat(c.length == 2 ? Range.new(*c).to_a : c)
150
+ }
151
+ end
87
152
 
88
- LinuxStat::Sysconf.processor_configured
153
+ ret
89
154
  end
90
155
 
91
156
  ##
92
- # Returns the total number of CPU threads configured for the sysetm.
157
+ # Returns the total number of CPU offline in the sysetm.
93
158
  #
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
159
+ # It opens /sys/devices/system/cpu/offline and
160
+ # performs various job to get one Ruby array.
161
+ #
162
+ # If the information isn't available, it will return an empty Array.
163
+ def offline
164
+ @@offline_file ||= '/sys/devices/system/cpu/offline'.freeze
165
+ @@offline_readable ||= File.readable?(@@offline_file)
166
+ return [] unless @@offline_readable
98
167
 
99
- LinuxStat::Sysconf.processor_online
168
+ ret = []
169
+ IO.read(@@offline_file).split(?,.freeze).each { |x|
170
+ x.strip!
171
+ c = x.split(?-.freeze).map(&:to_i)
172
+ ret.concat(c.length == 2 ? Range.new(*c).to_a : c)
173
+ }
174
+
175
+ ret
100
176
  end
101
177
 
102
178
  ##
@@ -110,33 +186,115 @@ module LinuxStat
110
186
  end
111
187
 
112
188
  ##
113
- # Returns an array with current core frequencies corresponding to the usages.
189
+ # Returns a Hash with current core frequencies corresponding to the CPUs.
190
+ #
191
+ # For example:
192
+ # LinuxStat::CPU.cur_freq
114
193
  #
115
- # If the information isn't available, it will return an empty array.
194
+ # => {"cpu0"=>1999990, "cpu1"=>2000042, "cpu2"=>2000016, "cpu3"=>2000088}
195
+ #
196
+ # If the information isn't available, it will return an empty Hash.
116
197
  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?))
198
+ @@cur_f ||= cpus.map { |x|
199
+ [File.split(x)[-1], File.join(x, 'cpufreq/scaling_cur_freq'.freeze)]
200
+ }
119
201
 
120
- if @@cur_freqs_readable
121
- @@cpu_freqs.map { |x| IO.read(x).to_i }
122
- else
123
- []
124
- end
202
+ h = {}
203
+ @@cur_f.each { |id, file|
204
+ h.merge!(id => IO.read(file).to_i) if File.readable?(file)
205
+ }
206
+
207
+ h
125
208
  end
126
209
 
127
210
  ##
128
- # Returns an array with max core frequencies corresponding to the usages.
211
+ # Returns a Hash with max core frequencies corresponding to the CPUs.
129
212
  #
130
- # If the information isn't available, it will return an empty array.
213
+ # For example:
214
+ # LinuxStat::CPU.min_freq
215
+ #
216
+ # => {"cpu0"=>2000000, "cpu1"=>2000000, "cpu2"=>2000000, "cpu3"=>2000000}
217
+ #
218
+ # If the information isn't available, it will return an empty Hash.
219
+ def min_freq
220
+ @@min_f ||= cpus.map { |x|
221
+ [File.split(x)[-1], File.join(x, 'cpufreq/scaling_min_freq'.freeze)]
222
+ }
223
+
224
+ h = {}
225
+ @@min_f.each { |id, file|
226
+ h.merge!(id => IO.read(file).to_i) if File.readable?(file)
227
+ }
228
+
229
+ h
230
+ end
231
+
232
+ ##
233
+ # Returns a Hash with max core frequencies corresponding to the CPUs.
234
+ #
235
+ # For example:
236
+ # LinuxStat::CPU.max_freq
237
+ #
238
+ # => {"cpu0"=>2000000, "cpu1"=>2000000, "cpu2"=>2000000, "cpu3"=>2000000}
239
+ #
240
+ # If the information isn't available, it will return an empty Hash.
131
241
  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?))
242
+ @@min_f ||= cpus.map { |x|
243
+ [File.split(x)[-1], File.join(x, 'cpufreq/scaling_max_freq'.freeze)]
244
+ }
134
245
 
135
- if @@max_freqs_readable
136
- @@max_freqs.map { |x| IO.read(x).to_i }
137
- else
138
- []
139
- end
246
+ h = {}
247
+ @@min_f.each { |id, file|
248
+ h.merge!(id => IO.read(file).to_i) if File.readable?(file)
249
+ }
250
+
251
+ h
252
+ end
253
+
254
+ ##
255
+ # Returns the corresponding governor of each CPU.
256
+ #
257
+ # The return type is a Hash.
258
+ #
259
+ # For example:
260
+ # LinuxStat::CPU.governor
261
+ #
262
+ # => {"cpu0"=>"powersave", "cpu1"=>"powersave", "cpu2"=>"performance", "cpu3"=>"performance"}
263
+ #
264
+ # If the information isn't available, it will return an empty Hash.
265
+ def governor
266
+ @@scaling_g ||= cpus.map { |x|
267
+ [File.split(x)[-1], File.join(x, 'cpufreq/scaling_governor'.freeze)]
268
+ }
269
+
270
+ h = {}
271
+ @@scaling_g.each { |id, file|
272
+ h.merge!(id => IO.read(file).tap(&:strip!)) if File.readable?(file)
273
+ }
274
+
275
+ h
276
+ end
277
+
278
+ ##
279
+ # Returns an array of governors for each CPU as a Hash.
280
+ #
281
+ # For example:
282
+ # LinuxStat::CPU.available_governors
283
+ #
284
+ # => {"cpu0"=>["performance", "powersave"], "cpu1"=>["performance", "powersave"], "cpu2"=>["performance", "powersave"], "cpu3"=>["performance", "powersave"]}
285
+ #
286
+ # If the information isn't available, it will return an empty Hash.
287
+ def available_governors
288
+ @@scaling_av_g ||= cpus.map { |x|
289
+ [File.split(x)[-1], File.join(x, 'cpufreq/scaling_available_governors'.freeze)]
290
+ }
291
+
292
+ h = {}
293
+ @@scaling_av_g.each { |id, file|
294
+ h.merge!(id => IO.read(file).split.each(&:strip!)) if File.readable?(file)
295
+ }
296
+
297
+ h
140
298
  end
141
299
 
142
300
  alias usages stat
@@ -144,7 +302,7 @@ module LinuxStat
144
302
 
145
303
  private
146
304
  def cpuinfo
147
- File.readable?('/proc/cpuinfo') ? IO.readlines('/proc/cpuinfo') : []
305
+ File.readable?('/proc/cpuinfo') ? IO.readlines('/proc/cpuinfo').freeze : [].freeze
148
306
  end
149
307
 
150
308
  def stat?
@@ -155,7 +313,12 @@ module LinuxStat
155
313
  # ticks to ms times 5
156
314
  # If the ticks is 100, it will return 0.05
157
315
  def ticks_to_ms_t5
158
- @@ms_t5 ||= 1.0 / LinuxStat::Sysconf.sc_clk_tck * 5
316
+ @@sc_clk_tck ||= LinuxStat::Sysconf.sc_clk_tck.to_i
317
+ @@ms_t5 ||= 1.0 / (@@sc_clk_tck < 1 ? 100 : @@sc_clk_tck) * 5
318
+ end
319
+
320
+ def cpus
321
+ @@all_cpu = Dir["/sys/devices/system/cpu/cpu[0-9]*/"].sort!.freeze
159
322
  end
160
323
  end
161
324
  end
@@ -2,7 +2,7 @@ module LinuxStat
2
2
  module Filesystem
3
3
  class << self
4
4
  ##
5
- # = stat(fs = '/')
5
+ # = stat(fs = '.')
6
6
  #
7
7
  # Where fs is the directory of the file system (like / or /tmp/ or /run/media/thumbdrive).
8
8
  #
@@ -16,7 +16,7 @@ module LinuxStat
16
16
  # {:total=>119981191168, :free=>43155574784, :used=>76825616384, :available=>43155574784}
17
17
  #
18
18
  # If the stat can't be acquired, this method will return an empty Hash.
19
- def stat(fs = ?/.freeze)
19
+ def stat(fs = ?..freeze)
20
20
  s = stat_raw(fs)
21
21
  return {} if s.empty?
22
22
  s.default = 0
@@ -29,14 +29,14 @@ module LinuxStat
29
29
  end
30
30
 
31
31
  ##
32
- # = total(fs = '/')
32
+ # = total(fs = '.')
33
33
  #
34
34
  # Where fs is the directory of the file system (like / or /tmp/ or /run/media/thumbdrive).
35
35
  #
36
36
  # It returns the total size of a given disk in bytes.
37
37
  #
38
38
  # If the stat can't be acquired, this method will return nil.
39
- def total(fs = ?/.freeze)
39
+ def total(fs = ?..freeze)
40
40
  s = stat_raw(fs)
41
41
  return nil if s.empty?
42
42
  s.default = 0
@@ -44,7 +44,7 @@ module LinuxStat
44
44
  end
45
45
 
46
46
  ##
47
- # = free(fs = '/')
47
+ # = free(fs = '.')
48
48
  #
49
49
  # Where fs is the directory of the file system (like / or /tmp/ or /run/media/thumbdrive).
50
50
  #
@@ -55,7 +55,7 @@ module LinuxStat
55
55
  # Free returns the size of free blocks.
56
56
  #
57
57
  # If the stat can't be acquired, this method will return an empty Hash.
58
- def free(fs = ?/.freeze)
58
+ def free(fs = ?..freeze)
59
59
  s = stat_raw(fs)
60
60
  return nil if s.empty?
61
61
  s.default = 0
@@ -63,14 +63,14 @@ module LinuxStat
63
63
  end
64
64
 
65
65
  ##
66
- # = used(fs = '/')
66
+ # = used(fs = '.')
67
67
  #
68
68
  # Where fs is the directory of the file system (like / or /tmp/ or /run/media/thumbdrive).
69
69
  #
70
70
  # It returns the used space of a given disk in bytes.
71
71
  #
72
72
  # If the stat can't be acquired, this method will return nil.
73
- def used(fs = ?/.freeze)
73
+ def used(fs = ?..freeze)
74
74
  s = stat_raw(fs)
75
75
  return nil if s.empty?
76
76
  s.default = 0
@@ -78,7 +78,7 @@ module LinuxStat
78
78
  end
79
79
 
80
80
  ##
81
- # = available(fs = '/')
81
+ # = available(fs = '.')
82
82
  #
83
83
  # Where fs is the directory of the file system (like / or /tmp/ or /run/media/thumbdrive).
84
84
  #
@@ -89,7 +89,7 @@ module LinuxStat
89
89
  # Available returns the size of free blocks for unpriviledged users.
90
90
  #
91
91
  # If the stat can't be acquired, this method will return an empty Hash.
92
- def available(fs = ?/.freeze)
92
+ def available(fs = ?..freeze)
93
93
  s = stat_raw(fs)
94
94
  return nil if s.empty?
95
95
  s.default = 0
@@ -97,7 +97,7 @@ module LinuxStat
97
97
  end
98
98
 
99
99
  ##
100
- # = stat_raw(fs = '/')
100
+ # = stat_raw(fs = '.')
101
101
  #
102
102
  # Where fs is the directory of the file system (like / or /tmp/ or /run/media/thumbdrive).
103
103
  #
@@ -105,7 +105,7 @@ module LinuxStat
105
105
  # {:block_size=>4096, :fragment_size=>4096, :blocks=>29292283, :block_free=>10535967, :block_avail_unpriv=>10535967, :inodes=>58612160, :free_inodes=>56718550, :filesystem_id=>2050, :mount_flags=>1024, :max_filename_length=>255}
106
106
  #
107
107
  # If the stat can't be acquired, this method will return an empty Hash.
108
- def stat_raw(fs = ?/.freeze)
108
+ def stat_raw(fs = ?..freeze)
109
109
  LinuxStat::FS.stat(fs)
110
110
  end
111
111
  end
@@ -185,7 +185,7 @@ module LinuxStat
185
185
 
186
186
  private
187
187
  def splitted
188
- @@string_splitted ||= string.split
188
+ @@string_splitted ||= string.split.freeze
189
189
  end
190
190
  end
191
191
  end
@@ -62,7 +62,7 @@ module LinuxStat
62
62
  end
63
63
 
64
64
  ##
65
- # mount_point(dev = root)
65
+ # = mount_point(dev = root)
66
66
  #
67
67
  # Where device = block device.
68
68
  #
@@ -94,7 +94,7 @@ module LinuxStat
94
94
  end
95
95
 
96
96
  ##
97
- # list_devices_mount_point()
97
+ # = list_devices_mount_point()
98
98
  #
99
99
  # It shows all the block devices corresponding to mount points.
100
100
  #
@@ -120,7 +120,7 @@ module LinuxStat
120
120
  end
121
121
 
122
122
  ##
123
- # devices_stat
123
+ # = devices_stat
124
124
  #
125
125
  # [ Not to confuse this method with device_stat(dev) which shows only one device's info ]
126
126
  #
@@ -162,7 +162,7 @@ module LinuxStat
162
162
  end
163
163
 
164
164
  ##
165
- # device_stat(dev = root)
165
+ # = device_stat(dev = root)
166
166
  #
167
167
  # [ Not to confuse this method with devices_stat() which shows all devices ]
168
168
  #