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 +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +30 -1
- data/lib/compute_unit/asic.rb +19 -0
- data/lib/compute_unit/compute_base.rb +10 -0
- data/lib/compute_unit/cpu.rb +114 -2
- data/lib/compute_unit/device.rb +7 -4
- data/lib/compute_unit/gpu.rb +1 -1
- data/lib/compute_unit/gpus/amd_gpu.rb +10 -10
- data/lib/compute_unit/logger.rb +2 -2
- data/lib/compute_unit/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ce131c209f99ed5bd86a2439e56b2fcd8e0d7b85120db149d3c4427e6ea8ef0
|
4
|
+
data.tar.gz: 478ef837c6b68adecfc84bb6adc4f6120a8f8e119e371ce13f3503808e92788f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f1f22c7a80b053fb7612bb0e40bd7f2ea609b4c747dcdf486875289d2edab9090d590ca333d33be763cc3cec55faa6ca3a8568dc8f8f212eea3adf3e629120b
|
7
|
+
data.tar.gz: 11b96609eec70c967865ecb476367210a356dfdec6a9b833929c4992e937ad8f568cdf5a01e4f1a7fa77cdcf941a245d20a55a5704385b7de1c4efc11855605d
|
data/CHANGELOG.md
CHANGED
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
|
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
|
|
data/lib/compute_unit/asic.rb
CHANGED
@@ -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)
|
data/lib/compute_unit/cpu.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/compute_unit/device.rb
CHANGED
@@ -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
|
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.
|
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.
|
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
|
data/lib/compute_unit/gpu.rb
CHANGED
@@ -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 =
|
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
|
|
data/lib/compute_unit/logger.rb
CHANGED
@@ -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
|
-
|
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 ==
|
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))
|
data/lib/compute_unit/version.rb
CHANGED
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.
|
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
|
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
|