linux_stat 0.7.4 → 0.9.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.
@@ -2,7 +2,7 @@ module LinuxStat
2
2
  module CPU
3
3
  class << self
4
4
  ##
5
- # = stat(sleep = 1.0 / LinuxStat::Sysconf.sc_clk_tck)
5
+ # = stat(sleep = 1.0 / LinuxStat::Sysconf.sc_clk_tck * 5)
6
6
  #
7
7
  # Where sleep is the delay to gather the data.
8
8
  #
@@ -14,18 +14,20 @@ 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
- def stat(sleep = ticks_to_ms)
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
- # On devices like android, the core count can change anytime.
30
+ # On devices like android, the core count can change anytime (hotplugging).
29
31
  # I had crashes on Termux.
30
32
  # So better just count the min number of CPU and iterate over that
31
33
  # If data.length is smaller than data2.length, we don't have enough data to compare.
@@ -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
 
@@ -60,28 +60,119 @@ module LinuxStat
60
60
  # It's like running LinuxStat::CPU.stat[0] but it's much more efficient and calculates just the aggregated usage which is available at the top of the /proc/stat file.
61
61
  #
62
62
  # If the information is not available, it will return nil.
63
- def total_usage(sleep = ticks_to_ms)
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)
76
78
  end
77
79
 
78
80
  ##
79
- # Returns the total number of CPU threads.
81
+ # Returns the total number of CPU available for the sysetm.
82
+ #
83
+ # It returns an Integer.
80
84
  #
81
- # If the information isn't available, it will return 0.
85
+ # If the information isn't available, it will return nil.
82
86
  def count
83
- # CPU count can change during the program runtime
84
- cpuinfo.count { |x| x.start_with?('processor') }
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
121
+ end
122
+
123
+ ##
124
+ # Returns the total number of CPU online in the sysetm.
125
+ #
126
+ # It will read /proc/stat to get the info.
127
+ #
128
+ # If the info isn't available, it reads /sys/devices/system/cpu/onfline and
129
+ # performs various job to get one Ruby array.
130
+ #
131
+ # If the information isn't available, it will return an empty Array.
132
+ def online
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
152
+
153
+ ret
154
+ end
155
+
156
+ ##
157
+ # Returns the total number of CPU offline in the sysetm.
158
+ #
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
167
+
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
85
176
  end
86
177
 
87
178
  ##
@@ -95,33 +186,115 @@ module LinuxStat
95
186
  end
96
187
 
97
188
  ##
98
- # 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
99
193
  #
100
- # 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.
101
197
  def cur_freq
102
- @@cpu_freqs ||= Dir["/sys/devices/system/cpu/cpu[0-9]*/cpufreq/scaling_cur_freq"]
103
- @@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
+ }
104
201
 
105
- if @@cur_freqs_readable
106
- @@cpu_freqs.map { |x| IO.read(x).to_i }
107
- else
108
- []
109
- 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
110
208
  end
111
209
 
112
210
  ##
113
- # Returns an array with max core frequencies corresponding to the usages.
211
+ # Returns a Hash with max core frequencies corresponding to the CPUs.
212
+ #
213
+ # For example:
214
+ # LinuxStat::CPU.min_freq
114
215
  #
115
- # If the information isn't available, it will return an empty array.
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.
116
241
  def max_freq
117
- @@max_freqs ||= Dir["/sys/devices/system/cpu/cpu[0-9]*/cpufreq/scaling_max_freq"]
118
- @@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
+ }
119
245
 
120
- if @@max_freqs_readable
121
- @@max_freqs.map { |x| IO.read(x).to_i }
122
- else
123
- []
124
- 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
125
298
  end
126
299
 
127
300
  alias usages stat
@@ -129,15 +302,23 @@ module LinuxStat
129
302
 
130
303
  private
131
304
  def cpuinfo
132
- File.readable?('/proc/cpuinfo') ? IO.readlines('/proc/cpuinfo') : []
305
+ File.readable?('/proc/cpuinfo') ? IO.readlines('/proc/cpuinfo').freeze : [].freeze
133
306
  end
134
307
 
135
308
  def stat?
136
309
  @@stat_readable ||= File.readable?('/proc/stat')
137
310
  end
138
311
 
139
- def ticks_to_ms
140
- @@ms ||= 1.0 / LinuxStat::Sysconf.sc_clk_tck
312
+ # Just to avoid duplicate calculations
313
+ # ticks to ms times 5
314
+ # If the ticks is 100, it will return 0.05
315
+ def ticks_to_ms_t5
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
141
322
  end
142
323
  end
143
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
@@ -121,7 +121,7 @@ module LinuxStat
121
121
  hour: h,
122
122
  minute: m,
123
123
  second: s
124
- }
124
+ }.freeze
125
125
  end
126
126
 
127
127
  private
@@ -143,7 +143,7 @@ module LinuxStat
143
143
  end
144
144
 
145
145
  def uptime_readable?
146
- @@uptime_readable = File.readable?('/proc/uptime')
146
+ @@uptime_readable ||= File.readable?('/proc/uptime')
147
147
  end
148
148
  end
149
149
  end