linux_stat 2.2.3 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }