compute_unit 0.1.0 → 0.2.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: 5caf721411458c1307f2714ba330c737ddd5987433a51d7753b6004649a92429
4
- data.tar.gz: ef3bacd1c4662e1ffe33dafad9c48f44c6fc3cefe161098957cc476e7ecac78d
3
+ metadata.gz: 0ce131c209f99ed5bd86a2439e56b2fcd8e0d7b85120db149d3c4427e6ea8ef0
4
+ data.tar.gz: 478ef837c6b68adecfc84bb6adc4f6120a8f8e119e371ce13f3503808e92788f
5
5
  SHA512:
6
- metadata.gz: 73b107433ce4ffcb3d6a5d35a8711cf39489ed111ccc368cb66d5f788f36690382242a3437c0bd6d40147c2ca727856d2fffd48b8b5edbaa8f4dd22b5ab228da
7
- data.tar.gz: 2debc1c284e7200efd00ca0e064d3b48f55a935d55409cc77f33db2db9344efabcdaadc3cd2bfd909174e58ba38727ed4ed845dad0395a19e08dc5ee0f54a428
6
+ metadata.gz: 9f1f22c7a80b053fb7612bb0e40bd7f2ea609b4c747dcdf486875289d2edab9090d590ca333d33be763cc3cec55faa6ca3a8568dc8f8f212eea3adf3e629120b
7
+ data.tar.gz: 11b96609eec70c967865ecb476367210a356dfdec6a9b833929c4992e937ad8f568cdf5a01e4f1a7fa77cdcf941a245d20a55a5704385b7de1c4efc11855605d
@@ -1,3 +1,10 @@
1
1
  # Compute Unit Changelog
2
2
 
3
+ ## Unrleased
4
+ ## 0.2.0
5
+ Released 6/5/2020
6
+ * Added more cpu methods for various POI.
7
+ * Ensure constants exist when side loaded
8
+ * Add descendent discovery mechanism to GPU class
9
+
3
10
  ## initial version 0.1.0
data/README.md CHANGED
@@ -40,6 +40,34 @@ devices = ComputeUnit.find_all
40
40
 
41
41
  ```
42
42
 
43
+ ### Subclassing a compute object
44
+ Instead of monkey patching this code you can simply subclass the objects. The find_all methods are intelligent enough to locate your subclass by searching the Objectspace for all decendants of `ComputeUnit::ComputeBase`. This makes it dead simple to add new functionality without having to wrap any code. This gives you the ability to include new modules or override existing methods.
45
+
46
+ ```ruby
47
+ # coolproject/vegagpu.rb
48
+ module CoolProject
49
+ class VegaGpu < ::ComputeUnit::Gpu::AmdGpu
50
+ include CoolProject::Metrics
51
+
52
+ def initialize(device_path, opts)
53
+ super(device_path, opts)
54
+ @is_vega = true
55
+ end
56
+ end
57
+ end
58
+
59
+ ```
60
+
61
+ Once you have your new class created all you need to do is load the class before running find all.
62
+
63
+ ```
64
+ require 'compute_unit'
65
+ require 'coolproject/vegagpu'
66
+ require 'yaml'
67
+
68
+ puts ComputeUnit.find_all.to_yaml
69
+
70
+ ```
43
71
 
44
72
  ## Make and Model information
45
73
  This library uses the pci database maintained here https://pci-ids.ucw.cz/ which is also used by `lspci` and other linux tools. If your device is giving the wrong info the problem is likely due to the database being incorrect.
@@ -51,9 +79,10 @@ If you want to refresh the database every time with finding all the devices you
51
79
  Or you can also run the simple cli tool. `update_pcidb` that comes with this library.
52
80
 
53
81
  ## Kernel support
54
- There will likely be changes with reading and writing information to sysfs as new kerneles are released. This library has been tested against.
82
+ There will likely be changes with reading and writing information to sysfs as new kernels are released. This library has been tested against.
55
83
 
56
84
  * 4.15 - 4.20
85
+ * 5.x
57
86
 
58
87
  ## Development
59
88
 
@@ -9,6 +9,25 @@ module ComputeUnit
9
9
  []
10
10
  end
11
11
 
12
+ def self.create_from_path(device_path, index)
13
+ opts = {
14
+ device_class_id: device_class(device_path),
15
+ device_id: device(device_path),
16
+ device_vendor_id: device_vendor(device_path),
17
+ subsystem_vendor_id: subsystem_vendor(device_path),
18
+ subsystem_device_id: subsystem_device(device_path),
19
+ index: index
20
+ }
21
+ new(device_path, opts)
22
+ end
23
+
24
+ def self.find_all
25
+ return []
26
+ devices.sort.map.with_index do |device_path, index|
27
+ create_from_path(device_path, index)
28
+ end
29
+ end
30
+
12
31
  # /sys/devices/platform $ more coretemp.0/hwmon/hwmon1/temp1_input / 1000
13
32
  end
14
33
  end
@@ -16,6 +16,16 @@ module ComputeUnit
16
16
  # timeout value
17
17
  CACHE_TIMEOUT = 30
18
18
 
19
+ # @return [Array] - find all the decendants of thyself
20
+ def self.compute_classes
21
+ ObjectSpace.each_object(Class).select do |klass|
22
+ # <Class:#<Crossbelt::ComputeUnit::NvidiaGpu:0x00007fddc5c02a10>>
23
+ # We have to filter out these kinds of Ojbects as they don't respond to :new
24
+ # without a singleton error.
25
+ klass < self && !klass.to_s.include?('Class')
26
+ end
27
+ end
28
+
19
29
  # @param value [Float] a value to offset the power calculation, either a whole number, or decimal
20
30
  # @return [Integer] the value set as the offset
21
31
  def power_offset=(value)
@@ -13,6 +13,78 @@ module ComputeUnit
13
13
  end
14
14
  end
15
15
 
16
+ def model
17
+ raw_cpu_data[:model_name]
18
+ end
19
+
20
+ def make
21
+ raw_cpu_data[:vendor_id]
22
+ end
23
+
24
+ def num_cores
25
+ raw_cpu_data[:cores_per_socket].to_i
26
+ end
27
+
28
+ def num_threads
29
+ raw_cpu_data[:threads_per_core].to_i
30
+ end
31
+
32
+ def nproc
33
+ raw_cpu_data[:cpus].to_i
34
+ end
35
+
36
+ def current_freq_mhz
37
+ raw_cpu_data[:cpu_mhz].to_f.round(0)
38
+ end
39
+
40
+ def max_freq_mhz
41
+ raw_cpu_data[:cpu_max_mhz].to_f.round(0)
42
+ end
43
+
44
+ def min_freq_mhz
45
+ raw_cpu_data[:cpu_min_mhz].to_f.round(0)
46
+ end
47
+
48
+ def base_hwmon_path
49
+ File.join(ComputeUnit::SYSFS_PATH, 'devices/platform/coretemp.0/hwmon')
50
+ end
51
+
52
+ # @return [Hash] - a hash of temp readings and their labels
53
+ # @example temps => {:core_0=>31, :core_1=>31, :package_id_0=>27}
54
+ def temps
55
+ Dir.glob(File.join(hwmon_path, 'temp*_label')).each_with_object({}) do |label_file, acc|
56
+ temp_file = label_file.sub('label', 'input')
57
+ label = normalize_name(read_file(label_file))
58
+ reading = read_file(temp_file).to_f.round(0) / 1000
59
+ acc[label] = reading
60
+ acc
61
+ end
62
+ end
63
+
64
+ # @return [Integer] - the temperature of the cpu package in Celsius
65
+ def temp
66
+ read_hwmon_data('temp1_input', 0).to_f.round(0) / 1000
67
+ end
68
+
69
+ def metrics
70
+ {
71
+ temp: temp,
72
+ minFreqMhz: min_freq_mhz,
73
+ maxFreqMhz: max_freq_mhz,
74
+ currentFreqMhz: current_freq_mhz,
75
+ model: model,
76
+ make: make,
77
+ numCores: num_cores,
78
+ numThreads: num_threads,
79
+ nproc: nproc,
80
+ temps: temps
81
+ }
82
+ end
83
+
84
+ def to_h
85
+ super.merge(metrics)
86
+ end
87
+
16
88
  def self.create_from_path(device_path, index)
17
89
  opts = {
18
90
  device_class_id: device_class(device_path),
@@ -26,11 +98,51 @@ module ComputeUnit
26
98
  end
27
99
 
28
100
  def self.find_all
29
- return [] # not quite ready to show cpu data
30
101
  devices.sort.map.with_index do |device_path, index|
31
102
  create_from_path(device_path, index)
32
103
  end
33
104
  end
34
- # /sys/devices/platform $ more coretemp.0/hwmon/hwmon1/temp1_input / 1000
105
+
106
+ private
107
+
108
+ # @param value [String]
109
+ # @return [String]
110
+ # @summary downcases and transforms spaces into underscores
111
+ def normalize_name(value)
112
+ value.downcase.gsub(/\s/, '_').gsub('(s)', 's').to_sym
113
+ end
114
+
115
+ # @return [Hash] - a hash of cpu info returned from lscpu
116
+ # normalizes the key name by downcasing and removing spaces
117
+ # @example
118
+ # raw_cpu_data() =>
119
+ # {"architecture"=>"x86_64", "cpu_op-modes"=>"32-bit, 64-bit", "byte_order"=>"Little Endian",
120
+ # "cpus"=>"4", "on-line_cpus list"=>"0-3", "threads_per core"=>"2", "cores_per socket"=>"2",
121
+ # "sockets"=>"1", "numa_nodes"=>"1", "vendor_id"=>"GenuineIntel", "cpu_family"=>"6",
122
+ # "model"=>"158", "model_name"=>"Intel(R) Core(TM) i3-7100 CPU @ 3.90GHz", "stepping"=>"9",
123
+ # "cpu_mhz"=>"800.545", "cpu_max mhz"=>"3900.0000", "cpu_min mhz"=>"800.0000",
124
+ # "bogomips"=>"7799.87", "virtualization"=>"VT-x", "l1d_cache"=>"32K", "l1i_cache"=>"32K",
125
+ # "l2_cache"=>"256K", "l3_cache"=>"3072K", "numa_node0 cpus"=>"0-3",
126
+ # "flags"=>"fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36
127
+ # clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc
128
+ # art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni
129
+ # pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1
130
+ # sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm
131
+ # 3dnowprefetch cpuid_fault invpcid_single tpr_shadow vnmi flexpriority ept vpid ept_ad
132
+ # fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx rdseed adx smap clflushopt intel_pt
133
+ # xsaveopt xsavec xgetbv1 xsaves dtherm arat pln pts hwp hwp_notify hwp_act_window hwp_epp"
134
+ # }
135
+ def raw_cpu_data
136
+ @raw_cpu_data ||= begin
137
+ # turns each line into a hash of key value pairs
138
+ regex = /(?<name>[\s\w\-\(\)]+)\:\s+(?<value>[@\s\w\-\,\.\(\)]+)$/
139
+ `lscpu`.lines.each_with_object({}) do |line, acc|
140
+ m = line.match(regex)
141
+ name = normalize_name(m.named_captures['name'])
142
+ acc[name] = m.named_captures['value'].chomp if m
143
+ acc
144
+ end
145
+ end
146
+ end
35
147
  end
36
148
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'compute_unit'
3
4
  require 'compute_unit/logger'
4
5
  require 'compute_unit/cache_store'
5
6
  require 'compute_unit/utils'
6
-
7
7
  # This file supports reading from sysfs
8
8
  # More information about sysfs can be found here - https://www.kernel.org/doc/Documentation/filesystems/sysfs-pci.txt
9
9
  module ComputeUnit
@@ -127,7 +127,10 @@ module ComputeUnit
127
127
 
128
128
  def read_file(path, default = nil)
129
129
  File.read(path).chomp
130
- rescue Errno::EINVAL, Errno::EPERM, Errno::ENOENT
130
+ rescue Errno::EINVAL, Errno::EPERM
131
+ default
132
+ rescue Errno::ENOENT
133
+ logger.warn("File #{path} does not exist, using defaults")
131
134
  default
132
135
  rescue Errno::EACCES
133
136
  logger.fatal('run this command as root or with sudo, using default value')
@@ -268,7 +271,7 @@ module ComputeUnit
268
271
  logger.fatal(e.message)
269
272
  default
270
273
  rescue Errno::ENOENT
271
- logger.fatal("File #{path} does not exist")
274
+ logger.warn("File #{path} does not exist")
272
275
  default
273
276
  rescue Errno::EACCES
274
277
  logger.fatal('Run this command as root or with sudo')
@@ -286,7 +289,7 @@ module ComputeUnit
286
289
  rescue Errno::EINVAL, Errno::EPERM => e
287
290
  logger.fatal(e.message)
288
291
  rescue Errno::ENOENT
289
- logger.fatal("File #{path} does not exist")
292
+ logger.warn("File #{path} does not exist")
290
293
  rescue Errno::EACCES
291
294
  logger.fatal('Run this command as root or with sudo')
292
295
  end
@@ -265,7 +265,7 @@ module ComputeUnit
265
265
  def self.find_all(use_opencl = false)
266
266
  require 'compute_unit/gpus/amd_gpu'
267
267
  require 'compute_unit/gpus/nvidia_gpu'
268
- g = ComputeUnit::AmdGpu.find_all(use_opencl) + ComputeUnit::NvidiaGpu.find_all(use_opencl)
268
+ g = compute_classes.map { |klass| klass.find_all(use_opencl) }.flatten
269
269
  g.sort_by(&:index)
270
270
  end
271
271
 
@@ -90,6 +90,16 @@ module ComputeUnit
90
90
  utilization
91
91
  end
92
92
 
93
+ # @return [Integer] - the temperature of the asic chip
94
+ def asic_temp
95
+ read_hwmon_data('temp2_input', 0).to_i / 1000
96
+ end
97
+
98
+ # @return [Integer] - temperature of the memory
99
+ def mem_temp
100
+ read_hwmon_data('temp3_input', 0).to_i / 1000
101
+ end
102
+
93
103
  # @return [Integer] - returns temp of gpu in celius
94
104
  def temp
95
105
  read_hwmon_data('temp1_input', 0).to_i / 1000
@@ -421,16 +431,6 @@ module ComputeUnit
421
431
  vddci_voltage_table.first[:volt]
422
432
  end
423
433
 
424
- # @return [Integer] - the temperature of the asic chip
425
- def asic_temp
426
- read_hwmon_data('temp2_input', 0).to_i / 1000
427
- end
428
-
429
- # @return [Integer] - the temperature of the memory chips
430
- def mem_temp
431
- read_hwmon_data('temp3_input', 0).to_i / 1000
432
- end
433
-
434
434
  def set_mem_clock_and_vddc(mem_clock, mem_volt)
435
435
  return unless experimental_on?
436
436
 
@@ -8,7 +8,7 @@ module ComputeUnit
8
8
  if ENV['LOG_FILENAME'] && File.exist?(ENV['LOG_FILENAME'])
9
9
  ENV['LOG_FILENAME']
10
10
  else
11
- STDOUT
11
+ STDERR
12
12
  end
13
13
  end
14
14
 
@@ -18,7 +18,7 @@ module ComputeUnit
18
18
  log.level = log_level
19
19
  log.progname = 'ComputeUnit'
20
20
  log.formatter = proc do |severity, datetime, progname, msg|
21
- if Logger.log_file == STDOUT
21
+ if Logger.log_file == STDERR
22
22
  "#{severity} - #{progname}: #{msg}\n".send(color(severity))
23
23
  else
24
24
  "#{datetime} #{severity} - #{progname}: #{msg}\n".send(color(severity))
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ComputeUnit
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: compute_unit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.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-05-25 00:00:00.000000000 Z
11
+ date: 2020-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opencl_ruby_ffi