compute_unit 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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: