compute_unit 0.3.0 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dcc45e864245505b64cd82233ca7f8ad70d0d12ca1a976862ba46c80e66fefc8
4
- data.tar.gz: 6903aff2b613ee6f88c41aa051e65404f31c8923bab2059323dfd27bc99cc5e0
3
+ metadata.gz: e7454de36f403e2803ee5b87ee989781de8b663d32cfe290b3c22ab0c18f598d
4
+ data.tar.gz: 6b6afa144e05011bec545ddbda688ae663650dce4d09070be9a3922f84bc9606
5
5
  SHA512:
6
- metadata.gz: a971813c562bc8c29305f1fe3668f229b52bd018049d36879fcc943a935232e8d8bb34095e74643ca9d3da594796a4cdfdc33fe06b36a8501a75c0a330489cb3
7
- data.tar.gz: bc17da953ab1904661c7037977c36b1dda69c7c4236c5854730743fa9332987a92ba3891e97052c4ee9361bea7a0b830a917235e15f1db75e8246b7835715a6e
6
+ metadata.gz: 3821595267038d8424a7ae3558437339f87b871ce4e294ffe80cce1c928924a9ae1ebd7fa9b293c08a2b40217a71f7a4358e8a943456dd0c978cf7e4bfbb5a0a
7
+ data.tar.gz: 4fa97e267f9fd8c60999d8af1dd96e15e9e77435c98ece688e53386147e0e7470b1f9a7e149f702fbcb237fbf6c41085f051db9ad441e1388dbde6ce9d2469a5
@@ -1,6 +1,28 @@
1
1
  # Compute Unit Changelog
2
2
 
3
- ## Unrleased
3
+ ## 0.5.0
4
+ Released 10/5/2020
5
+
6
+ * Add more method docs
7
+ * Allow overriding of cpu power
8
+ * Update cpu name using model
9
+ * Add new search methods
10
+ * Add voltage and other cpu metrics
11
+ ## 0.4.0
12
+ * Adds ability to list attached processes to compute_unit sorted by field
13
+ * Adds ability to list top_x attached processes sorted by field
14
+
15
+ ## 0.3.3
16
+ * Fix bug with default database not being created
17
+
18
+ ## 0.3.2
19
+ * Fix bug with default database not being created
20
+
21
+ ## 0.3.1
22
+ Released 9/24/2020
23
+
24
+ * Use the default system pcidb file instead of throwing error
25
+ * Return default data if no hmon value exist
4
26
 
5
27
  ## 0.3.0
6
28
  Released 6/16/2020
data/README.md CHANGED
@@ -35,6 +35,12 @@ Or install it yourself as:
35
35
 
36
36
  ## Usage
37
37
 
38
+ Ensure the pci database exist on your system. You can update it at anytime with the built in linux command.
39
+
40
+ `/usr/sbin/update-pciids` or the command from this gem `update_pcidb` installed in your gem bin directory.
41
+
42
+ Additionally, when using the `ComputeUnit.find_all_with_database` method.
43
+
38
44
  Find all compute devices
