linux_stat 2.1.2 → 2.3.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.
- checksums.yaml +4 -4
- data/README.md +54 -1052
- data/exe/linuxstat.rb +148 -98
- data/ext/fs_stat/disk_stat.h +25 -0
- data/ext/fs_stat/extconf.rb +2 -1
- data/ext/fs_stat/fs_stat.c +10 -1
- data/ext/fs_stat/sector_size.h +13 -0
- data/ext/nproc/nproc.c +1 -1
- data/ext/procfs/loadavg_pid.h +1 -1
- data/ext/procfs/procfs.c +1 -0
- data/ext/procfs/stat.h +23 -2
- data/ext/procfs/statm.h +5 -5
- data/ext/procfs/uptime.h +1 -1
- data/ext/sysconf/sysconf.c +17 -17
- data/ext/sysinfo/sysinfo.c +11 -11
- data/ext/utsname/utsname.c +5 -5
- data/lib/linux_stat/battery.rb +32 -6
- data/lib/linux_stat/filesystem.rb +45 -0
- data/lib/linux_stat/os.rb +11 -5
- data/lib/linux_stat/prettify_bytes.rb +130 -31
- data/lib/linux_stat/process_info.rb +21 -13
- data/lib/linux_stat/swap.rb +1 -0
- data/lib/linux_stat/version.rb +1 -1
- metadata +5 -3
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| x.to_i.to_s == 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
|
@@ -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
|
-
|
104
|
-
|
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
|
-
|
113
|
+
puts " #{HEXAGONS.rotate![0]} Format: Markdown" if MARKDOWN
|
114
|
+
puts " #{HEXAGONS.rotate![0]} Format: HTML" if HTML
|
107
115
|
|
108
|
-
|
116
|
+
sleep 2
|
117
|
+
puts
|
109
118
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
121
|
-
arg = nil
|
138
|
+
meths = e.methods(false).sort
|
122
139
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
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
|
-
|
146
|
+
puts "\e[1;4;38;2;255;240;0mLinuxStat::#{c}\e[0m"
|
131
147
|
end
|
132
148
|
end
|
133
149
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
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
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
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
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
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
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
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;
|
208
|
-
end
|
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
|
-
|
212
|
-
|
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
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
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}ms"
|
270
|
+
puts "Total CPU Time: #{T_FMT % total_cpu_t}ms"
|
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
|
+
}
|
data/ext/fs_stat/extconf.rb
CHANGED
@@ -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('
|
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
|
|
data/ext/fs_stat/fs_stat.c
CHANGED
@@ -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
|
+
}
|
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) ;
|
data/ext/procfs/loadavg_pid.h
CHANGED
data/ext/procfs/procfs.c
CHANGED
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,28 @@ VALUE ps_state(VALUE obj, VALUE pid) {
|
|
17
17
|
return rb_str_new_cstr(_s) ;
|
18
18
|
}
|
19
19
|
|
20
|
-
VALUE
|
20
|
+
static VALUE ps_times(volatile VALUE obj, volatile VALUE pid) {
|
21
|
+
int _pid = FIX2INT(pid) ;
|
22
|
+
if (_pid < 0) return Qnil ;
|
23
|
+
|
24
|
+
char _path[22] ;
|
25
|
+
sprintf(_path, "/proc/%d/stat", _pid) ;
|
26
|
+
|
27
|
+
FILE *f = fopen(_path, "r") ;
|
28
|
+
if (!f) return Qnil ;
|
29
|
+
|
30
|
+
unsigned long utime, stime ;
|
31
|
+
|
32
|
+
char status = fscanf(f, "%*llu (%*[^)]%*[)] %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %lu %lu", &utime, &stime) ;
|
33
|
+
fclose(f) ;
|
34
|
+
|
35
|
+
if (status != 2) return Qnil ;
|
36
|
+
double total_time = (utime + stime) / (float)sysconf(_SC_CLK_TCK);
|
37
|
+
|
38
|
+
return DBL2NUM(total_time) ;
|
39
|
+
}
|
40
|
+
|
41
|
+
static VALUE ps_stat(volatile VALUE obj, volatile VALUE pid) {
|
21
42
|
int _pid = FIX2INT(pid) ;
|
22
43
|
if (_pid < 0) return rb_str_new_cstr("") ;
|
23
44
|
|
data/ext/procfs/statm.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#define PAGESIZE sysconf(_SC_PAGESIZE)
|
2
2
|
|
3
|
-
VALUE statm(VALUE obj, VALUE pid) {
|
3
|
+
static VALUE statm(volatile VALUE obj, volatile VALUE pid) {
|
4
4
|
VALUE hash = rb_hash_new() ;
|
5
5
|
|
6
6
|
int _pid = FIX2INT(pid) ;
|
@@ -34,7 +34,7 @@ VALUE statm(VALUE obj, VALUE pid) {
|
|
34
34
|
return hash ;
|
35
35
|
}
|
36
36
|
|
37
|
-
VALUE statm_virtual(VALUE obj, VALUE pid) {
|
37
|
+
static VALUE statm_virtual(volatile VALUE obj, volatile VALUE pid) {
|
38
38
|
int _pid = FIX2INT(pid) ;
|
39
39
|
if (_pid < 0) return Qnil ;
|
40
40
|
|
@@ -52,7 +52,7 @@ VALUE statm_virtual(VALUE obj, VALUE pid) {
|
|
52
52
|
return UINT2NUM(_virtual * PAGESIZE) ;
|
53
53
|
}
|
54
54
|
|
55
|
-
VALUE statm_resident(VALUE obj, VALUE pid) {
|
55
|
+
static VALUE statm_resident(volatile VALUE obj, volatile VALUE pid) {
|
56
56
|
int _pid = FIX2INT(pid) ;
|
57
57
|
if (_pid < 0) return Qnil ;
|
58
58
|
|
@@ -70,7 +70,7 @@ VALUE statm_resident(VALUE obj, VALUE pid) {
|
|
70
70
|
return UINT2NUM(resident * PAGESIZE) ;
|
71
71
|
}
|
72
72
|
|
73
|
-
VALUE statm_shared(VALUE obj, VALUE pid) {
|
73
|
+
static VALUE statm_shared(volatile VALUE obj, volatile VALUE pid) {
|
74
74
|
int _pid = FIX2INT(pid) ;
|
75
75
|
if (_pid < 0) return Qnil ;
|
76
76
|
|
@@ -88,7 +88,7 @@ VALUE statm_shared(VALUE obj, VALUE pid) {
|
|
88
88
|
return UINT2NUM(shared * PAGESIZE) ;
|
89
89
|
}
|
90
90
|
|
91
|
-
VALUE statm_memory(VALUE obj, VALUE pid) {
|
91
|
+
static VALUE statm_memory(volatile VALUE obj, volatile VALUE pid) {
|
92
92
|
int _pid = FIX2INT(pid) ;
|
93
93
|
if (_pid < 0) return Qnil ;
|
94
94
|
|