linux_stat 2.2.3 → 2.5.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f6509d9a0ed303d95d92e1d410bd2e8ee1046d0b320cdbc5a2c8230b20037614
4
- data.tar.gz: ca02da4c022fe3dfcb0a900537cc1389a602a8d79e5f300ffe206878d737e8f2
3
+ metadata.gz: 2fd7fd4cae80d13f9e3004928809ada275053cffc32630d05f7ab3f1fb9c2514
4
+ data.tar.gz: 36f07d5f2f149979466a30d63d6d8cc31e77a028454be0bbe25b2af0513e1bb4
5
5
  SHA512:
6
- metadata.gz: e0c2ce5029b1fb98812a18a6f5383f52b89b06fbf2bba3ed1bda29d880491cba781950ed3295e4a85b6040b8f62a68c6de390598bfd9d6cd53bd1f141e6815f3
7
- data.tar.gz: 40b493dc6dd1c9f862ceeab1ee2c24e3493996560cc214046167907f01fca9ec262dfa54f2d237212ec2cd50f84ae2b0ae5a41be62b6017c5833dc9895235807
6
+ metadata.gz: 2ef9b96aacee268b4c0d74a8093d4161a0d21fea3165533c0d0f993c6cda302f1e96f51a1292192b18ffed35b2a0f6e83fdb2ac03583da8e088e97ec2c230f19
7
+ data.tar.gz: 82c397f568ebfd7f578b401ec245b10971412931b06df1433e6637848f506a642eb68046025ad3c3a66bafe678aea1b4845507cbc9a2a13d80f107ec93d667c4
data/README.md CHANGED
@@ -38,18 +38,36 @@ It only works on Linux, and detecting the OS is upto the user of this gem.
38
38
  2. Ruby: Ruby 2.3.0 and above.
39
39
 
40
40
  ## Build Dependencies:
41
- + You need to have the C compiler installed to be able to compile the C extensions.
42
- On Arch Linux:
41
+ #### You need to have the C compiler installed to be able to compile the C extensions.
42
+
43
+ + On Arch Linux / Manjaro / Archlabs / Other Arch Based Distributions
44
+ ```
45
+ # pacman -S gcc make ruby
46
+ ```
47
+
48
+ + On Debian / Ubuntu / Linux Mint / Pop!_OS / Raspberry Pi OS / Other Debian Based Distributions
49
+ ```
50
+ # apt install gcc build-essential ruby ruby-dev build-essential
51
+ ```
52
+
53
+ + Gentoo / Gentoo Based Distributions
54
+ ```
55
+ # emerge --ask dev-lang/ruby
56
+ ```
57
+
58
+ + Fedora / AmazonLinux* / CentOS* / Other RedHat Based Distributions
43
59
  ```
44
- # pacman -S gcc make
60
+ # yum install gcc ruby-devel ruby make
45
61
  ```
46
62
 
47
- On Debian based systems:
63
+ You can run linux_stat on *AmazonLinux and *CentOS if you have Ruby 2.3.0+.
64
+
65
+ + OpenSUSE
48
66
  ```
49
- # apt install gcc build-essential ruby-dev
67
+ # zypper install gcc ruby ruby-devel make
50
68
  ```
51
69
 
52
- + You can remove the packages once the program is installed.
70
+ + You can remove the above packages once the gem is installed.
53
71
 
54
72
  ---
55
73
 
@@ -62,13 +80,28 @@ You can install hwdata simply.
62
80
  + Arch:
63
81
 
64
82
  ```
65
- sudo pacman -S hwids
83
+ # pacman -S hwids
66
84
  ```
67
85
 
68
86
  + Debian based systems:
69
87
 
70
88
  ```
71
- sudo apt install hwdata
89
+ # apt install hwdata
90
+ ```
91
+
92
+ + Gentoo / Gentoo Based Distributions
93
+ ```
94
+ # emerge --ask sys-apps/hwids
95
+ ```
96
+
97
+ + Fedora / Amazon Linux / CentOS
98
+ ```
99
+ # yum install hwdata
100
+ ```
101
+
102
+ + OpenSUSE
103
+ ```
104
+ zypper install hwdata
72
105
  ```
73
106
 
74
107
  But without hwdata, it won't show such information.
