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.
@@ -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 = File.readable?('/proc/uptime')
146
+ @@uptime_readable ||= File.readable?('/proc/uptime')
147
147
  end
148
148
  end
149
149
  end
@@ -6,7 +6,7 @@ module LinuxStat
6
6
  #
7
7
  # The return type is an Array of Integers.
8
8
  def list
9
- Dir['/proc/*'].select! { |x|
9
+ Dir['/proc/*'].select { |x|
10
10
  pid = File.split(x)[1]
11
11
  pid.to_i.to_s == pid
12
12
  }.map! { |x| File.split(x)[-1].to_i }
@@ -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
- cpu = totald.-(idle2 - idle1).fdiv(totald).*(100).round(2).abs./(LinuxStat::CPU.count)
272
+ cpu_u = totald.-(idle2 - idle1).fdiv(totald).abs.*(100)./(cpu_count)
271
273
 
272
274
  {
273
- cpu_usage: cpu,
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
- totald.-(idle2 - idle1).fdiv(totald).*(100).round(2).abs./(LinuxStat::CPU.count)
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
- totald.-(idle2 - idle1).fdiv(totald).*(100).round(2).abs
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.619999999999
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 - (IO.read(stat_file).split[21].to_i / get_ticks)
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
- @@ticks ||= Sysconf.sc_clk_tck
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
@@ -117,7 +117,7 @@ module LinuxStat
117
117
  val = IO.readlines('/proc/swaps').drop(1)
118
118
  return [[], []] if val.empty?
119
119
 
120
- val.map { |x|
120
+ val.map! { |x|
121
121
  x.strip.split.values_at(2, 3).map!(&:to_i)
122
122
  }.transpose
123
123
  end
@@ -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
@@ -1,3 +1,3 @@
1
1
  module LinuxStat
2
- VERSION ||= "0.7.5"
2
+ VERSION ||= "1.0.1"
3
3
  end
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.7.5
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-17 00:00:00.000000000 Z
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/