39
45
  ```
40
46
  require 'compute_unit'
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.metadata['homepage_uri'] = spec.homepage
27
27
  spec.metadata['source_code_uri'] = spec.homepage
28
- spec.metadata['changelog_uri'] = "#{spec.homepage}/CHANGELOG.md"
28
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/-/blob/master/CHANGELOG.md"
29
29
 
30
30
  # Specify which files should be added to the gem when it is released.
31
31
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
35
35
  spec.bindir = 'exe'
36
36
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
37
  spec.require_paths = ['lib']
38
-
38
+ spec.add_dependency 'sys-proctable', '~> 1.2', '>= 1.2.0'
39
39
  spec.add_dependency 'opencl_ruby_ffi', '~> 1.3.4'
40
40
  spec.add_development_dependency 'bundler', '~> 2.1'
41
41
  spec.add_development_dependency 'rake', '~> 13'
@@ -11,23 +11,56 @@ module ComputeUnit
11
11
  SYS_DEVICE_PATH = File.join(SYSFS_PATH, 'bus/pci/devices')
12
12
  PCI_DATABASE_PATH = File.join(File.dirname(__dir__), 'pci.ids')
13
13
  PCI_DATABASE_URL = 'http://pci-ids.ucw.cz/v2.2/pci.ids'
14
+ DEFAULT_PCIDB_PATH = '/usr/share/misc/pci.ids'
14
15
 
16
+ # @param use_opencl [Boolean]
17
+ # @return [Array] - return a list of compute units
15
18
  def self.find_all(use_opencl = false)
16
19
  require 'compute_unit/gpu'
17
20
  require 'compute_unit/cpu'
18
21
  require 'compute_unit/asic'
19
- raise Exceptions::InvalidPCIDatabase.new('Run: ComputeUnit.refresh_pci_database') unless File.exist?(PCI_DATABASE_PATH)
20
22
 
21
- ComputeUnit::Gpu.find_all(use_opencl) +
22
- ComputeUnit::Cpu.find_all +
23
- ComputeUnit::Asic.find_all
23
+ # if this file doesn't exist we need to fetch it or copy it
24
+ refresh_pci_database unless File.exist?(PCI_DATABASE_PATH)
25
+
26
+ Gpu.find_all(use_opencl) + Cpu.find_all + Asic.find_all
27
+ end
28
+
29
+ # @param pid [Integer] the pid to search with
30
+ # @param field [Symbol] - the field to sort by
31
+ # @return [Array] - a array of device paths
32
+ # @example usage
33
+ # device_paths_by_process(3748) => ["/sys/bus/pci/devices/0000:00:00.0"]
34
+ def self.device_paths_by_process(pid)
35
+ # processes = ComputeUnit::Cpu.attached_processes(field).last(1) + ComputeUnit::Gpu.attached_processes(field)
36
+ # processes.find_all { |process| process.pid == pid }
37
+ # We can get the utilized devices but it appears cubersome to convert to a device path
38
+ # This method uses more resources
39
+ find_by_process(pid).map(&:device_path)
40
+ end
41
+
42
+ # @param pid [Integer] the pid to search with
43
+ # @param use_opencl [Boolean] use opencl on gpu devices
44
+ def self.find_by_process(pid, use_opencl = false)
45
+ find_all(use_opencl).find_all do |unit|
46
+ unit.top_processes.first.pid.to_i == pid.to_i
47
+ end
48
+ end
49
+
50
+ # copies the default pci database from linux filesystem over to the gem path
51
+ def self.copy_default_database
52
+ FileUtils.cp(DEFAULT_PCIDB_PATH, PCI_DATABASE_PATH) if File.exist?(DEFAULT_PCIDB_PATH)
24
53
  end
25
54
 
55
+ # get a fresh copy of the database and then use find_all
56
+ # @param use_opencl [Boolean]
57
+ # @return [Array] - return a list of compute units
26
58
  def self.find_all_with_database(use_opencl = false)
27
59
  refresh_pci_database
28
60
  find_all(use_opencl)
29
61
  end
30
62
 
63
+ # downloads the pci database
31
64
  def self.refresh_pci_database
32
65
  ComputeUnit::Utils.check_for_root
33
66
  require 'net/http'
@@ -4,9 +4,12 @@ require 'time'
4
4
  require 'compute_unit/formatters'
5
5
  require 'compute_unit/logger'
6
6
  require 'compute_unit/device'
7
+ require 'sys/proctable'
7
8
 
8
9
  module ComputeUnit
9
10
  class ComputeBase < Device
11
+ include Sys
12
+
10
13
  attr_reader :type, :serial, :meta, :uuid, :timestamp, :index, :compute_type
11
14
  attr_accessor :power_offset
12
15
 
@@ -26,6 +29,24 @@ module ComputeUnit
26
29
  end
27
30
  end
28
31
 
32
+ # @summary Finds all cpu attached processes and sorts by pctcpu
33
+ # param filter [Regex] - if supplied filter out devices from fd list
34
+ # @param field [Symbol] - the field to sort by
35
+ # @return [Array] - an array of attached processes
36
+ def attached_processes(field = :pctcpu, filter = nil)
37
+ raise NotImplementedError unless self.class.respond_to?(:attached_processes)
38
+
39
+ self.class.attached_processes(field, filter)
40
+ end
41
+
42
+ # @summary Find the processes consuming the most cpu
43
+ # @param x [Integer] the number of processes to return, defaults to 1
44
+ # @param field [Symbol] - the field to sort by
45
+ # @return [Array] - an array of attached processes
46
+ def top_processes(x = 1, field = :pctcpu)
47
+ attached_processes(field).last(x)
48
+ end
49
+
29
50
  # @param value [Float] a value to offset the power calculation, either a whole number, or decimal
30
51
  # @return [Integer] the value set as the offset
31
52
  def power_offset=(value)
@@ -6,8 +6,8 @@ module ComputeUnit
6
6
  class Cpu < ComputeBase
7
7
  DEVICE_CLASS = '060000'
8
8
  DEVICE_CLASS_NAME = 'CPU'
9
+ VOLTAGE_MSR = 0x198
9
10
  # @return [Array] - returns a list of device paths of all devices considered for display
10
- alias name model
11
11
 
12
12
  def self.devices
13
13
  ComputeUnit::ComputeBase.devices.find_all do |device|
@@ -15,38 +15,83 @@ module ComputeUnit
15
15
  end
16
16
  end
17
17
 
18
+ def utilization
19
+ 1 # until we can calculate this. Is loadavg a good metric? or load / cpus
20
+ end
21
+
22
+ # @summary Finds all cpu attached processes and sorts by pctcpu
23
+ # @param field [Symbol] - the field to sort by
24
+ # @param filter [Regex] - if supplied filter out devices from fd list
25
+ # @return [Array] - an array of attached processes
26
+ def self.attached_processes(field = :pctcpu, _filter = nil)
27
+ Sys::ProcTable.ps(smaps: false).sort_by(&field)
28
+ end
29
+
30
+ # @summary [Float] - returns the voltage of the cpu
31
+ # @param processor_id [Integer] - the id of the cpu
32
+ def voltage(processor_id = 0)
33
+ file = "/dev/cpu/#{processor_id}/msr"
34
+ return 0 unless File.exist?(file)
35
+
36
+ # read 8 bytes, then unpack it by turning it into an integer
37
+ # make it a binary string, pluck out some specific bits, then
38
+ # convert it back to an integer
39
+ # divide by 8192 to give the voltage
40
+ # lowbit = 32
41
+ # highbit = 47
42
+ # bits = 47 - 32 + 1 # we want to read bits 32-47
43
+ msr = IO.new IO.sysopen(file, 'rb')
44
+ msr.sysseek(VOLTAGE_MSR)
45
+ data, = msr.sysread(8).unpack('q')
46
+ format('%.2f', ((data >> 32) / 8192.to_f))
47
+ end
48
+
49
+ # @return [String] - the model / name of the cpu
18
50
  def model
19
51
  raw_cpu_data[:model_name]
20
52
  end
21
53
 
54
+ # @return [String] - the model / name of the cpu
55
+ def name
56
+ model
57
+ end
58
+
59
+ # @return [String] - the maker of the cpu
22
60
  def make
23
61
  raw_cpu_data[:vendor_id]
24
62
  end
25
63
 
64
+ # @return [Integer] - the number of cores
26
65
  def num_cores
27
66
  raw_cpu_data[:cores_per_socket].to_i
28
67
  end
29
68
 
69
+ # @return [Integer] - the number of threads
30
70
  def num_threads
31
71
  raw_cpu_data[:threads_per_core].to_i
32
72
  end
33
73
 
74
+ # @return [Integer] - the number of cpus
34
75
  def nproc
35
76
  raw_cpu_data[:cpus].to_i
36
77
  end
37
78
 
79
+ # @return [Float] - current mhz of cpu
38
80
  def current_freq_mhz
39
81
  raw_cpu_data[:cpu_mhz].to_f.round(0)
40
82
  end
41
83
 
84
+ # @return [Float] - max mhz of cpu
42
85
  def max_freq_mhz
43
86
  raw_cpu_data[:cpu_max_mhz].to_f.round(0)
44
87
  end
45
88
 
89
+ # @return [Float] - current min of cpu
46
90
  def min_freq_mhz
47
91
  raw_cpu_data[:cpu_min_mhz].to_f.round(0)
48
92
  end
49
93
 
94
+ # @return [String] the path of the hwmon path for monitoring temps
50
95
  def base_hwmon_path
51
96
  File.join(ComputeUnit::SYSFS_PATH, 'devices/platform/coretemp.0/hwmon')
52
97
  end
@@ -68,6 +113,40 @@ module ComputeUnit
68
113
  read_hwmon_data('temp1_input', 0).to_f.round(0) / 1000
69
114
  end
70
115
 
116
+ def status
117
+ 0
118
+ end
119
+
120
+ def power
121
+ ENV.fetch('CPU_POWER', 60) # until we can calculate power we will just use 60
122
+ end
123
+
124
+ def fan
125
+ 2500 # until we can calculate fan speed
126
+ end
127
+
128
+ def mem_temp
129
+ 0 # until we can get the mem temp
130
+ end
131
+
132
+ def pci_loc
133
+ device_path
134
+ end
135
+
136
+ def status_info
137
+ { index: "CPU#{index}",
138
+ name: model,
139
+ bios: 'N/A',
140
+ core_clock: current_freq_mhz,
141
+ memory_clock: 'N/A',
142
+ power: power,
143
+ fan: fan,
144
+ core_volt: voltage,
145
+ temp: temp,
146
+ mem_temp: mem_temp,
147
+ status: status }
148
+ end
149
+
71
150
  def metrics
72
151
  {
73
152
  temp: temp,
@@ -87,6 +166,14 @@ module ComputeUnit
87
166
  super.merge(metrics)
88
167
  end
89
168
 
169
+ def initialize(_device_path, opts)
170
+ super
171
+ @type = :CPU
172
+ @pci_loc = device_path,
173
+ @index = opts[:index].to_i
174
+ @power_offset = 0
175
+ end
176
+
90
177
  def self.create_from_path(device_path, index)
91
178
  opts = {
92
179
  device_class_id: device_class(device_path),
@@ -99,7 +186,7 @@ module ComputeUnit
99
186
  new(device_path, opts)
100
187
  end
101
188
 
102
- def self.find_all
189
+ def self.find_all(_use_opencl = false)
103
190
  devices.sort.map.with_index do |device_path, index|
104
191
  create_from_path(device_path, index)
105
192
  end
@@ -140,9 +140,9 @@ module ComputeUnit
140
140
  # @param item [String] - the name of the hwmon file to read from
141
141
  # @param default [Object] - the default value to return if the file is empty or not readable
142
142
  # @return [String] - the value of the item looked up
143
- def read_hwmon_data(item, _default = nil)
143
+ def read_hwmon_data(item, default = nil)
144
144
  path = File.join(hwmon_path, item)
145
- read_file(path)
145
+ read_file(path, default)
146
146
  end
147
147
 
148
148
  # @param item [String] - the name of the hwmon file to write to
@@ -13,6 +13,19 @@ module ComputeUnit
13
13
  type
14
14
  end
15
15
 
16
+ # @summary Finds all cpu attached processes and sorts by pctcpu
17
+ # @param filter [Regex] - if supplied filter out devices from fd list
18
+ # @param field [Symbol] - the field to sort by
19
+ # @return [Array] - an array of attached processes
20
+ def self.attached_processes(field = :pctcpu, filter = %r{/dev/dri|nvidia\d+})
21
+ filter ||= %r{/dev/dri|nvidia\d+}
22
+ # looks for any fd device with dri or nvidia in the name
23
+ p = Sys::ProcTable.ps(smaps: false).find_all do |p|
24
+ p.fd.values.find { |f| f =~ filter }
25
+ end
26
+ p.sort_by(&field)
27
+ end
28
+
16
29
  # @return [OpenCL_Device]
17
30
  def opencl_device
18
31
  @opencl_device ||= self.class.opencl_devices.find_all { |cu| cu[:type] == make }[index] if use_opencl
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ComputeUnit
4
- VERSION = '0.3.0'
4
+ VERSION = '0.5.0'
5
5
  end
metadata CHANGED
@@ -1,15 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: compute_unit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Corey Osman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-16 00:00:00.000000000 Z
11
+ date: 2020-11-07 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sys-proctable
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.2.0
20
+ - - "~>"
21
+ - !ruby/object:Gem::Version
22
+ version: '1.2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 1.2.0
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.2'
13
33
  - !ruby/object:Gem::Dependency
14
34
  name: opencl_ruby_ffi
15
35
  requirement: !ruby/object:Gem::Requirement
@@ -119,7 +139,7 @@ licenses:
119
139
  metadata:
120
140
  homepage_uri: https://gitlab.com/blockops/compute_unit
121
141
  source_code_uri: https://gitlab.com/blockops/compute_unit
122
- changelog_uri: https://gitlab.com/blockops/compute_unit/CHANGELOG.md
142
+ changelog_uri: https://gitlab.com/blockops/compute_unit/-/blob/master/CHANGELOG.md
123
143
  post_install_message:
124
144
  rdoc_options: []
125
145
  require_paths: