linux_stat 0.7.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.
@@ -7,6 +7,46 @@ rescue LoadError
7
7
  abort "The Gem needs to be installed before this test can be run!"
8
8
  end
9
9
 
10
+ # Gradient colour to strings
11
+ class String
12
+ def colourize(colour = 1, flip: false)
13
+ colours, line_length = [], -1
14
+ temp = ''
15
+
16
+ each_line do |c|
17
+ n, i = c.length, -1
18
+
19
+ if line_length != n
20
+ step, line_length = 255.0./(n), n
21
+ colours.clear
22
+
23
+ while (i += 1) < n
24
+ l = i.*(step)
25
+ colours.<<(
26
+ case colour
27
+ when 0 then [ l.*(2).to_i.clamp(0, 255), l.to_i.clamp(0, 255), 255.-(l).to_i.clamp(0, 255) ]
28
+ when 1 then [ 255, 255.-(l).to_i.clamp(0, 255), l.to_i.clamp(0, 255) ]
29
+ when 2 then [ l.to_i.clamp(0, 255), 255.-(l).to_i.clamp(0, 255), l.to_i.clamp(0, 255) ]
30
+ when 3 then [ l.*(2).to_i.clamp(0, 255), 255.-(l).to_i.clamp(0, 255), 100.+(l / 2).to_i.clamp(0, 255) ]
31
+ when 4 then [ 30, 255.-(l / 2).to_i.clamp(0, 255), 110.+(l / 2).to_i.clamp(0, 255) ]
32
+ when 5 then [ 255.-(l * 2).to_i.clamp(0, 255), l.to_i.clamp(0, 255), 200 ]
33
+ when 6 then [ 50.+(255 - l).to_i.clamp(0, 255), 255.-(l / 2).to_i.clamp(0, 255), (l * 2).to_i.clamp(0, 255) ]
34
+ else [ l.*(2).to_i.clamp(0, 255), 255.-(l).to_i.clamp(0, 255), 100.+(l / 2).to_i.clamp(0, 255) ]
35
+ end
36
+ )
37
+ end
38
+
39
+ colours.reverse! if flip
40
+ end
41
+
42
+ i = -1
43
+ temp.concat "\e[38;2;#{colours[i][0]};#{colours[i][1]};#{colours[i][2]}m#{c[i]}" while (i += 1) < n
44
+ end
45
+
46
+ temp << "\e[0m".freeze
47
+ end
48
+ end
49
+
10
50
  # Check which conflicting argument (e.g., `-md -html` together) is passed last
11
51
  # Always use the last argument
12
52
  conflicting, hash = [
@@ -36,17 +76,23 @@ MARKDOWN, HTML = hash[:markdown], hash[:html]
36
76
 
37
77
  # Print time each method takes unless --no-time or -nt option is passed
38
78
  PRINT_TIME = (MARKDOWN || HTML) ? false : !ARGV.any? { |x| x[/^\-\-no-time$/] || x[/^\-nt$/] }
39
-
40
- %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))
41
81
 
42
82
  # Run only desired classes / modules
43
83
  constants = LinuxStat.constants
44
84
 
85
+ # Modules to delete from documentation and testing
86
+ %i(
87
+ Nproc
88
+ ).each(&constants.method(:delete))
89
+
45
90
  execute = constants.map(&:downcase).map.with_index { |x, i|
46
91
  constants[i] if ARGV.find { |y| y.downcase.to_sym == x }
47
92
  }.compact
48
93
 
49
94
  execute.replace(constants) if execute.empty?
95
+ HEXAGONS = %W(\u2b22 \u2b23 \u2B53 \u2B1F)
50
96
 
51
97
  execute.sort.each do |c|
52
98
  e = eval("LinuxStat::#{c}")
@@ -54,7 +100,6 @@ execute.sort.each do |c|
54
100
  next if e.class != Module && e.class != Class
55
101
 
56
102
  meths = e.methods(false).sort
57
- next if meths.any? { |a| e.method(a).arity > 0 }
58
103
 
59
104
  if meths.length > 0
60
105
  if MARKDOWN
@@ -67,20 +112,83 @@ execute.sort.each do |c|
67
112
  end
