linux_stat 0.7.5 → 1.0.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 +4 -4
- data/README.md +542 -312
- data/exe/linuxstat.rb +34 -13
- data/ext/fs_stat/fs_stat.c +9 -2
- data/ext/nproc/extconf.rb +11 -0
- data/ext/nproc/nproc.c +31 -0
- data/ext/sysconf/sysconf.c +78 -11
- data/ext/utsname/utsname.c +26 -14
- data/lib/linux_stat.rb +8 -1
- data/lib/linux_stat/battery.rb +183 -20
- data/lib/linux_stat/cpu.rb +215 -37
- data/lib/linux_stat/filesystem.rb +12 -12
- data/lib/linux_stat/kernel.rb +1 -1
- data/lib/linux_stat/mounts.rb +4 -4
- data/lib/linux_stat/os.rb +2 -2
- data/lib/linux_stat/process.rb +1 -1
- data/lib/linux_stat/process_info.rb +70 -14
- data/lib/linux_stat/swap.rb +1 -1
- data/lib/linux_stat/usb.rb +192 -0
- data/lib/linux_stat/version.rb +1 -1
- metadata +6 -2
data/lib/linux_stat/os.rb
CHANGED
@@ -121,7 +121,7 @@ module LinuxStat
|
|
121
121
|
hour: h,
|
122
122
|
minute: m,
|
123
123
|
second: s
|
124
|
-
}
|
124
|
+
}.freeze
|
125
125
|
end
|
126
126
|
|
127
127
|
private
|
@@ -143,7 +143,7 @@ module LinuxStat
|
|
143
143
|
end
|
144
144
|
|
145
145
|
def uptime_readable?
|
146
|
-
@@uptime_readable
|
146
|
+
@@uptime_readable ||= File.readable?('/proc/uptime')
|
147
147
|
end
|
148
148
|
end
|
149
149
|
end
|
data/lib/linux_stat/process.rb
CHANGED
@@ -246,18 +246,20 @@ module LinuxStat
|
|
246
246
|
# The :last_executed_cpu also returns an Integer indicating the last executed cpu of the process.
|
247
247
|
def cpu_stat(pid: $$, sleep: ticks_to_ms_t5)
|
248
248
|
file = "/proc/#{pid}/stat"
|
249
|
-
return {} unless File.readable?(file)
|
250
|
-
|
251
249
|
ticks = get_ticks
|
252
250
|
|
251
|
+
return {} unless File.readable?(file)
|
253
252
|
utime, stime, starttime = IO.read(file)
|
254
253
|
.split.values_at(13, 14, 21).map(&:to_f)
|
254
|
+
|
255
255
|
uptime = IO.read('/proc/uptime'.freeze).to_f * ticks
|
256
256
|
|
257
257
|
total_time = utime + stime
|
258
258
|
idle1 = uptime - starttime - total_time
|
259
259
|
|
260
260
|
sleep(sleep)
|
261
|
+
|
262
|
+
return {} unless File.readable?(file)
|
261
263
|
stat = IO.read(file).split
|
262
264
|
|
263
265
|
utime2, stime2, starttime2 = stat.values_at(13, 14, 21).map(&:to_f)
|
@@ -267,10 +269,10 @@ module LinuxStat
|
|
267
269
|
idle2 = uptime - starttime2 - total_time2
|
268
270
|
|
269
271
|
totald = idle2.+(total_time2).-(idle1 + total_time)
|
270
|
-
|
272
|
+
cpu_u = totald.-(idle2 - idle1).fdiv(totald).abs.*(100)./(cpu_count)
|
271
273
|
|
272
274
|
{
|
273
|
-
cpu_usage:
|
275
|
+
cpu_usage: cpu_u > 100 ? 100.0 : cpu_u.round(2),
|
274
276
|
threads: stat[19].to_i,
|
275
277
|
last_executed_cpu: stat[38].to_i
|
276
278
|
}
|
@@ -293,6 +295,10 @@ module LinuxStat
|
|
293
295
|
#
|
294
296
|
# => 10.0
|
295
297
|
#
|
298
|
+
# 10.0 means it's using 10% of the total processing power of the system.
|
299
|
+
#
|
300
|
+
# The value is divided with the configured number of CPU and not online CPU.
|
301
|
+
#
|
296
302
|
# A value of 100.0 indicates it is using 100% processing power available to the system.
|
297
303
|
#
|
298
304
|
# But if the info isn't available, it will return nil.
|
@@ -300,12 +306,12 @@ module LinuxStat
|
|
300
306
|
# This method is more efficient than running LinuxStat::ProcessInfo.cpu_stat()
|
301
307
|
def cpu_usage(pid: $$, sleep: ticks_to_ms_t5)
|
302
308
|
file = "/proc/#{pid}/stat"
|
303
|
-
return nil unless File.readable?(file)
|
304
|
-
|
305
309
|
ticks = get_ticks
|
306
310
|
|
311
|
+
return nil unless File.readable?(file)
|
307
312
|
utime, stime, starttime = IO.read(file)
|
308
313
|
.split.values_at(13, 14, 21).map(&:to_f)
|
314
|
+
|
309
315
|
uptime = IO.read('/proc/uptime'.freeze).to_f * ticks
|
310
316
|
|
311
317
|
total_time = utime + stime
|
@@ -313,15 +319,19 @@ module LinuxStat
|
|
313
319
|
|
314
320
|
sleep(sleep)
|
315
321
|
|
322
|
+
return nil unless File.readable?(file)
|
316
323
|
utime2, stime2, starttime2 = IO.read(file)
|
317
324
|
.split.values_at(13, 14, 21).map(&:to_f)
|
325
|
+
|
318
326
|
uptime = IO.read('/proc/uptime'.freeze).to_f * ticks
|
319
327
|
|
320
328
|
total_time2 = utime2 + stime2
|
321
329
|
idle2 = uptime - starttime2 - total_time2
|
322
330
|
|
323
331
|
totald = idle2.+(total_time2).-(idle1 + total_time)
|
324
|
-
|
332
|
+
|
333
|
+
u = totald.-(idle2 - idle1).fdiv(totald).abs.*(100)./(cpu_count)
|
334
|
+
u > 100 ? 100.0 : u.round(2)
|
325
335
|
end
|
326
336
|
|
327
337
|
##
|
@@ -348,12 +358,12 @@ module LinuxStat
|
|
348
358
|
# But if the info isn't available, it will return nil.
|
349
359
|
def thread_usage(pid: $$, sleep: ticks_to_ms_t5)
|
350
360
|
file = "/proc/#{pid}/stat"
|
351
|
-
return nil unless File.readable?(file)
|
352
|
-
|
353
361
|
ticks = get_ticks
|
354
362
|
|
363
|
+
return nil unless File.readable?(file)
|
355
364
|
utime, stime, starttime = IO.read(file)
|
356
365
|
.split.values_at(13, 14, 21).map(&:to_f)
|
366
|
+
|
357
367
|
uptime = IO.read('/proc/uptime'.freeze).to_f * ticks
|
358
368
|
|
359
369
|
total_time = utime + stime
|
@@ -361,15 +371,21 @@ module LinuxStat
|
|
361
371
|
|
362
372
|
sleep(sleep)
|
363
373
|
|
374
|
+
return nil unless File.readable?(file)
|
364
375
|
utime2, stime2, starttime2 = IO.read(file)
|
365
376
|
.split.values_at(13, 14, 21).map(&:to_f)
|
377
|
+
|
366
378
|
uptime = IO.read('/proc/uptime'.freeze).to_f * ticks
|
367
379
|
|
368
380
|
total_time2 = utime2 + stime2
|
369
381
|
idle2 = uptime - starttime2 - total_time2
|
370
382
|
|
371
383
|
totald = idle2.+(total_time2).-(idle1 + total_time)
|
372
|
-
|
384
|
+
|
385
|
+
u = totald.-(idle2 - idle1).fdiv(totald).abs.*(100)
|
386
|
+
|
387
|
+
cpu_count_t100 = cpu_count * 100
|
388
|
+
u > cpu_count_t100 ? cpu_count_t100 : u.round(2)
|
373
389
|
end
|
374
390
|
|
375
391
|
##
|
@@ -539,7 +555,9 @@ module LinuxStat
|
|
539
555
|
# For example:
|
540
556
|
# LinuxStat::ProcessInfo.running_time 14183
|
541
557
|
#
|
542
|
-
# => 1947.
|
558
|
+
# => 1947.61
|
559
|
+
#
|
560
|
+
# It always rounds the float number upto 2 decimal places
|
543
561
|
#
|
544
562
|
# If the info isn't available or the argument passed doesn't exist as a process ID, it will return nil.
|
545
563
|
def running_time(pid = $$)
|
@@ -549,7 +567,8 @@ module LinuxStat
|
|
549
567
|
@@u_readable ||= File.readable?(uptime)
|
550
568
|
return nil unless @@u_readable && File.readable?(stat_file)
|
551
569
|
|
552
|
-
IO.foreach(uptime, ' '.freeze).next.to_f
|
570
|
+
IO.foreach(uptime, ' '.freeze).next.to_f
|
571
|
+
.-(IO.read(stat_file).split[21].to_f / get_ticks).round(2)
|
553
572
|
end
|
554
573
|
|
555
574
|
##
|
@@ -592,9 +611,42 @@ module LinuxStat
|
|
592
611
|
IO.foreach(file, ' ').first(19)[-1].to_i
|
593
612
|
end
|
594
613
|
|
614
|
+
##
|
615
|
+
# = nproc(pid = $$)
|
616
|
+
# Returns the cpu allocated to the process.
|
617
|
+
#
|
618
|
+
# The output value is an Integer.
|
619
|
+
#
|
620
|
+
# For example:
|
621
|
+
# $ taskset -c 0 irb
|
622
|
+
#
|
623
|
+
# irb(main):001:0> require 'linux_stat'
|
624
|
+
#
|
625
|
+
# => true
|
626
|
+
#
|
627
|
+
# irb(main):002:0> LinuxStat::ProcessInfo.nproc
|
628
|
+
#
|
629
|
+
# => 1
|
630
|
+
#
|
631
|
+
# irb(main):003:0> LinuxStat::ProcessInfo.nproc 11562
|
632
|
+
#
|
633
|
+
# => 3
|
634
|
+
#
|
635
|
+
# irb(main):004:0> LinuxStat::ProcessInfo.nproc 12513
|
636
|
+
#
|
637
|
+
# => 4
|
638
|
+
#
|
639
|
+
# If the info isn't available or the argument passed doesn't exist as a process ID, it will return nil.
|
640
|
+
def nproc(pid = $$)
|
641
|
+
LinuxStat::Nproc.count_cpu_for_pid(pid)
|
642
|
+
end
|
643
|
+
|
644
|
+
alias count_cpu nproc
|
645
|
+
|
595
646
|
private
|
596
647
|
def get_ticks
|
597
|
-
@@
|
648
|
+
@@sc_clk_tck ||= LinuxStat::Sysconf.sc_clk_tck
|
649
|
+
@@ticks ||= @@sc_clk_tck < 1 ? 100 : @@sc_clk_tck
|
598
650
|
end
|
599
651
|
|
600
652
|
# Just to avoid multiple calculations!...
|
@@ -605,7 +657,11 @@ module LinuxStat
|
|
605
657
|
end
|
606
658
|
|
607
659
|
def pagesize
|
608
|
-
@@pagesize ||= LinuxStat::Sysconf.pagesize
|
660
|
+
@@pagesize ||= LinuxStat::Sysconf.pagesize.to_i
|
661
|
+
end
|
662
|
+
|
663
|
+
def cpu_count
|
664
|
+
@@nprocessors_conf ||= LinuxStat::CPU.count
|
609
665
|
end
|
610
666
|
end
|
611
667
|
end
|
data/lib/linux_stat/swap.rb
CHANGED
@@ -0,0 +1,192 @@
|
|
1
|
+
module LinuxStat
|
2
|
+
module USB
|
3
|
+
class << self
|
4
|
+
##
|
5
|
+
# = devices_stat(hwdata: true)
|
6
|
+
#
|
7
|
+
# Returns details about the devices found in /sys/bus/usb/devices/
|
8
|
+
#
|
9
|
+
# The return value is an Array of multiple Hashes. If there's no info available,
|
10
|
+
# it will rather return an empty Array.
|
11
|
+
#
|
12
|
+
# On Android Termux for example, it can not list the directories because they are
|
13
|
+
# not readable the the regular user.
|
14
|
+
#
|
15
|
+
# It can have information like:
|
16
|
+
#
|
17
|
+
# id, vendor id, product id, manufacturer, serial, bus number, dev number,
|
18
|
+
# b_max_power, b_max_packet_size, etc.
|
19
|
+
#
|
20
|
+
# An example of the returned sample from a test machine is:
|
21
|
+
# LinuxStat::USB.devices_stat
|
22
|
+
#
|
23
|
+
# [{:path=>"/sys/bus/usb/devices/1-1.2/", :id=>"04d9:1203", :vendor_id=>"04d9", :product_id=>"1203", :bus_num=>1, :dev_num=>4, :hwdata=>{:vendor=>"Holtek Semiconductor, Inc.", :product=>"Keyboard"}, :authorized=>true, :b_max_power=>"100mA", :b_max_packet_size0=>8}
|
24
|
+
#
|
25
|
+
# Right, it's an array of Hashes.
|
26
|
+
#
|
27
|
+
# It also takes one option. The hwdata, which is true by default.
|
28
|
+
#
|
29
|
+
# Information about usb devices is found inside /usr/share/hwdata/usb.ids
|
30
|
+
#
|
31
|
+
# The data contains the vendor and the product.
|
32
|
+
#
|
33
|
+
# If the option is enabled, it will try look at /usr/share/hwdata/usb.ids
|
34
|
+
#
|
35
|
+
# But the file will be read only once. The consecutive calls to this method
|
36
|
+
# won't open the hwdata all the times.
|
37
|
+
#
|
38
|
+
# But if there's no hwdata, the Hash returned by this method will not contain
|
39
|
+
# hwdata key.
|
40
|
+
#
|
41
|
+
# The data is only populated if it's available. For example, if there's no
|
42
|
+
# manufacturer available for the product, the returned Hash will not contain the
|
43
|
+
# information about the manufacturer.
|
44
|
+
#
|
45
|
+
# Also note that if there's no info available or no USB devices, it will return an empty
|
46
|
+
# Hash.
|
47
|
+
def devices_stat(hwdata: true)
|
48
|
+
@@sys_usb_readable ||= File.readable?('/sys/bus/usb/devices/')
|
49
|
+
return [] unless @@sys_usb_readable
|
50
|
+
|
51
|
+
Dir['/sys/bus/usb/devices/*/'.freeze].sort!.map! { |x|
|
52
|
+
id_vendor_file = File.join(x, 'idVendor'.freeze)
|
53
|
+
next unless File.readable?(id_vendor_file)
|
54
|
+
id_vendor = IO.read(id_vendor_file).strip
|
55
|
+
|
56
|
+
id_product_file = File.join(x, 'idProduct'.freeze)
|
57
|
+
next unless File.readable?(id_vendor_file)
|
58
|
+
id_product = IO.read(id_product_file).strip
|
59
|
+
|
60
|
+
bus_num_file = File.join(x, 'busnum'.freeze)
|
61
|
+
bus_num = File.readable?(bus_num_file) ? IO.read(bus_num_file).strip : ''.freeze
|
62
|
+
|
63
|
+
dev_num_file = File.join(x, 'devnum'.freeze)
|
64
|
+
dev_num = File.readable?(dev_num_file) ? IO.read(dev_num_file).strip : ''.freeze
|
65
|
+
|
66
|
+
serial_file = File.join(x, 'serial'.freeze)
|
67
|
+
serial = File.readable?(serial_file) ? IO.read(serial_file).strip : ''.freeze
|
68
|
+
|
69
|
+
product_file = File.join(x, 'product'.freeze)
|
70
|
+
product = File.readable?(product_file) ? IO.read(product_file).strip : ''.freeze
|
71
|
+
|
72
|
+
manufacturer_file = File.join(x, 'manufacturer'.freeze)
|
73
|
+
manufacturer = File.readable?(manufacturer_file) ? IO.read(manufacturer_file).strip : ''.freeze
|
74
|
+
|
75
|
+
removable_file = File.join(x, 'removable'.freeze)
|
76
|
+
removable = File.readable?(removable_file) ? IO.read(removable_file).strip : ''.freeze
|
77
|
+
|
78
|
+
authorized_file = File.join(x, 'authorized'.freeze)
|
79
|
+
authorized = File.readable?(authorized_file) ? IO.read(authorized_file).to_i : ''.freeze
|
80
|
+
|
81
|
+
b_max_power_file = File.join(x, 'bMaxPower'.freeze)
|
82
|
+
b_max_power = File.readable?(b_max_power_file) ? IO.read(b_max_power_file).strip : ''.freeze
|
83
|
+
|
84
|
+
b_max_packet_size0_file = File.join(x, 'bMaxPacketSize0'.freeze)
|
85
|
+
b_max_packet_size0 = File.readable?(b_max_packet_size0_file) ? IO.read(b_max_packet_size0_file).to_i : ''.freeze
|
86
|
+
|
87
|
+
query = hwdata ? query_hwdata(id_vendor, id_product) : {}
|
88
|
+
|
89
|
+
removable.downcase!
|
90
|
+
is_removable = if removable == 'removable'.freeze
|
91
|
+
true
|
92
|
+
elsif removable == 'unknown'.freeze
|
93
|
+
nil
|
94
|
+
else
|
95
|
+
false
|
96
|
+
end
|
97
|
+
|
98
|
+
ret = {
|
99
|
+
path: x, id: "#{id_vendor}:#{id_product}",
|
100
|
+
vendor_id: id_vendor, product_id: id_product
|
101
|
+
}
|
102
|
+
|
103
|
+
ret.merge!(bus_num: bus_num.to_i) unless bus_num.empty?
|
104
|
+
ret.merge!(dev_num: dev_num.to_i) unless dev_num.empty?
|
105
|
+
|
106
|
+
ret.merge!(serial: serial) unless serial.empty?
|
107
|
+
|
108
|
+
ret.merge!(hwdata: query) unless query.empty?
|
109
|
+
ret.merge!(product: product) unless product.empty?
|
110
|
+
ret.merge!(manufacturer: manufacturer) unless manufacturer.empty?
|
111
|
+
|
112
|
+
ret.merge!(removable: is_removable) unless is_removable.nil?
|
113
|
+
ret.merge!(authorized: authorized == 1)
|
114
|
+
|
115
|
+
ret.merge!(b_max_power: b_max_power) unless b_max_power.empty?
|
116
|
+
ret.merge!(b_max_packet_size0: b_max_packet_size0) if b_max_packet_size0
|
117
|
+
}.tap(&:compact!)
|
118
|
+
end
|
119
|
+
|
120
|
+
##
|
121
|
+
# Opens /sys/bus/usb/devices, and counts the total number of
|
122
|
+
# devices connected to the USB interface.
|
123
|
+
# The return type is an integer.
|
124
|
+
#
|
125
|
+
# It checks for devices with vendor and product id file.
|
126
|
+
# If there's no such file, it will not count them as a USB device.
|
127
|
+
#
|
128
|
+
# It could be also an integrated hub or a webcam, as well as
|
129
|
+
# external hotpluggable devices like printer, USB storage devices,
|
130
|
+
# USB mouse, USB keyboard, USB joypad etc.
|
131
|
+
#
|
132
|
+
# But if the information isn't available, it will return nil.
|
133
|
+
def count
|
134
|
+
@@sys_usb_readable ||= File.readable?('/sys/bus/usb/devices/')
|
135
|
+
return nil unless @@sys_usb_readable
|
136
|
+
|
137
|
+
Dir['/sys/bus/usb/devices/*/'.freeze].count { |x|
|
138
|
+
id_vendor_file = File.join(x, 'idVendor'.freeze)
|
139
|
+
id_product_file = File.join(x, 'idProduct'.freeze)
|
140
|
+
File.readable?(id_vendor_file) && File.readable?(id_product_file)
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
alias count_devices count
|
145
|
+
|
146
|
+
private
|
147
|
+
def hwdata
|
148
|
+
@@hwdata_file ||= "/usr/share/hwdata/usb.ids"
|
149
|
+
|
150
|
+
@@hwdata ||= if File.readable?(@@hwdata_file)
|
151
|
+
file_data = IO.readlines(@@hwdata_file, encoding: 'ASCII-8BIT')
|
152
|
+
ret, vendor_id = {}, nil
|
153
|
+
|
154
|
+
i = -1
|
155
|
+
file_data_size = file_data.size
|
156
|
+
|
157
|
+
while (i += 1) < file_data_size
|
158
|
+
x = file_data[i]
|
159
|
+
|
160
|
+
_lstripped = x.lstrip
|
161
|
+
next if _lstripped == ?#.freeze || _lstripped.empty?
|
162
|
+
|
163
|
+
if x.start_with?(?\t.freeze)
|
164
|
+
data = x.tap(&:strip!)
|
165
|
+
device_id = data[/\A.*?\s/].to_s.strip
|
166
|
+
device = data[device_id.length..-1].to_s.strip
|
167
|
+
ret[vendor_id][1][device_id] = device
|
168
|
+
else
|
169
|
+
data = x
|
170
|
+
vendor_id = data[/\A.*?\s/].to_s.strip
|
171
|
+
vendor = data[vendor_id.length..-1].to_s.strip
|
172
|
+
ret[vendor_id] = [vendor, {}]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
ret.freeze
|
177
|
+
else
|
178
|
+
{}
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def query_hwdata(vendor_id, product_id)
|
183
|
+
vendor = hwdata[vendor_id]
|
184
|
+
if vendor
|
185
|
+
{vendor: vendor[0], product: vendor[1][product_id]}
|
186
|
+
else
|
187
|
+
{}
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
data/lib/linux_stat/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: linux_stat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sourav Goswami
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-12-
|
11
|
+
date: 2020-12-24 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Linux only, efficient linux system utilization reporting and system monitoring
|
14
14
|
gem
|
@@ -20,6 +20,7 @@ extensions:
|
|
20
20
|
- ext/fs_stat/extconf.rb
|
21
21
|
- ext/sysconf/extconf.rb
|
22
22
|
- ext/utsname/extconf.rb
|
23
|
+
- ext/nproc/extconf.rb
|
23
24
|
extra_rdoc_files:
|
24
25
|
- README.md
|
25
26
|
files:
|
@@ -30,6 +31,8 @@ files:
|
|
30
31
|
- exe/linuxstat.rb
|
31
32
|
- ext/fs_stat/extconf.rb
|
32
33
|
- ext/fs_stat/fs_stat.c
|
34
|
+
- ext/nproc/extconf.rb
|
35
|
+
- ext/nproc/nproc.c
|
33
36
|
- ext/sysconf/extconf.rb
|
34
37
|
- ext/sysconf/sysconf.c
|
35
38
|
- ext/utsname/extconf.rb
|
@@ -48,6 +51,7 @@ files:
|
|
48
51
|
- lib/linux_stat/process.rb
|
49
52
|
- lib/linux_stat/process_info.rb
|
50
53
|
- lib/linux_stat/swap.rb
|
54
|
+
- lib/linux_stat/usb.rb
|
51
55
|
- lib/linux_stat/user.rb
|
52
56
|
- lib/linux_stat/version.rb
|
53
57
|
homepage: https://github.com/Souravgoswami/linux_stat/
|