data/exe/linuxstat.rb CHANGED
@@ -7,6 +7,12 @@ rescue LoadError
7
7
  abort "The Gem needs to be installed before this test can be run!"
8
8
  end
9
9
 
10
+ # Time reporting format
11
+ T_FMT = '%d'.freeze
12
+
13
+ # Check the number of iterations
14
+ iterations = (ARGV.find { |x| LinuxStat::Misc.integer?(x) } || 1).to_i
15
+
10
16
  Integer.class_exec do
11
17
  define_method(:clamp) { |min, max|
12
18
  self < min ? min : self > max ? max : self
@@ -67,14 +73,14 @@ conflicting.each do |x, y, z|
67
73
  rev = ARGV.reverse
68
74
 
69
75
  if rev.index { |_x| _x[y] } < rev.index { |_x| _x[z] }
70
- hash.merge!(o1 => true)
76
+ hash.store(o1, true)
71
77
  else
72
- hash.merge!(o2 => true)
78
+ hash.store(o2, true)
73
79
  end
74
80
  elsif m1
75
- hash.merge!(o1 => true)
81
+ hash.store(o1, true)
76
82
  elsif m2
77
- hash.merge!(o2 => true)
83
+ hash.store(o2, true)
78
84
  end
79
85
  end
80
86
 
@@ -100,122 +106,166 @@ execute = constants.map(&:downcase).map.with_index { |x, i|
100
106
  execute.replace(constants) if execute.empty?
101
107
  HEXAGONS = %W(\u2b22 \u2b23 \u2B53 \u2B1F)
102
108
 
103
- execute.sort.each do |c|
104
- e = eval("LinuxStat::#{c}")
109
+ puts " #{HEXAGONS.rotate![0]} LinuxStat: #{LinuxStat::VERSION}"
110
+ puts " #{HEXAGONS.rotate![0]} Test Modules: #{execute.size}"
111
+ puts " #{HEXAGONS.rotate![0]} Iterations: #{iterations}"
105
112
 
106
- next if e.class != Module && e.class != Class
113
+ puts " #{HEXAGONS.rotate![0]} Format: Markdown" if MARKDOWN
114
+ puts " #{HEXAGONS.rotate![0]} Format: HTML" if HTML
107
115
 
108
- meths = e.methods(false).sort
116
+ sleep 2
117
+ puts
109
118
 
110
- if meths.length > 0
111
- if MARKDOWN
112
- puts "### LinuxStat::#{c}\n```"
113
- elsif HTML
114
- puts "<h3>LinuxStat::#{c}</h3>\n<pre>"
115
- else
116
- puts "\e[1;4;38;2;255;240;0mLinuxStat::#{c}\e[0m"
117
- end
119
+ def get_colour(n)
120
+ if n > 10_000
121
+ "\e[1;38;2;255;50;50m"
122
+ elsif n > 5_000
123
+ "\e[1;38;2;255;170;0m"
124
+ else
125
+ "\e[1;38;2;0;170;0m"
118
126
  end
127
+ end
128
+
129
+ total_real_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
130
+ total_cpu_time = Process.times
131
+
132
+ iterations.times do
133
+ execute.sort.each do |c|
134
+ e = eval("LinuxStat::#{c}")
135
+
136
+ next if e.class != Module && e.class != Class
119
137
 
120
- meths.each do |meth|
121
- arg = nil
138
+ meths = e.methods(false).sort
122
139
 
123
- arity = e.method(meth).arity
124
- if arity > 0 || arity == -2
125
- if c == :PrettifyBytes
126
- arg = rand(10 ** 15)
127
- elsif c == :FS
128
- arg = '/'
140
+ if meths.length > 0
141
+ if MARKDOWN
142
+ puts "### LinuxStat::#{c}\n```"
143
+ elsif HTML
144
+ puts "<h3>LinuxStat::#{c}</h3>\n<pre>"
129
145
  else
130
- next
146
+ puts "\e[1;4;38;2;255;240;0mLinuxStat::#{c}\e[0m"
131
147
  end
132
148
  end
133
149
 
134
- params = e.method(meth).parameters
135
- param = ''
136
- params.each do |p|
137
- case p[0]
138
- when :opt
139
- param << "#{p[1]}, "
140
- when :key
141
- param << "#{p[1]}:, "
142
- when :req
143
- _arg = arg ? " = #{arg.inspect}" : ''.freeze
144
- param << "#{p[1] || 'arg'}#{_arg}, "
150
+ meths.each do |meth|
151
+ arg = nil
152
+
153
+ arity = e.method(meth).arity
154
+ if arity > 0 || arity == -2
155
+ if c == :PrettifyBytes
156
+ arg = rand(10 ** 15)
157
+ elsif c == :FS
158
+ arg = '/'
159
+ else
160
+ next
161
+ end
145
162
  end
146
- end
147
163
 
148
- param.chomp!(", ")
149
-
150
- disp_meth = "#{meth}"
151
- disp_meth.concat(arg ? "(#{param})" : "(#{param})")
152
-
153
- time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
154
- ret = arg ? e.send(meth, arg) : e.send(meth)
155
- time2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
156
- time = time2.-(time).*(1_000_000).round(3)
157
-
158
- v = ret.inspect
159
- dis = v.length > 253 ? v[0..250].strip + '...'.freeze : v
160
-
161
- source = e.singleton_method(meth).source_location.to_a
162
- src, src_meth, src_ret = '', '', ''
163
-
164
- unless source.empty?
165
- src << " File:\t\t#{File.split(source[0])[-1]} | Line: #{source[1]}\n"
166
- src_meth << " Definition:\t#{IO.foreach(source[0]).first(source[1])[-1].strip}\n"
167
-
168
- src_ret << " Returns:\t" << case ret
169
- when Array then 'Array | Empty Array'
170
- when Complex then 'Complex | nil'
171
- when Float then 'Float | nil'
172
- when Hash then 'Hash | Empty Hash'
173
- when Integer then 'Integer | nil'
174
- when Rational then 'Rational | nil'
175
- when String then "String | (Frozen) Empty String"
176
- when Time then 'Time | nil'
177
- when true, false then 'True or False | nil'
178
- when nil then 'nil'
179
- else ''
180
- end << ?\n.freeze if PRINT_TYPE
181
-
182
- if MARKDOWN || HTML
183
- src.prepend('#'.freeze)
184
- src_meth.prepend('#'.freeze)
185
- src_ret.prepend(?#.freeze) if PRINT_TYPE
186
- else
187
- src.prepend(HEXAGONS.rotate![0].freeze)
188
- src_meth.prepend(HEXAGONS.rotate![0].freeze)
189
- src_ret.prepend(HEXAGONS.rotate![0].freeze) if PRINT_TYPE
164
+ params = e.method(meth).parameters
165
+ param = ''
166
+ params.each do |p|
167
+ case p[0]
168
+ when :opt
169
+ param << "#{p[1]}, "
170
+ when :key
171
+ param << "#{p[1]}:, "
172
+ when :req
173
+ _arg = arg ? " = #{arg.inspect}" : ''.freeze
174
+ param << "#{p[1] || 'arg'}#{_arg}, "
175
+ end
190
176
  end
191
- end
192
177
 
193
- if MARKDOWN
194
- puts "#{src}#{src_meth}#{src_ret}#{e}.#{disp_meth}\n=> #{dis}"
195
- elsif HTML
196
- puts "#{src}#{src_meth}#{src_ret}#{e}.#{disp_meth}\n=> #{dis}"
197
- else
198
- 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}"
199
- end
178
+ param.chomp!(", ")
179
+
180
+ disp_meth = "#{meth}"
181
+ disp_meth.concat(arg ? "(#{param})" : "(#{param})")
182
+
183
+ time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
184
+ cputime = Process.times
185
+
186
+ ret = arg ? e.send(meth, arg) : e.send(meth)
187
+
188
+ time2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
189
+ cputime2 = Process.times
190
+
191
+ time = time2.-(time).*(1_000_000)
192
+ cputime = cputime2.stime.+(cputime2.utime).-(cputime.stime + cputime.utime).*(1_000_000)
193
+
194
+ v = ret.inspect
195
+ dis = v.length > 253 ? v[0..250].strip + '...'.freeze : v
196
+
197
+ source = e.singleton_method(meth).source_location.to_a
198
+ src, src_meth, src_ret = '', '', ''
199
+
200
+ unless source.empty?
201
+ src << " File:\t\t#{File.split(source[0])[-1]} | Line: #{source[1]}\n"
202
+ src_meth << " Definition:\t#{IO.foreach(source[0]).first(source[1])[-1].strip}\n"
203
+
204
+ src_ret << " Returns:\t" << case ret
205
+ when Array then 'Array | Empty Array'
206
+ when Complex then 'Complex | nil'
207
+ when Float then 'Float | nil'
208
+ when Hash then 'Hash | Empty Hash'
209
+ when Integer then 'Integer | nil'
210
+ when Rational then 'Rational | nil'
211
+ when String then "String | (Frozen) Empty String"
212
+ when Time then 'Time | nil'
213
+ when true, false then 'True or False | nil'
214
+ when nil then 'nil'
215
+ else ''
216
+ end << ?\n.freeze if PRINT_TYPE
217
+
218
+ if MARKDOWN || HTML
219
+ src.prepend('#'.freeze)
220
+ src_meth.prepend('#'.freeze)
221
+ src_ret.prepend(?#.freeze) if PRINT_TYPE
222
+ else
223
+ src.prepend(HEXAGONS.rotate![0].freeze)
224
+ src_meth.prepend(HEXAGONS.rotate![0].freeze)
225
+ src_ret.prepend(HEXAGONS.rotate![0].freeze) if PRINT_TYPE
226
+ end
227
+ end
200
228
 
201
- puts( "(" +
202
- if time > 10_000
203
- "\e[1;38;2;255;50;50m"
204
- elsif time > 5_000
205
- "\e[1;38;2;255;170;0m"
229
+ if MARKDOWN
230
+ puts "#{src}#{src_meth}#{src_ret}#{e}.#{disp_meth}\n=> #{dis}"
231
+ elsif HTML
232
+ puts "#{src}#{src_meth}#{src_ret}#{e}.#{disp_meth}\n=> #{dis}"
206
233
  else
207
- "\e[1;38;2;0;170;0m"
208
- end + "Time taken: #{time}\u03BCs\e[0m)"
209
- ) if PRINT_TIME
234
+ 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}"
235
+ end
210
236
 
211
- puts
212
- end
237
+ if PRINT_TIME
238
+ time_colour = get_colour(time)
239
+ cputime_colour = get_colour(cputime)
240
+
241
+ puts "[Real Time: #{time_colour}#{T_FMT % time}\u03BCs\e[0m, "\
242
+ "CPU Time: #{cputime_colour}#{T_FMT % cputime}\u03BCs\e[0m]"
243
+ end
244
+
245
+ puts
246
+ end
213
247
 
214
- if meths.length > 0
215
- if MARKDOWN
216
- puts "```\n\n"
217
- elsif HTML
218
- puts "</pre>"
248
+ if meths.length > 0
249
+ if MARKDOWN
250
+ puts "```\n\n"
251
+ elsif HTML
252
+ puts "</pre>"
253
+ end
219
254
  end
220
255
  end
221
256
  end
257
+
258
+ if PRINT_TIME
259
+ total_real_time2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
260
+ total_cpu_time2 = Process.times
261
+
262
+ total_real_t = total_real_time2.-(total_real_time).*(1_000_000)
263
+
264
+ total_cpu_t = total_cpu_time2.stime.+(total_cpu_time2.utime).-(
265
+ total_cpu_time.stime + total_cpu_time.utime
266
+ ).*(1_000_000)
267
+
268
+ puts "\e[38;2;255;255;0m:: Warning total time also depends on your terminal speed!\e[0m"
269
+ puts "Total Real Time: #{T_FMT % total_real_t}\u03BCs"
270
+ puts "Total CPU Time: #{T_FMT % total_cpu_t}\u03BCs"
271
+ end
@@ -0,0 +1,25 @@
1
+ static VALUE getDiskStats (volatile VALUE obj, volatile VALUE path) {
2
+ FILE *file = fopen("/proc/diskstats", "r") ;
3
+ if(!file) return rb_ary_new() ;
4
+
5
+ char lines[120] ;
6
+ unsigned long long read, write ;
7
+ char *p = StringValuePtr(path) ;
8
+
9
+ while(fgets(lines, 119, file)) {
10
+ sscanf(lines, "%*s %*s %s %*s %*s %llu %*s %*s %*s %llu", lines, &read, &write) ;
11
+
12
+ if(strcmp(lines, p) == 0) {
13
+ fclose(file) ;
14
+
15
+ return rb_ary_new_from_args(
16
+ 2,
17
+ ULL2NUM(read),
18
+ ULL2NUM(write)
19
+ ) ;
20
+ }
21
+ }
22
+
23
+ fclose(file) ;
24
+ return rb_ary_new() ;
25
+ }
@@ -4,7 +4,8 @@ unless have_const('linux') || RbConfig::CONFIG['arch'].to_s[/linux/]
4
4
  abort('Platform is not linux')
5
5
  end
6
6
 
7
- unless have_header('sys/statvfs.h') && have_header('ruby.h')
7
+ unless have_header('sys/statvfs.h') && have_header('sys/ioctl.h') &&
8
+ have_header('fcntl.h') && have_header('linux/fs.h') && have_header('unistd.h')
8
9
  abort('Missing header')
9
10
  end
10
11
 
@@ -1,5 +1,12 @@
1
1
  #include <sys/statvfs.h>
2
+ #include <sys/ioctl.h>
3
+ #include <fcntl.h>
4
+ #include <linux/fs.h>
5
+ #include <unistd.h>
6
+
2
7
  #include "ruby.h"
8
+ #include "sector_size.h"
9
+ #include "disk_stat.h"
3
10
 
4
11
  #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
5
12
  #pragma GCC optimize ("O3")
@@ -11,7 +18,7 @@
11
18
  #pragma intel optimization_level 3
12
19
  #endif
13
20
 
14
- static VALUE statfs(VALUE obj, VALUE dir) {
21
+ static VALUE statfs(volatile VALUE obj, volatile VALUE dir) {
15
22
  struct statvfs buf ;
16
23
  char *d = StringValuePtr(dir) ;
17
24
  VALUE hash = rb_hash_new() ;
@@ -36,4 +43,6 @@ void Init_fs_stat() {
36
43
  VALUE _linux_stat = rb_define_module("LinuxStat") ;
37
44
  VALUE fs = rb_define_module_under(_linux_stat, "FS") ;
38
45
  rb_define_module_function(fs, "stat", statfs, 1) ;
46
+ rb_define_module_function(fs, "sectors", getSectorSize, 1) ;
47
+ rb_define_module_function(fs, "total_io", getDiskStats, 1) ;
39
48
  }
@@ -0,0 +1,13 @@
1
+ static VALUE getSectorSize(volatile VALUE obj, volatile VALUE path) {
2
+ char *dev = StringValuePtr(path) ;
3
+
4
+ unsigned int fd = open(dev, O_RDONLY | O_NONBLOCK) ;
5
+ if(fd < 0) return Qnil ;
6
+
7
+ unsigned int sSize = 0 ;
8
+ short status = ioctl(fd, BLKSSZGET, &sSize) ;
9
+ close(fd) ;
10
+ if(status < 0) return Qnil ;
11
+
12
+ return UINT2NUM(sSize) ;
13
+ }
@@ -0,0 +1,2 @@
1
+ require 'mkmf'
2
+ create_makefile 'linux_stat/misc/integer'
@@ -0,0 +1,63 @@
1
+ /*
2
+ Validates if a String is integer or not.
3
+
4
+ Conditions:
5
+ - The String can start with - (negative)
6
+ - If the Argument is a BigInt or Integer, or anything else, return false
7
+ - The String cannot have anything other than 0 to 9
8
+ - The String can have leading zeroes and negative sign:
9
+ Example 1: "-00999" which translates to Ruby's -999 (decimal)
10
+ Example 2: "000999" translates to 999
11
+ - If it fails to determine, it returns nil instead of false
12
+ - It doesn't raise any error. Handing nil is enough to indicate that it failed.
13
+ */
14
+
15
+ #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
16
+ #pragma GCC optimize ("O3")
17
+ #pragma GCC diagnostic warning "-Wall"
18
+ #elif defined(__clang__)
19
+ #pragma clang optimize on
20
+ #pragma clang diagnostic warning "-Wall"
21
+ #elif defined(__INTEL_COMPILER)
22
+ #pragma intel optimization_level 3
23
+ #endif
24
+
25
+ #include <limits.h>
26
+ #include "ruby.h"
27
+
28
+ VALUE isNumber(volatile VALUE obj, volatile VALUE val) {
29
+ // But we don't expect anything other than String though as Argument.
30
+ // Note that raising ArgumentError or any kind of Error shouldn't be done here
31
+ // Otherwise Integer(n) is the best method in Ruby.
32
+ if (!RB_TYPE_P(val, T_STRING))
33
+ return Qnil ;
34
+
35
+ char *str = StringValuePtr(val) ;
36
+ char ch = str[0] ;
37
+
38
+ // If the string is empty, return false
39
+ if (!ch) return Qfalse ;
40
+
41
+ unsigned char i = ch == '-' ? 1 : 0 ;
42
+ if (!str[i]) return Qfalse ;
43
+
44
+ unsigned char max = UCHAR_MAX ;
45
+
46
+ # pragma GCC unroll 4
47
+ while((ch = str[i++])) {
48
+ if (ch < 48 || ch > 57)
49
+ return Qfalse ;
50
+
51
+ if (i == max)
52
+ return Qnil ;
53
+ }
54
+
55
+ return Qtrue ;
56
+ }
57
+
58
+ void Init_integer() {
59
+ VALUE linuxStat = rb_define_module("LinuxStat") ;
60
+ VALUE misc = rb_define_module_under(linuxStat, "Misc") ;
61
+
62
+ rb_define_module_function(misc, "integer?", isNumber, 1) ;
63
+ }
data/ext/nproc/nproc.c CHANGED
@@ -15,7 +15,7 @@
15
15
  #pragma intel optimization_level 3
16
16
  #endif
17
17
 
18
- static VALUE count_cpu_for_pid(VALUE obj, VALUE pid) {
18
+ static VALUE count_cpu_for_pid(volatile VALUE obj, volatile VALUE pid) {
19
19
  cpu_set_t set ;
20
20
  CPU_ZERO(&set) ;
21
21
  char status = sched_getaffinity(FIX2INT(pid), sizeof(set), &set) ;
@@ -1,4 +1,4 @@
1
- VALUE last_pid(VALUE obj) {
1
+ static VALUE last_pid(volatile VALUE obj) {
2
2
  FILE *f = fopen("/proc/loadavg", "r") ;
3
3
  if (!f) return Qnil ;
4
4
 
data/ext/procfs/procfs.c CHANGED
@@ -13,6 +13,7 @@
13
13
  #include <stdio.h>
14
14
  #include <unistd.h>
15
15
  #include <string.h>
16
+ #include <glob.h>
16
17
  #include "ruby.h"
17
18
  #include "uptime.h"
18
19
  #include "statm.h"
@@ -22,6 +23,8 @@
22
23
  int Init_procfs() {
23
24
  VALUE _linux_stat = rb_define_module("LinuxStat") ;
24
25
  VALUE _procfs = rb_define_module_under(_linux_stat, "ProcFS") ;
26
+ VALUE _cpu = rb_define_module_under(_linux_stat, "CPU") ;
27
+ VALUE _process = rb_define_module_under(_linux_stat, "Process") ;
25
28
 
26
29
  // uptime
27
30
  rb_define_module_function(_procfs, "uptime_f", uptime_f, 0) ;
@@ -40,4 +43,7 @@ int Init_procfs() {
40
43
  rb_define_module_function(_procfs, "ps_state", ps_state, 1) ;
41
44
  rb_define_module_function(_procfs, "ps_times", ps_times, 1) ;
42
45
  rb_define_module_function(_procfs, "ps_stat", ps_stat, 1) ;
46
+ rb_define_module_function(_procfs, "cpu_times", cpuTimes, 0) ;
47
+ rb_define_module_function(_procfs, "list_process", listProcess, 0) ;
48
+
43
49
  }
data/ext/procfs/stat.h CHANGED
@@ -1,4 +1,4 @@
1
- VALUE ps_state(VALUE obj, VALUE pid) {
1
+ static VALUE ps_state(volatile VALUE obj, volatile VALUE pid) {
2
2
  int _pid = FIX2INT(pid) ;
3
3
  if (_pid < 0) return rb_str_new_cstr("") ;
4
4
 
@@ -17,7 +17,30 @@ VALUE ps_state(VALUE obj, VALUE pid) {
17
17
  return rb_str_new_cstr(_s) ;
18
18
  }
19
19
 
20
- VALUE ps_times(VALUE obj, VALUE pid) {
20
+ static VALUE listProcess(volatile VALUE obj) {
21
+ VALUE ary = rb_ary_new() ;
22
+
23
+ glob_t globlist ;
24
+ int status = glob("/proc/[0-9]*/", GLOB_NOSORT, NULL, &globlist) ;
25
+
26
+ if (status == GLOB_NOSPACE || status == GLOB_ABORTED || status == GLOB_NOMATCH) {
27
+ globfree(&globlist) ;
28
+ return ary ;
29
+ }
30
+
31
+ char *v, *token ;
32
+ unsigned int i = 0 ;
33
+ unsigned int num ;
34
+
35
+ while(v = globlist.gl_pathv[i++]) {
36
+ if (sscanf(v, "/proc/%u", &num) == 1) rb_ary_push(ary, UINT2NUM(num)) ;
37
+ }
38
+
39
+ globfree(&globlist) ;
40
+ return ary ;
41
+ }
42
+
43
+ static VALUE ps_times(volatile VALUE obj, volatile VALUE pid) {
21
44
  int _pid = FIX2INT(pid) ;
22
45
  if (_pid < 0) return Qnil ;
23
46
 
@@ -38,7 +61,7 @@ VALUE ps_times(VALUE obj, VALUE pid) {
38
61
  return DBL2NUM(total_time) ;
39
62
  }
40
63
 
41
- VALUE ps_stat(VALUE obj, VALUE pid) {
64
+ static VALUE ps_stat(volatile VALUE obj, volatile VALUE pid) {
42
65
  int _pid = FIX2INT(pid) ;
43
66
  if (_pid < 0) return rb_str_new_cstr("") ;
44
67
 
@@ -117,3 +140,46 @@ VALUE ps_stat(VALUE obj, VALUE pid) {
117
140
  INT2NUM(exit_code)
118
141
  ) ;
119
142
  }
143
+
144
+ static VALUE cpuTimes(volatile VALUE obj) {
145
+ VALUE ary = rb_ary_new() ;
146
+ FILE *f = fopen("/proc/stat", "r") ;
147
+
148
+ if (!f) return ary ;
149
+
150
+ unsigned long user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice ;
151
+ char line[1024] ;
152
+ char cpuCode[7] ;
153
+ float ticks = sysconf(_SC_CLK_TCK) ;
154
+ char scanStatus ;
155
+
156
+ while(fgets(line, 1023, f)) {
157
+ if (!(line[0] == 'c' && line[1] == 'p' && line[2] == 'u')) break ;
158
+
159
+ scanStatus = sscanf(line,
160
+ "%7[cpu0-9] %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
161
+ cpuCode, &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal, &guest, &guest_nice
162
+ ) ;
163
+
164
+ if (scanStatus != 11) break ;
165
+
166
+ VALUE innerHash = rb_hash_new() ;
167
+ rb_hash_aset(innerHash, ID2SYM(rb_intern("cpu")), rb_str_new_cstr(cpuCode)) ;
168
+ rb_hash_aset(innerHash, ID2SYM(rb_intern("user")), rb_float_new(user / ticks)) ;
169
+ rb_hash_aset(innerHash, ID2SYM(rb_intern("nice")), rb_float_new(nice / ticks)) ;
170
+ rb_hash_aset(innerHash, ID2SYM(rb_intern("system")), rb_float_new(system / ticks)) ;
171
+ rb_hash_aset(innerHash, ID2SYM(rb_intern("idle")), rb_float_new(idle / ticks)) ;
172
+ rb_hash_aset(innerHash, ID2SYM(rb_intern("iowait")), rb_float_new(iowait / ticks)) ;
173
+ rb_hash_aset(innerHash, ID2SYM(rb_intern("irq")), rb_float_new(irq / ticks)) ;
174
+ rb_hash_aset(innerHash, ID2SYM(rb_intern("softirq")), rb_float_new(softirq / ticks)) ;
175
+ rb_hash_aset(innerHash, ID2SYM(rb_intern("steal")), rb_float_new(steal / ticks)) ;
176
+ rb_hash_aset(innerHash, ID2SYM(rb_intern("guest")), rb_float_new(guest / ticks)) ;
177
+ rb_hash_aset(innerHash, ID2SYM(rb_intern("guest_nice")), rb_float_new(guest_nice / ticks)) ;
178
+
179
+ rb_ary_push(ary, innerHash) ;
180
+ }
181
+
182
+ fclose(f) ;
183
+
184
+ return ary ;
185
+ }