68
113
 
69
114
  meths.each do |meth|
115
+ arg = nil
116
+ params = e.method(meth).parameters
117
+
118
+ param = ''
119
+
120
+ params.each do |p|
121
+ case p[0]
122
+ when :opt
123
+ param << "#{p[1]}, "
124
+ when :key
125
+ param << "#{p[1]}:, "
126
+ when :req
127
+ param << "#{p[1] || 'arg'}, "
128
+ end
129
+ end
130
+
131
+ param.delete_suffix!(", ")
132
+
133
+ if e.method(meth).arity > 0
134
+ if c == :PrettifyBytes
135
+ arg = rand(10 ** 15)
136
+ elsif c == :FS
137
+ arg = '/'
138
+ else
139
+ next
140
+ end
141
+ end
142
+
143
+ disp_meth = "#{meth}"
144
+ disp_meth.concat(arg ? "(#{param} = #{arg.inspect})" : "(#{param})")
145
+
70
146
  time = Time.now
71
- v = e.send(meth)
147
+ ret = arg ? e.send(meth, arg) : e.send(meth)
72
148
  time2 = Time.now
73
149
  time = time2.-(time).*(1_000_000).round(3)
74
150
 
75
- v = v.inspect
151
+ v = ret.inspect
76
152
  dis = v.length > 253 ? v[0..250].strip + '...'.freeze : v
77
153
 
