linux_stat 0.6.5 → 0.8.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 +516 -197
- data/exe/linuxstat.rb +92 -5
- data/ext/fs_stat/fs_stat.c +7 -3
- data/ext/sysconf/sysconf.c +28 -3
- data/ext/utsname/utsname.c +24 -15
- data/lib/linux_stat/cpu.rb +27 -9
- data/lib/linux_stat/os.rb +2 -2
- data/lib/linux_stat/prettify_bytes.rb +1 -4
- data/lib/linux_stat/process_info.rb +173 -14
- data/lib/linux_stat/user.rb +1 -1
- data/lib/linux_stat/version.rb +1 -1
- metadata +2 -2
data/exe/linuxstat.rb
CHANGED
@@ -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 = [
|
@@ -54,7 +94,6 @@ execute.sort.each do |c|
|
|
54
94
|
next if e.class != Module && e.class != Class
|
55
95
|
|
56
96
|
meths = e.methods(false).sort
|
57
|
-
next if meths.any? { |a| e.method(a).arity > 0 }
|
58
97
|
|
59
98
|
if meths.length > 0
|
60
99
|
if MARKDOWN
|
@@ -67,20 +106,68 @@ execute.sort.each do |c|
|
|
67
106
|
end
|
68
107
|
|
69
108
|
meths.each do |meth|
|
109
|
+
arg = nil
|
110
|
+
params = e.method(meth).parameters
|
111
|
+
|
112
|
+
param = ''
|
113
|
+
|
114
|
+
params.each do |p|
|
115
|
+
case p[0]
|
116
|
+
when :opt
|
117
|
+
param << "#{p[1]}, "
|
118
|
+
when :key
|
119
|
+
param << "#{p[1]}:, "
|
120
|
+
when :req
|
121
|
+
param << "#{p[1] || 'arg'}, "
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
param.delete_suffix!(", ")
|
126
|
+
|
127
|
+
if e.method(meth).arity > 0
|
128
|
+
if c == :PrettifyBytes
|
129
|
+
arg = rand(10 ** 15)
|
130
|
+
elsif c == :FS
|
131
|
+
arg = '/'
|
132
|
+
else
|
133
|
+
next
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
disp_meth = "#{meth}"
|
138
|
+
disp_meth.concat(arg ? "(#{param} = #{arg.inspect})" : "(#{param})")
|
139
|
+
|
70
140
|
time = Time.now
|
71
|
-
v = e.send(meth)
|
141
|
+
v = arg ? e.send(meth, arg) : e.send(meth)
|
72
142
|
time2 = Time.now
|
73
143
|
time = time2.-(time).*(1_000_000).round(3)
|
74
144
|
|
75
145
|
v = v.inspect
|
76
146
|
dis = v.length > 253 ? v[0..250].strip + '...'.freeze : v
|
77
147
|
|
148
|
+
source = e.singleton_method(meth).source_location.to_a
|
149
|
+
src, src_meth = '', ''
|
150
|
+
|
151
|
+
unless source.empty?
|
152
|
+
src << " File: #{File.split(source[0])[-1]} | Line: #{source[1]}\n"
|
153
|
+
src_meth << " Definition: #{IO.foreach(source[0]).first(source[1])[-1].strip}\n"
|
154
|
+
|
155
|
+
if MARKDOWN || HTML
|
156
|
+
src.prepend('#'.freeze)
|
157
|
+
src_meth.prepend('#'.freeze)
|
158
|
+
else
|
159
|
+
src.prepend(?\u2B23.freeze)
|
160
|
+
src_meth.prepend(?\u2B23.freeze)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
78
165
|
if MARKDOWN
|
79
|
-
puts "#{e}.#{
|
166
|
+
puts "#{src}#{src_meth}#{e}.#{disp_meth}\n=> #{dis}"
|
80
167
|
elsif HTML
|
81
|
-
puts "#{e}.#{
|
168
|
+
puts "#{src}#{src_meth}#{e}.#{disp_meth}\n=> #{dis}"
|
82
169
|
else
|
83
|
-
puts "\e[1;38;2;80;80;255m#{e}.#{
|
170
|
+
puts "\e[1m#{src.colourize}\e[1m#{src_meth.colourize(4)}\e[0m\e[1;38;2;80;80;255m#{e}.#{disp_meth}\e[0m\n=> #{dis}"
|
84
171
|
end
|
85
172
|
|
86
173
|
puts( "(" +
|
data/ext/fs_stat/fs_stat.c
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
#include <sys/statvfs.h>
|
2
2
|
#include "ruby.h"
|
3
3
|
|
4
|
-
#
|
5
|
-
#pragma
|
6
|
-
#pragma
|
4
|
+
#ifdef __GNUC__
|
5
|
+
#pragma GCC optimize ("O3")
|
6
|
+
#pragma GCC diagnostic warning "-Wall"
|
7
|
+
#elif __clang__
|
8
|
+
#pragma clang optimize on
|
9
|
+
#pragma clang diagnostic warning "-Wall"
|
10
|
+
#endif
|
7
11
|
|
8
12
|
static VALUE statfs(VALUE obj, VALUE dir) {
|
9
13
|
struct statvfs buf ;
|
data/ext/sysconf/sysconf.c
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
#include <unistd.h>
|
2
2
|
#include "ruby.h"
|
3
3
|
|
4
|
-
#
|
5
|
-
#pragma
|
6
|
-
#pragma
|
4
|
+
#ifdef __GNUC__
|
5
|
+
#pragma GCC optimize ("O3")
|
6
|
+
#pragma GCC diagnostic warning "-Wall"
|
7
|
+
#elif __clang__
|
8
|
+
#pragma clang optimize on
|
9
|
+
#pragma clang diagnostic warning "-Wall"
|
10
|
+
#endif
|
7
11
|
|
8
12
|
static VALUE getTick(VALUE obj) {
|
9
13
|
return INT2FIX(sysconf(_SC_CLK_TCK)) ;
|
@@ -41,6 +45,22 @@ static VALUE getPosixVersion(VALUE obj) {
|
|
41
45
|
return INT2FIX(sysconf(_SC_VERSION)) ;
|
42
46
|
}
|
43
47
|
|
48
|
+
static VALUE getLineMax(VALUE obj) {
|
49
|
+
return INT2FIX(sysconf(_SC_LINE_MAX)) ;
|
50
|
+
}
|
51
|
+
|
52
|
+
static VALUE getExprNestMax(VALUE obj) {
|
53
|
+
return INT2FIX(sysconf(_SC_EXPR_NEST_MAX)) ;
|
54
|
+
}
|
55
|
+
|
56
|
+
VALUE getProcessorConfigured(VALUE obj) {
|
57
|
+
return INT2FIX(sysconf(_SC_NPROCESSORS_CONF)) ;
|
58
|
+
}
|
59
|
+
|
60
|
+
VALUE getProcessorOnline(VALUE obj) {
|
61
|
+
return INT2FIX(sysconf(_SC_NPROCESSORS_ONLN)) ;
|
62
|
+
}
|
63
|
+
|
44
64
|
static VALUE getUser(VALUE obj) {
|
45
65
|
char *name = getlogin() ;
|
46
66
|
return name ? rb_str_new_cstr(name) : rb_str_new_cstr("") ;
|
@@ -71,6 +91,11 @@ void Init_sysconf() {
|
|
71
91
|
rb_define_module_function(_sysconf, "stream_max", getStreamMax, 0) ;
|
72
92
|
rb_define_module_function(_sysconf, "tty_name_max", getTTYNameMax, 0) ;
|
73
93
|
rb_define_module_function(_sysconf, "posix_version", getPosixVersion, 0) ;
|
94
|
+
rb_define_module_function(_sysconf, "line_max", getLineMax, 0) ;
|
95
|
+
rb_define_module_function(_sysconf, "expr_nest_max", getExprNestMax, 0) ;
|
96
|
+
|
97
|
+
rb_define_module_function(_sysconf, "processor_online", getProcessorOnline, 0) ;
|
98
|
+
rb_define_module_function(_sysconf, "processor_configured", getProcessorConfigured, 0) ;
|
74
99
|
|
75
100
|
rb_define_module_function(_sysconf, "get_uid", getUID, 0) ;
|
76
101
|
rb_define_module_function(_sysconf, "get_gid", getGID, 0) ;
|
data/ext/utsname/utsname.c
CHANGED
@@ -1,40 +1,49 @@
|
|
1
1
|
#include <sys/utsname.h>
|
2
2
|
#include "ruby.h"
|
3
3
|
|
4
|
-
#
|
5
|
-
#pragma
|
6
|
-
#pragma
|
4
|
+
#ifdef __GNUC__
|
5
|
+
#pragma GCC optimize ("O3")
|
6
|
+
#pragma GCC diagnostic warning "-Wall"
|
7
|
+
#elif __clang__
|
8
|
+
#pragma clang optimize on
|
9
|
+
#pragma clang diagnostic warning "-Wall"
|
10
|
+
#endif
|
7
11
|
|
8
12
|
static struct utsname buf ;
|
9
|
-
|
13
|
+
|
14
|
+
static char *sysname = "", *nodename = "" ;
|
15
|
+
static char *release = "", *version = "", *machine = "" ;
|
10
16
|
|
11
17
|
void init_buf() {
|
12
|
-
status = uname(&buf) ;
|
18
|
+
short status = uname(&buf) ;
|
19
|
+
|
20
|
+
if (status > -1) {
|
21
|
+
sysname = buf.sysname ;
|
22
|
+
nodename = buf.nodename ;
|
23
|
+
release = buf.release ;
|
24
|
+
version = buf.version ;
|
25
|
+
machine = buf.machine ;
|
26
|
+
}
|
13
27
|
}
|
14
28
|
|
15
29
|
static VALUE getSysname(VALUE obj) {
|
16
|
-
|
17
|
-
return sysname ;
|
30
|
+
return rb_str_new_cstr(sysname) ;
|
18
31
|
}
|
19
32
|
|
20
33
|
static VALUE getNodename(VALUE obj) {
|
21
|
-
|
22
|
-
return nodename ;
|
34
|
+
return rb_str_new_cstr(nodename) ;
|
23
35
|
}
|
24
36
|
|
25
37
|
static VALUE getRelease(VALUE obj) {
|
26
|
-
|
27
|
-
return release ;
|
38
|
+
return rb_str_new_cstr(release) ;
|
28
39
|
}
|
29
40
|
|
30
41
|
static VALUE getVersion(VALUE obj) {
|
31
|
-
|
32
|
-
return version ;
|
42
|
+
return rb_str_new_cstr(version) ;
|
33
43
|
}
|
34
44
|
|
35
45
|
static VALUE getMachine(VALUE obj) {
|
36
|
-
|
37
|
-
return machine ;
|
46
|
+
return rb_str_new_cstr(machine) ;
|
38
47
|
}
|
39
48
|
|
40
49
|
void Init_utsname() {
|
data/lib/linux_stat/cpu.rb
CHANGED
@@ -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
|
#
|
@@ -18,14 +18,14 @@ module LinuxStat
|
|
18
18
|
# {0=>84.38, 1=>100.0, 2=>50.0, 3=>87.5, 4=>87.5}
|
19
19
|
#
|
20
20
|
# If the information is not available, it will return an empty Hash
|
21
|
-
def stat(sleep =
|
21
|
+
def stat(sleep = ticks_to_ms_t5)
|
22
22
|
return {} unless stat?
|
23
23
|
|
24
24
|
data = IO.readlines('/proc/stat').select! { |x| x[/^cpu\d*/] }.map! { |x| x.split.map!(&:to_f) }
|
25
25
|
sleep(sleep)
|
26
26
|
data2 = IO.readlines('/proc/stat').select! { |x| x[/^cpu\d*/] }.map! { |x| x.split.map!(&:to_f) }
|
27
27
|
|
28
|
-
# On devices like android, the core count can change anytime.
|
28
|
+
# On devices like android, the core count can change anytime (hotplugging).
|
29
29
|
# I had crashes on Termux.
|
30
30
|
# So better just count the min number of CPU and iterate over that
|
31
31
|
# If data.length is smaller than data2.length, we don't have enough data to compare.
|
@@ -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 =
|
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)
|
@@ -76,12 +76,27 @@ module LinuxStat
|
|
76
76
|
end
|
77
77
|
|
78
78
|
##
|
79
|
-
# Returns the total number of CPU threads.
|
79
|
+
# Returns the total number of CPU threads online now.
|
80
|
+
#
|
81
|
+
# This value can change while a CPU is offline, due to kernel's hotplugging feature.
|
82
|
+
#
|
83
|
+
# If the information isn't available, it will return 0.
|
84
|
+
def online
|
85
|
+
# Let's rely on sysconf(_SC_NPROCESSORS_CONF), which is 100x faster than
|
86
|
+
# counting online cpu from /sys/devices/system/cpu
|
87
|
+
|
88
|
+
LinuxStat::Sysconf.processor_configured
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# Returns the total number of CPU threads configured for the sysetm.
|
80
93
|
#
|
81
94
|
# If the information isn't available, it will return 0.
|
82
95
|
def count
|
83
|
-
#
|
84
|
-
|
96
|
+
# Let's rely on sysconf(_SC_NPROCESSORS_ONLN), which is 100x faster than running:
|
97
|
+
# IO.read('/sys/devices/system/cpu/online')[-2].to_i + 1
|
98
|
+
|
99
|
+
LinuxStat::Sysconf.processor_online
|
85
100
|
end
|
86
101
|
|
87
102
|
##
|
@@ -136,8 +151,11 @@ module LinuxStat
|
|
136
151
|
@@stat_readable ||= File.readable?('/proc/stat')
|
137
152
|
end
|
138
153
|
|
139
|
-
|
140
|
-
|
154
|
+
# Just to avoid duplicate calculations
|
155
|
+
# ticks to ms times 5
|
156
|
+
# If the ticks is 100, it will return 0.05
|
157
|
+
def ticks_to_ms_t5
|
158
|
+
@@ms_t5 ||= 1.0 / LinuxStat::Sysconf.sc_clk_tck * 5
|
141
159
|
end
|
142
160
|
end
|
143
161
|
end
|
data/lib/linux_stat/os.rb
CHANGED
@@ -135,8 +135,8 @@ module LinuxStat
|
|
135
135
|
key = splitted[0].to_s.strip
|
136
136
|
value = splitted[1..-1].join(?=).to_s.strip
|
137
137
|
|
138
|
-
value[0] = '' if value[0] == ?"
|
139
|
-
value[-1] = '' if value[-1] == ?"
|
138
|
+
value[0] = ''.freeze if value[0] == ?".freeze
|
139
|
+
value[-1] = ''.freeze if value[-1] == ?".freeze
|
140
140
|
|
141
141
|
h.merge!( key.to_sym => value )
|
142
142
|
}
|
@@ -100,10 +100,7 @@ module LinuxStat
|
|
100
100
|
|
101
101
|
private
|
102
102
|
def pad_left(n, mantissa_length = 2)
|
103
|
-
|
104
|
-
exp, mant = n.to_s.split(?..freeze)
|
105
|
-
m = mant.length < mantissa_length ? mant + ?0.freeze * (mantissa_length - mant.length) : mant
|
106
|
-
exp + ?..freeze + m
|
103
|
+
sprintf("%.#{mantissa_length}f".freeze, n)
|
107
104
|
end
|
108
105
|
end
|
109
106
|
end
|
@@ -203,13 +203,13 @@ module LinuxStat
|
|
203
203
|
end
|
204
204
|
|
205
205
|
##
|
206
|
-
# = cpu_stat(pid: $$, sleep: 1.0 / LinuxStat::Sysconf.sc_clk_tck)
|
206
|
+
# = cpu_stat(pid: $$, sleep: 1.0 / LinuxStat::Sysconf.sc_clk_tck * 5)
|
207
207
|
#
|
208
208
|
# Where pid is the process ID and sleep time is the interval between measurements.
|
209
209
|
#
|
210
210
|
# By default it is the id of the current process ($$), and sleep is LinuxStat::Sysconf.sc_clk_tck
|
211
211
|
#
|
212
|
-
# The smallest amount of available sleep time is 1.0 / LinuxStat::Sysconf.sc_clk_tck.
|
212
|
+
# The smallest amount of available sleep time is 1.0 / LinuxStat::Sysconf.sc_clk_tck * 5.
|
213
213
|
#
|
214
214
|
# * Note 1:
|
215
215
|
# 1. Do note that the sleep time can slow down your application.
|
@@ -244,7 +244,7 @@ module LinuxStat
|
|
244
244
|
# Only use this method if you need all of the data at once, in such case, it's more efficient to use this method.
|
245
245
|
#
|
246
246
|
# The :last_executed_cpu also returns an Integer indicating the last executed cpu of the process.
|
247
|
-
def cpu_stat(pid: $$, sleep:
|
247
|
+
def cpu_stat(pid: $$, sleep: ticks_to_ms_t5)
|
248
248
|
file = "/proc/#{pid}/stat"
|
249
249
|
return {} unless File.readable?(file)
|
250
250
|
|
@@ -277,15 +277,15 @@ module LinuxStat
|
|
277
277
|
end
|
278
278
|
|
279
279
|
##
|
280
|
-
# = cpu_usage(pid: $$, sleep: 1.0 / LinuxStat::Sysconf.sc_clk_tck)
|
280
|
+
# = cpu_usage(pid: $$, sleep: 1.0 / LinuxStat::Sysconf.sc_clk_tck * 5)
|
281
281
|
#
|
282
282
|
# Where pid is the process ID and sleep time is the interval between measurements.
|
283
283
|
#
|
284
|
-
# By default it is the id of the current process ($$), and sleep is 1.0 / LinuxStat::Sysconf.sc_clk_tck
|
284
|
+
# By default it is the id of the current process ($$), and sleep is 1.0 / LinuxStat::Sysconf.sc_clk_tck * 5
|
285
285
|
#
|
286
286
|
# The smallest amount of available sleep time is LinuxStat::Sysconf.sc_clk_tck.
|
287
287
|
#
|
288
|
-
# It retuns the CPU usage
|
288
|
+
# It retuns the CPU usage as Float.
|
289
289
|
#
|
290
290
|
# For example:
|
291
291
|
#
|
@@ -298,7 +298,7 @@ module LinuxStat
|
|
298
298
|
# But if the info isn't available, it will return nil.
|
299
299
|
#
|
300
300
|
# This method is more efficient than running LinuxStat::ProcessInfo.cpu_stat()
|
301
|
-
def cpu_usage(pid: $$, sleep:
|
301
|
+
def cpu_usage(pid: $$, sleep: ticks_to_ms_t5)
|
302
302
|
file = "/proc/#{pid}/stat"
|
303
303
|
return nil unless File.readable?(file)
|
304
304
|
|
@@ -324,6 +324,54 @@ module LinuxStat
|
|
324
324
|
totald.-(idle2 - idle1).fdiv(totald).*(100).round(2).abs./(LinuxStat::CPU.count)
|
325
325
|
end
|
326
326
|
|
327
|
+
##
|
328
|
+
# = thread_usage(pid: $$, sleep: 1.0 / LinuxStat::Sysconf.sc_clk_tck * 5)
|
329
|
+
#
|
330
|
+
# Where pid is the process ID and sleep time is the interval between measurements.
|
331
|
+
#
|
332
|
+
# By default it is the id of the current process ($$), and sleep is 1.0 / LinuxStat::Sysconf.sc_clk_tck * 5
|
333
|
+
#
|
334
|
+
# The smallest amount of available sleep time is LinuxStat::Sysconf.sc_clk_tck.
|
335
|
+
#
|
336
|
+
# It retuns the per core CPU usage as Float.
|
337
|
+
#
|
338
|
+
# For example:
|
339
|
+
#
|
340
|
+
# LinuxStat::ProcessInfo.core_usage
|
341
|
+
#
|
342
|
+
# => 200.0
|
343
|
+
#
|
344
|
+
# A value of 100.0 indicates it is using 100% processing power of a core.
|
345
|
+
#
|
346
|
+
# The value could be 0 to (100 * the number of CPU threads (including hyperthreading) in the system)
|
347
|
+
#
|
348
|
+
# But if the info isn't available, it will return nil.
|
349
|
+
def thread_usage(pid: $$, sleep: ticks_to_ms_t5)
|
350
|
+
file = "/proc/#{pid}/stat"
|
351
|
+
return nil unless File.readable?(file)
|
352
|
+
|
353
|
+
ticks = get_ticks
|
354
|
+
|
355
|
+
utime, stime, starttime = IO.read(file)
|
356
|
+
.split.values_at(13, 14, 21).map(&:to_f)
|
357
|
+
uptime = IO.read('/proc/uptime'.freeze).to_f * ticks
|
358
|
+
|
359
|
+
total_time = utime + stime
|
360
|
+
idle1 = uptime - starttime - total_time
|
361
|
+
|
362
|
+
sleep(sleep)
|
363
|
+
|
364
|
+
utime2, stime2, starttime2 = IO.read(file)
|
365
|
+
.split.values_at(13, 14, 21).map(&:to_f)
|
366
|
+
uptime = IO.read('/proc/uptime'.freeze).to_f * ticks
|
367
|
+
|
368
|
+
total_time2 = utime2 + stime2
|
369
|
+
idle2 = uptime - starttime2 - total_time2
|
370
|
+
|
371
|
+
totald = idle2.+(total_time2).-(idle1 + total_time)
|
372
|
+
totald.-(idle2 - idle1).fdiv(totald).*(100).round(2).abs
|
373
|
+
end
|
374
|
+
|
327
375
|
##
|
328
376
|
# = threads(pid = $$)
|
329
377
|
#
|
@@ -345,7 +393,7 @@ module LinuxStat
|
|
345
393
|
file = "/proc/#{pid}/stat".freeze
|
346
394
|
return nil unless File.readable?(file)
|
347
395
|
|
348
|
-
data = IO.
|
396
|
+
data = IO.foreach(file, ' '.freeze).first(20)[-1]
|
349
397
|
data ? data.to_i : nil
|
350
398
|
end
|
351
399
|
|
@@ -383,7 +431,7 @@ module LinuxStat
|
|
383
431
|
file = "/proc/#{pid}/status".freeze
|
384
432
|
return nil unless File.readable?(file)
|
385
433
|
|
386
|
-
data = IO.
|
434
|
+
data = IO.foreach(file.freeze).find { |x|
|
387
435
|
x[/Uid.*\d*/]
|
388
436
|
}.to_s.split.drop(1)
|
389
437
|
|
@@ -402,12 +450,12 @@ module LinuxStat
|
|
402
450
|
#
|
403
451
|
# :real, :effective, :saved_set, :filesystem_uid
|
404
452
|
#
|
405
|
-
# If the info isn't available it
|
453
|
+
# If the info isn't available or the argument passed doesn't exist as a process ID, it will return an empty Hash.
|
406
454
|
def gid(pid = $$)
|
407
455
|
file = "/proc/#{pid}/status".freeze
|
408
456
|
return nil unless File.readable?(file)
|
409
457
|
|
410
|
-
data = IO.
|
458
|
+
data = IO.foreach(file.freeze).find { |x|
|
411
459
|
x[/Gid.*\d*/]
|
412
460
|
}.split.drop(1)
|
413
461
|
|
@@ -428,21 +476,132 @@ module LinuxStat
|
|
428
476
|
file = "/proc/#{pid}/status".freeze
|
429
477
|
return ''.freeze unless File.readable?(file)
|
430
478
|
|
431
|
-
gid = IO.
|
479
|
+
gid = IO.foreach(file.freeze).find { |x|
|
432
480
|
x[/Gid.*\d*/]
|
433
481
|
}.split.drop(1)[2].to_i
|
434
482
|
|
435
483
|
LinuxStat::User.username_by_gid(gid)
|
436
484
|
end
|
437
485
|
|
486
|
+
##
|
487
|
+
# = start_time_epoch(pid = $$)
|
488
|
+
#
|
489
|
+
# Returns the epoch time (as Integer) the process was started.
|
490
|
+
#
|
491
|
+
# For example:
|
492
|
+
# LinuxStat::ProcessInfo.start_time_epoch 526
|
493
|
+
#
|
494
|
+
# => 1608097744
|
495
|
+
#
|
496
|
+
# If the info isn't available or the argument passed doesn't exist as a process ID, it will return nil.
|
497
|
+
def start_time_epoch(pid = $$)
|
498
|
+
stat_file = "/proc/#{pid}/stat".freeze
|
499
|
+
uptime = "/proc/uptime".freeze
|
500
|
+
|
501
|
+
@@u_readable ||= File.readable?(uptime)
|
502
|
+
return nil unless @@u_readable && File.readable?(stat_file)
|
503
|
+
|
504
|
+
u = IO.foreach(uptime, ' '.freeze).next.to_f
|
505
|
+
st = (IO.foreach(stat_file, ' '.freeze).first(22)[-1].to_f / get_ticks)
|
506
|
+
|
507
|
+
# Getting two Time objects and dealing with floating point numbers
|
508
|
+
# Just to make sure the time goes monotonically
|
509
|
+
Time.now.-(u - st).to_i
|
510
|
+
end
|
511
|
+
|
512
|
+
##
|
513
|
+
# = start_time(pid = $$)
|
514
|
+
#
|
515
|
+
# Returns the time (as Time object) the process was started.
|
516
|
+
#
|
517
|
+
# For example:
|
518
|
+
# LinuxStat::ProcessInfo.start_time 14183
|
519
|
+
#
|
520
|
+
# => 2020-12-16 13:31:43 +0000
|
521
|
+
#
|
522
|
+
# If the info isn't available or the argument passed doesn't exist as a process ID, it will return nil.
|
523
|
+
#
|
524
|
+
# The timezone returned based on current TZ.
|
525
|
+
# Thus the timezone could be affected by changing the ENV['TZ'] variable.
|
526
|
+
#
|
527
|
+
# Don't trust the timezone returned by the time.
|
528
|
+
def start_time(pid = $$)
|
529
|
+
# Getting two Time objects and dealing with floating point numbers
|
530
|
+
# Just to make sure the time goes monotonically
|
531
|
+
Time.at(start_time_epoch(pid))
|
532
|
+
end
|
533
|
+
|
534
|
+
##
|
535
|
+
# = running_time(pid = $$)
|
536
|
+
#
|
537
|
+
# Returns the time (in seconds, as Float) the process is running for.
|
538
|
+
#
|
539
|
+
# For example:
|
540
|
+
# LinuxStat::ProcessInfo.running_time 14183
|
541
|
+
#
|
542
|
+
# => 1947.619999999999
|
543
|
+
#
|
544
|
+
# If the info isn't available or the argument passed doesn't exist as a process ID, it will return nil.
|
545
|
+
def running_time(pid = $$)
|
546
|
+
stat_file = "/proc/#{pid}/stat".freeze
|
547
|
+
uptime = "/proc/uptime".freeze
|
548
|
+
|
549
|
+
@@u_readable ||= File.readable?(uptime)
|
550
|
+
return nil unless @@u_readable && File.readable?(stat_file)
|
551
|
+
|
552
|
+
IO.foreach(uptime, ' '.freeze).next.to_f - (IO.read(stat_file).split[21].to_i / get_ticks)
|
553
|
+
end
|
554
|
+
|
555
|
+
##
|
556
|
+
# = state(pid = $$)
|
557
|
+
# Returns the state of the process as a frozen String
|
558
|
+
#
|
559
|
+
# * A process could have multiple states:
|
560
|
+
#
|
561
|
+
# 1. S => Sleeping
|
562
|
+
#
|
563
|
+
# 2. R => Running
|
564
|
+
#
|
565
|
+
# 3. I => Idle
|
566
|
+
#
|
567
|
+
# 4. Z => Zombie
|
568
|
+
#
|
569
|
+
# It returns any one of them.
|
570
|
+
#
|
571
|
+
# If the info isn't available or the argument passed doesn't exist as a process ID,
|
572
|
+
# it will return an empty String.
|
573
|
+
def state(pid = $$)
|
574
|
+
file = "/proc/#{pid}/stat".freeze
|
575
|
+
return ''.freeze unless File.readable?(file)
|
576
|
+
IO.foreach(file, ' '.freeze).first(3)[-1].tap(&:rstrip!).freeze
|
577
|
+
end
|
578
|
+
|
579
|
+
##
|
580
|
+
# = nice(pid = $$)
|
581
|
+
# Returns the nice of the process
|
582
|
+
#
|
583
|
+
# The output value is an Integer ranging from -20 to 19
|
584
|
+
#
|
585
|
+
# -20 means the process has high priority, and 19 means the process has low priority
|
586
|
+
#
|
587
|
+
# If the info isn't available or the argument passed doesn't exist as a process ID, it will return nil.
|
588
|
+
def nice(pid = $$)
|
589
|
+
file = "/proc/#{pid}/stat"
|
590
|
+
return nil unless File.readable?(file)
|
591
|
+
|
592
|
+
IO.foreach(file, ' ').first(19)[-1].to_i
|
593
|
+
end
|
594
|
+
|
438
595
|
private
|
439
596
|
def get_ticks
|
440
597
|
@@ticks ||= Sysconf.sc_clk_tck
|
441
598
|
end
|
442
599
|
|
443
600
|
# Just to avoid multiple calculations!...
|
444
|
-
|
445
|
-
|
601
|
+
# ticks to ms * 5
|
602
|
+
# If ticks is 100, it will return 0.05
|
603
|
+
def ticks_to_ms_t5
|
604
|
+
@@ms_t5 ||= 1.0 / get_ticks * 5
|
446
605
|
end
|
447
606
|
|
448
607
|
def pagesize
|