154
+ source = e.singleton_method(meth).source_location.to_a
155
+ src, src_meth, src_ret = '', '', ''
156
+
157
+ unless source.empty?
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
174
+
175
+ if MARKDOWN || HTML
176
+ src.prepend('#'.freeze)
177
+ src_meth.prepend('#'.freeze)
178
+ src_ret.prepend(?#.freeze) if PRINT_TYPE
179
+ else
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
183
+ end
184
+ end
185
+
78
186
  if MARKDOWN
79
- puts "#{e}.#{meth}\n=> #{dis}"
187
+ puts "#{src}#{src_meth}#{src_ret}#{e}.#{disp_meth}\n=> #{dis}"
80
188
  elsif HTML
81
- puts "#{e}.#{meth}\n=> #{dis}"
189
+ puts "#{src}#{src_meth}#{src_ret}#{e}.#{disp_meth}\n=> #{dis}"
82
190
  else
83
- puts "\e[1;38;2;80;80;255m#{e}.#{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}"
84
192
  end
85
193
 
86
194
  puts( "(" +
@@ -1,8 +1,15 @@
1
1
  #include <sys/statvfs.h>
2
2
  #include "ruby.h"
3
3
 
4
- #pragma GCC optimize ("O3")
5
- #pragma clang optimize on
4
+ #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
5
+ #pragma GCC optimize ("O3")
6
+ #pragma GCC diagnostic warning "-Wall"
7
+ #elif defined(__clang__)
8
+ #pragma clang optimize on
9
+ #pragma clang diagnostic warning "-Wall"
10
+ #elif defined(__INTEL_COMPILER)
11
+ #pragma intel optimization_level 3
12
+ #endif
6
13
 
7
14
  static VALUE statfs(VALUE obj, VALUE dir) {
8
15
  struct statvfs buf ;
@@ -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,8 +1,15 @@
1
1
  #include <unistd.h>
2
2
  #include "ruby.h"
3
3
 
4
- #pragma GCC optimize ("O3")
5
- #pragma clang optimize on
4
+ #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
5
+ #pragma GCC optimize ("O3")
6
+ #pragma GCC diagnostic warning "-Wall"
7
+ #elif defined(__clang__)
8
+ #pragma clang optimize on
9
+ #pragma clang diagnostic warning "-Wall"
10
+ #elif defined(__INTEL_COMPILER)
11
+ #pragma intel optimization_level 3
12
+ #endif
6
13
 
7
14
  static VALUE getTick(VALUE obj) {
8
15
  return INT2FIX(sysconf(_SC_CLK_TCK)) ;
@@ -40,6 +47,22 @@ static VALUE getPosixVersion(VALUE obj) {
40
47
  return INT2FIX(sysconf(_SC_VERSION)) ;
41
48
  }
42
49
 
50
+ static VALUE getLineMax(VALUE obj) {
51
+ return INT2FIX(sysconf(_SC_LINE_MAX)) ;
52
+ }
53
+
54
+ static VALUE getExprNestMax(VALUE obj) {
55
+ return INT2FIX(sysconf(_SC_EXPR_NEST_MAX)) ;
56
+ }
57
+
58
+ static VALUE getProcessorConfigured(VALUE obj) {
59
+ return INT2FIX(sysconf(_SC_NPROCESSORS_CONF)) ;
60
+ }
61
+
62
+ static VALUE getProcessorOnline(VALUE obj) {
63
+ return INT2FIX(sysconf(_SC_NPROCESSORS_ONLN)) ;
64
+ }
65
+
43
66
  static VALUE getUser(VALUE obj) {
44
67
  char *name = getlogin() ;
45
68
  return name ? rb_str_new_cstr(name) : rb_str_new_cstr("") ;
@@ -70,6 +93,11 @@ void Init_sysconf() {
70
93
  rb_define_module_function(_sysconf, "stream_max", getStreamMax, 0) ;
71
94
  rb_define_module_function(_sysconf, "tty_name_max", getTTYNameMax, 0) ;
72
95
  rb_define_module_function(_sysconf, "posix_version", getPosixVersion, 0) ;
96
+ rb_define_module_function(_sysconf, "line_max", getLineMax, 0) ;
97
+ rb_define_module_function(_sysconf, "expr_nest_max", getExprNestMax, 0) ;
98
+
99
+ rb_define_module_function(_sysconf, "processor_online", getProcessorOnline, 0) ;
100
+ rb_define_module_function(_sysconf, "processor_configured", getProcessorConfigured, 0) ;
73
101
 
74
102
  rb_define_module_function(_sysconf, "get_uid", getUID, 0) ;
75
103
  rb_define_module_function(_sysconf, "get_gid", getGID, 0) ;
@@ -1,39 +1,51 @@
1
1
  #include <sys/utsname.h>
2
2
  #include "ruby.h"
3
3
 
4
- #pragma GCC optimize ("O3")
5
- #pragma clang optimize on
4
+ #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
5
+ #pragma GCC optimize ("O3")
6
+ #pragma GCC diagnostic warning "-Wall"
7
+ #elif defined(__clang__)
8
+ #pragma clang optimize on
9
+ #pragma clang diagnostic warning "-Wall"
10
+ #elif defined(__INTEL_COMPILER)
11
+ #pragma intel optimization_level 3
12
+ #endif
6
13
 
7
14
  static struct utsname buf ;
8
- static short status ;
15
+
16
+ static char *sysname = "", *nodename = "" ;
17
+ static char *release = "", *version = "", *machine = "" ;
9
18
 
10
19
  void init_buf() {
11
- status = uname(&buf) ;
20
+ short status = uname(&buf) ;
21
+
22
+ if (status > -1) {
23
+ sysname = buf.sysname ;
24
+ nodename = buf.nodename ;
25
+ release = buf.release ;
26
+ version = buf.version ;
27
+ machine = buf.machine ;
28
+ }
12
29
  }
13
30
 
14
31
  static VALUE getSysname(VALUE obj) {
15
- VALUE sysname = status < 0 ? rb_str_new_cstr("") : rb_str_new_cstr(buf.sysname) ;
16
- return sysname ;
32
+ return rb_str_new_cstr(sysname) ;
17
33
  }
18
34
 
19
35
  static VALUE getNodename(VALUE obj) {
20
- VALUE nodename = status < 0 ? rb_str_new_cstr("") : rb_str_new_cstr(buf.nodename) ;
21
- return nodename ;
36
+ return rb_str_new_cstr(nodename) ;
22
37
  }
23
38
 
24
39
  static VALUE getRelease(VALUE obj) {
25
- VALUE release = status < 0 ? rb_str_new_cstr("") : rb_str_new_cstr(buf.release) ;
26
- return release ;
40
+ return rb_str_new_cstr(release) ;
27
41
  }
28
42
 
29
43
  static VALUE getVersion(VALUE obj) {
30
- VALUE version = status < 0 ? rb_str_new_cstr("") : rb_str_new_cstr(buf.version) ;
31
- return version ;
44
+ return rb_str_new_cstr(version) ;
32
45
  }
33
46
 
34
47
  static VALUE getMachine(VALUE obj) {
35
- VALUE machine = status < 0 ? rb_str_new_cstr("") : rb_str_new_cstr(buf.machine) ;
36
- return machine ;
48
+ return rb_str_new_cstr(machine) ;
37
49
  }
38
50
 
39
51
  void Init_utsname() {
@@ -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
@@ -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,7 +60,7 @@ 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
66
  data = IO.foreach('/proc/stat').first.split.tap(&:shift).map!(&:to_f)
@@ -72,16 +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)
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.
80
82
  #
81
- # If the information isn't available, it will return 0.
83
+ # It returns an Integer.
84
+ #
85
+ # If the information isn't available, it will return an empty Array.
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 opens /sys/devices/system/cpu/offline and
94
+ # performs various job to get one Ruby array.
95
+ #
96
+ # If the information isn't available, it will return an empty Array.
97
+ def online
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
+ }
108
+
109
+ ret
110
+ end
111
+
112
+ ##
113
+ # Returns the total number of CPU offline in the sysetm.
114
+ #
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
+ }
130
+
131
+ ret
85
132
  end
86
133
 
87
134
  ##
@@ -95,33 +142,115 @@ module LinuxStat
95
142
  end
96
143
 
97
144
  ##
98
- # Returns an array with current core frequencies corresponding to the usages.
145
+ # Returns a Hash with current core frequencies corresponding to the CPUs.
99
146
  #
100
- # 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.
101
153
  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?))
154
+ @@cur_f ||= cpus.map { |x|
155
+ [File.split(x)[-1], File.join(x, 'cpufreq/scaling_cur_freq'.freeze)]
156
+ }
104
157
 
105
- if @@cur_freqs_readable
106
- @@cpu_freqs.map { |x| IO.read(x).to_i }
107
- else
108
- []
109
- 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
110
186
  end
111
187
 
112
188
  ##
113
- # Returns an array with max core frequencies corresponding to the usages.
189
+ # Returns a Hash with max core frequencies corresponding to the CPUs.
190
+ #
191
+ # For example:
192
+ # LinuxStat::CPU.max_freq
114
193
  #
115
- # If the information isn't available, it will return an empty array.
194
+ # => {"cpu0"=>2000000, "cpu1"=>2000000, "cpu2"=>2000000, "cpu3"=>2000000}
195
+ #
196
+ # If the information isn't available, it will return an empty Hash.
116
197
  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?))
198
+ @@min_f ||= cpus.map { |x|
199
+ [File.split(x)[-1], File.join(x, 'cpufreq/scaling_max_freq'.freeze)]
200
+ }
119
201
 
120
- if @@max_freqs_readable
121
- @@max_freqs.map { |x| IO.read(x).to_i }
122
- else
123
- []
124
- 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
125
254
  end
126
255
 
127
256
  alias usages stat
@@ -129,15 +258,22 @@ module LinuxStat
129
258
 
130
259
  private
131
260
  def cpuinfo
132
- File.readable?('/proc/cpuinfo') ? IO.readlines('/proc/cpuinfo') : []
261
+ File.readable?('/proc/cpuinfo') ? IO.readlines('/proc/cpuinfo').freeze : [].freeze
133
262
  end
134
263
 
135
264
  def stat?
136
265
  @@stat_readable ||= File.readable?('/proc/stat')
137
266
  end
138
267
 
139
- def ticks_to_ms
140
- @@ms ||= 1.0 / LinuxStat::Sysconf.sc_clk_tck
268
+ # Just to avoid duplicate calculations
269
+ # ticks to ms times 5
270
+ # If the ticks is 100, it will return 0.05
271
+ def ticks_to_ms_t5
272
+ @@ms_t5 ||= 1.0 / LinuxStat::Sysconf.sc_clk_tck * 5
273
+ end
274
+
275
+ def cpus
276
+ @@all_cpu = Dir["/sys/devices/system/cpu/cpu[0-9]*/"].sort!.freeze
141
277
  end
142
278
  end
143
279
  end