amdgpu_fan 0.6.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/environment.rb +2 -0
- data/config/icons.yml +2 -2
- data/lib/amdgpu_fan/cli.rb +46 -31
- data/lib/amdgpu_fan/connector.rb +3 -4
- data/lib/amdgpu_fan/mixin/cli_output_format.rb +23 -7
- data/lib/amdgpu_fan/mixin/fan.rb +1 -2
- data/lib/amdgpu_fan/mixin/sys_write.rb +1 -2
- data/lib/amdgpu_fan/pci.rb +66 -0
- data/lib/amdgpu_fan/service.rb +38 -10
- data/lib/amdgpu_fan/stat_set.rb +3 -2
- data/lib/amdgpu_fan/version.rb +1 -1
- data/lib/amdgpu_fan/watcher.rb +19 -15
- metadata +62 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad0c6af3e3dea6b56a0526203a603591583ea8184bd8e49f7efcdd2c3dab492b
|
4
|
+
data.tar.gz: 9ccb672107d73c822b31bd52d7c0048f0d79d175f02bca1c3b8a7df351f1b9b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 34230d04f43087f2c81517bccb6e74a0f976b8909b67c287011143f016a06e54a7c7a02b32e33cc21221305473b30ab23d2af699d658410573fa702452dd05ff
|
7
|
+
data.tar.gz: 7162d533859e691610b73ac969ea4a87946bdfc5803b83f391e38f9070e2077fe1eefe415baa7a553f82ab39d21da9f4e59cf107dbcbd8085a0ddcb34970443e
|
data/README.md
CHANGED
@@ -93,7 +93,7 @@ And now the watch is ended.
|
|
93
93
|
|
94
94
|
- [Ruby](https://www.ruby-lang.org) with [Bundler](https://bundler.io)
|
95
95
|
- [Thor](http://whatisthor.com/) (installed with `bundle install`)
|
96
|
-
-
|
96
|
+
- Internet connection - Device info is retrieved from https://pci-ids.ucw.cz/
|
97
97
|
|
98
98
|
## Building a binary
|
99
99
|
|
data/config/environment.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'async'
|
3
4
|
require 'thor'
|
4
5
|
|
5
6
|
require_relative '../lib/amdgpu_fan'
|
@@ -10,5 +11,6 @@ require_relative '../lib/amdgpu_fan/mixin/sys_write'
|
|
10
11
|
|
11
12
|
require_relative '../lib/amdgpu_fan/service'
|
12
13
|
require_relative '../lib/amdgpu_fan/cli'
|
14
|
+
require_relative '../lib/amdgpu_fan/pci'
|
13
15
|
require_relative '../lib/amdgpu_fan/stat_set'
|
14
16
|
require_relative '../lib/amdgpu_fan/watcher'
|
data/config/icons.yml
CHANGED
data/lib/amdgpu_fan/cli.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# rubocop:disable Metrics/AbcSize, Metrics/ClassLength, Metrics/MethodLength
|
4
|
+
|
3
5
|
require 'yaml'
|
4
6
|
|
5
7
|
module AmdgpuFan
|
@@ -7,10 +9,14 @@ module AmdgpuFan
|
|
7
9
|
class Cli < Thor
|
8
10
|
include CliOutputFormat
|
9
11
|
|
10
|
-
ICONS = YAML.
|
12
|
+
ICONS = YAML.safe_load(File.read(File.join(__dir__, '../../config/icons.yml')))
|
11
13
|
.transform_keys(&:to_sym).freeze
|
12
14
|
WATCH_FIELD_SEPARATOR = ' | '
|
13
15
|
|
16
|
+
def self.exit_on_failure?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
14
20
|
desc 'connectors', 'View the status of the display connectors.'
|
15
21
|
def connectors
|
16
22
|
amdgpu_service.connectors.each do |connector|
|
@@ -56,18 +62,19 @@ module AmdgpuFan
|
|
56
62
|
desc 'status [--logo]', 'View device info, current fan speed, and temperature.'
|
57
63
|
def status(option = nil)
|
58
64
|
puts radeon_logo if option == '--logo'
|
59
|
-
puts ICONS[:gpu] + ' GPU:'.ljust(
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
65
|
+
puts ICONS[:gpu] + ' GPU:'.ljust(11) + amdgpu_service.name
|
66
|
+
puts ICONS[:vbios] + ' vBIOS:'.ljust(11) + amdgpu_service.vbios_version
|
67
|
+
puts "#{ICONS[:display]} Displays: #{amdgpu_service.display_names.join(', ')}"
|
68
|
+
puts ICONS[:clock] + ' Clocks:'.ljust(11) + clock_status
|
69
|
+
puts ICONS[:memory] + ' Memory:'.ljust(11) + mem_total_mibibyes
|
70
|
+
puts ICONS[:fan] + ' Fan:'.ljust(11) + fan_status
|
71
|
+
puts ICONS[:temp] + ' Temp:'.ljust(11) + "#{amdgpu_service.temperature}°C"
|
72
|
+
puts ICONS[:power] + ' Power:'.ljust(11) +
|
73
|
+
"#{amdgpu_service.profile_mode} profile in " \
|
74
|
+
"#{amdgpu_service.power_dpm_state} mode using " \
|
75
|
+
"#{amdgpu_service.power_draw} / #{amdgpu_service.power_max} Watts "\
|
76
|
+
"(#{amdgpu_service.power_draw_percent}%)"
|
77
|
+
puts ICONS[:load] + ' Load:'.ljust(11) + percent_meter(amdgpu_service.busy_percent, 12)
|
71
78
|
end
|
72
79
|
|
73
80
|
desc 'version', 'Print the application version.'
|
@@ -76,7 +83,7 @@ module AmdgpuFan
|
|
76
83
|
end
|
77
84
|
|
78
85
|
desc 'watch [SECONDS]', 'Watch fan speed, load, power, and temperature ' \
|
79
|
-
|
86
|
+
'refreshed every n seconds.'
|
80
87
|
def watch(seconds = 1)
|
81
88
|
return puts 'Seconds must be from 1 to 600' unless (1..600).cover?(seconds.to_i)
|
82
89
|
|
@@ -120,21 +127,21 @@ module AmdgpuFan
|
|
120
127
|
watcher.measure
|
121
128
|
5.times { print "\033[K\033[A" } # move up a line and clear to end of line
|
122
129
|
|
123
|
-
puts ICONS[:clock]
|
124
|
-
ICONS[:memory]
|
125
|
-
ICONS[:fan]
|
126
|
-
ICONS[:power]
|
127
|
-
ICONS[:temp]
|
130
|
+
puts "#{ICONS[:clock]} Core clock #{watcher.core_clock}",
|
131
|
+
"#{ICONS[:memory]} Memory clk #{watcher.memory_clock}",
|
132
|
+
"#{ICONS[:fan]} Fan speed #{watcher.fan_speed_rpm}",
|
133
|
+
"#{ICONS[:power]} Power usage #{watcher.power_draw}",
|
134
|
+
"#{ICONS[:temp]} Temperature #{watcher.temperature}"
|
128
135
|
sleep 1
|
129
136
|
end
|
130
137
|
end
|
131
138
|
|
132
139
|
desc 'watch_csv [SECONDS]', 'Watch stats in CSV format ' \
|
133
|
-
|
140
|
+
'refreshed every n seconds defaulting to 1 second.'
|
134
141
|
def watch_csv(seconds = 1)
|
135
142
|
return puts 'Seconds must be from 1 to 600' unless (1..600).cover?(seconds.to_i)
|
136
143
|
|
137
|
-
puts 'Timestamp,
|
144
|
+
puts 'Timestamp,Core Clock (Mhz),Memory Clock (Mhz),Fan speed (rpm),'\
|
138
145
|
'Load (%),Power (Watts),Temp (°C)'
|
139
146
|
|
140
147
|
trap 'SIGINT' do
|
@@ -142,13 +149,19 @@ module AmdgpuFan
|
|
142
149
|
end
|
143
150
|
|
144
151
|
loop do
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
+
list = []
|
153
|
+
threads = [
|
154
|
+
Thread.new { list[0] = amdgpu_service.core_clock },
|
155
|
+
Thread.new { list[1] = amdgpu_service.memory_clock },
|
156
|
+
Thread.new { list[2] = amdgpu_service.fan_speed_rpm },
|
157
|
+
Thread.new { list[3] = amdgpu_service.busy_percent },
|
158
|
+
Thread.new { list[4] = amdgpu_service.power_draw },
|
159
|
+
Thread.new { list[5] = amdgpu_service.temperature }
|
160
|
+
]
|
161
|
+
threads.each(&:join)
|
162
|
+
|
163
|
+
puts [Time.now.strftime('%F %T'), *list].join(',')
|
164
|
+
|
152
165
|
sleep seconds.to_i
|
153
166
|
end
|
154
167
|
end
|
@@ -165,7 +178,7 @@ module AmdgpuFan
|
|
165
178
|
|
166
179
|
def fan_status
|
167
180
|
"#{amdgpu_service.fan_mode} mode running at " \
|
168
|
-
|
181
|
+
"#{amdgpu_service.fan_speed_rpm} rpm (#{amdgpu_service.fan_speed_percent}%)"
|
169
182
|
end
|
170
183
|
|
171
184
|
def mem_total_mibibyes
|
@@ -177,8 +190,8 @@ module AmdgpuFan
|
|
177
190
|
end
|
178
191
|
|
179
192
|
def summary_clock
|
180
|
-
"Core: #{amdgpu_service.core_clock.rjust(7)}#{WATCH_FIELD_SEPARATOR}"\
|
181
|
-
"Memory: #{amdgpu_service.memory_clock.rjust(7)}"
|
193
|
+
"Core: #{amdgpu_service.core_clock.to_s.rjust(7)}#{WATCH_FIELD_SEPARATOR}"\
|
194
|
+
"Memory: #{amdgpu_service.memory_clock.to_s.rjust(7)}"
|
182
195
|
end
|
183
196
|
|
184
197
|
def summary_fan
|
@@ -201,3 +214,5 @@ module AmdgpuFan
|
|
201
214
|
end
|
202
215
|
end
|
203
216
|
end
|
217
|
+
|
218
|
+
# rubocop:enable Metrics/AbcSize, Metrics/ClassLength, Metrics/MethodLength
|
data/lib/amdgpu_fan/connector.rb
CHANGED
@@ -11,7 +11,6 @@ module AmdgpuFan
|
|
11
11
|
index_range: (54..125)
|
12
12
|
}.freeze
|
13
13
|
|
14
|
-
|
15
14
|
attr_reader :card_num, :dir_path, :index, :type
|
16
15
|
|
17
16
|
class << self
|
@@ -19,9 +18,9 @@ module AmdgpuFan
|
|
19
18
|
# Return an array of connector objects for the provided card number.
|
20
19
|
# The files are sorted to improve how they are displayed to the user.
|
21
20
|
def where(card_num:)
|
22
|
-
Dir["/sys/class/drm/card#{card_num}/card#{card_num}-*"].
|
23
|
-
Connector.new card_num
|
24
|
-
dir_path
|
21
|
+
Dir["/sys/class/drm/card#{card_num}/card#{card_num}-*"].map do |dir_path|
|
22
|
+
Connector.new card_num:,
|
23
|
+
dir_path:,
|
25
24
|
index: dir_path[-1],
|
26
25
|
type: dir_path.slice(/(?<=card#{card_num}-)[A-z]+/)
|
27
26
|
end
|
@@ -3,19 +3,35 @@
|
|
3
3
|
module AmdgpuFan
|
4
4
|
# A mixin to help with CLI output formatting
|
5
5
|
module CliOutputFormat
|
6
|
-
|
6
|
+
METER_CHARS = [' ', *("\u2588".."\u258F").to_a.reverse].freeze
|
7
7
|
TIME_FORMAT = '%F %T'
|
8
8
|
|
9
|
-
private
|
10
|
-
|
11
9
|
def current_time
|
12
10
|
Time.now.strftime(TIME_FORMAT)
|
13
11
|
end
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
##
|
14
|
+
# Return a string with meter and percentage for +percent+
|
15
|
+
#
|
16
|
+
def percent_meter(percent, width = 3)
|
17
|
+
meter_char_indexes = []
|
18
|
+
percent_portion_size = 100.0 / width
|
19
|
+
width.times do |i|
|
20
|
+
current_portion = percent.to_i - (percent_portion_size * i)
|
21
|
+
|
22
|
+
current_portion_percent = if current_portion >= percent_portion_size
|
23
|
+
1
|
24
|
+
elsif current_portion <= 0
|
25
|
+
0
|
26
|
+
else
|
27
|
+
current_portion / percent_portion_size
|
28
|
+
end
|
29
|
+
|
30
|
+
meter_char_indexes << ((METER_CHARS.length - 1) * current_portion_percent.to_f).round
|
31
|
+
end
|
32
|
+
|
33
|
+
percent_string = "#{format '%<num>0.2i', num: percent}%".ljust(4)
|
34
|
+
"#{percent_string}[#{meter_char_indexes.map { |i| METER_CHARS[i] }.join}]"
|
19
35
|
end
|
20
36
|
|
21
37
|
def radeon_logo
|
data/lib/amdgpu_fan/mixin/fan.rb
CHANGED
@@ -4,7 +4,6 @@ module AmdgpuFan
|
|
4
4
|
##
|
5
5
|
# A mixin to read fan details and validate input
|
6
6
|
module Fan
|
7
|
-
|
8
7
|
private
|
9
8
|
|
10
9
|
def fan_file(type)
|
@@ -37,7 +36,7 @@ module AmdgpuFan
|
|
37
36
|
end
|
38
37
|
|
39
38
|
def valid_fan_percent_speed?(percent)
|
40
|
-
(1..100.to_i).cover?(percent.to_i)
|
39
|
+
(1..(100.to_i)).cover?(percent.to_i)
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
@@ -3,11 +3,10 @@
|
|
3
3
|
module AmdgpuFan
|
4
4
|
# A mixin to help with writing to system files
|
5
5
|
module SysWrite
|
6
|
-
|
7
6
|
private
|
8
7
|
|
9
8
|
##
|
10
|
-
# Write to a system file with elevated priviledges.
|
9
|
+
# Write to a system file with elevated priviledges.
|
11
10
|
def sudo_write(file_path, value)
|
12
11
|
`echo "#{value}" | sudo tee #{file_path}`
|
13
12
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
4
|
+
|
5
|
+
require 'net/http'
|
6
|
+
|
7
|
+
module AmdgpuFan
|
8
|
+
## PCI
|
9
|
+
#
|
10
|
+
# Retrieve device information from PCI IDs.
|
11
|
+
# https://pci-ids.ucw.cz/
|
12
|
+
#
|
13
|
+
class PCI
|
14
|
+
TMP_FILE = '/tmp/pci.ids.txt'
|
15
|
+
URL = 'https://pci-ids.ucw.cz/v2.2/pci.ids'
|
16
|
+
|
17
|
+
##
|
18
|
+
# Return the device name if available
|
19
|
+
#
|
20
|
+
def self.device_name(vendor_id, device_id, subdevice_id)
|
21
|
+
device = info.dig vendor_id, :devices, device_id
|
22
|
+
|
23
|
+
device.dig(subdevice_id, :name) || device[:name]
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.vendor_name(vendor_id)
|
27
|
+
info.dig vendor_id, :name
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.info
|
31
|
+
current_vendor_id = nil
|
32
|
+
current_device_id = nil
|
33
|
+
|
34
|
+
@info = raw.each_line.with_object({}) do |line, hash|
|
35
|
+
next if line.empty? || line.start_with?('#')
|
36
|
+
|
37
|
+
if line[0] =~ /(\d|[a-z])/
|
38
|
+
# Vendor line
|
39
|
+
current_vendor_id = line.split(' ').first.to_i(16)
|
40
|
+
vendor_name = line.split(' ').last.strip
|
41
|
+
hash[current_vendor_id] = { name: vendor_name, devices: {} }
|
42
|
+
elsif line[0..1] =~ /\t\w/
|
43
|
+
# Device line
|
44
|
+
current_device_id = line.split(' ').first.to_i(16)
|
45
|
+
device_name = line.split(' ').last.strip
|
46
|
+
hash[current_vendor_id][:devices][current_device_id] = { name: device_name }
|
47
|
+
elsif line[0..2] =~ /\t\t\w/
|
48
|
+
# Subvendor line
|
49
|
+
# subvendor_id = line.split(' ').first.to_i(16)
|
50
|
+
subdevice_id = line.split[1].to_i(16)
|
51
|
+
subdevice_name = line.split(' ')[1].strip
|
52
|
+
hash[current_vendor_id][:devices][current_device_id][subdevice_id] =
|
53
|
+
{ name: subdevice_name }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.raw
|
59
|
+
File.write(TMP_FILE, Net::HTTP.get(URI(URL))) unless File.exist?(TMP_FILE)
|
60
|
+
|
61
|
+
@raw ||= File.read(TMP_FILE)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
data/lib/amdgpu_fan/service.rb
CHANGED
@@ -4,6 +4,7 @@ require_relative 'mixin/fan'
|
|
4
4
|
require_relative 'mixin/sys_write'
|
5
5
|
|
6
6
|
require_relative 'connector'
|
7
|
+
require_relative 'pci'
|
7
8
|
|
8
9
|
module AmdgpuFan
|
9
10
|
## AmdgpuService
|
@@ -30,7 +31,7 @@ module AmdgpuFan
|
|
30
31
|
end
|
31
32
|
|
32
33
|
def connectors
|
33
|
-
@connectors ||= Connector.where card_num:
|
34
|
+
@connectors ||= Connector.where card_num:
|
34
35
|
end
|
35
36
|
|
36
37
|
def core_clock
|
@@ -45,10 +46,16 @@ module AmdgpuFan
|
|
45
46
|
FAN_MODES[File.read(fan_mode_file).strip] || 'unknown'
|
46
47
|
end
|
47
48
|
|
49
|
+
##
|
50
|
+
# Set the fan mode to auto or manual.
|
51
|
+
#
|
48
52
|
def fan_mode=(mode)
|
49
53
|
sudo_write fan_mode_file, FAN_MODES.key(mode.to_s)
|
50
54
|
end
|
51
55
|
|
56
|
+
##
|
57
|
+
# Set the fan speed to a percentage if <= 100 or a raw value
|
58
|
+
#
|
52
59
|
def fan_speed=(value)
|
53
60
|
if valid_fan_percent_speed?(value)
|
54
61
|
new_raw = (value.to_f / 100 * fan_raw_speeds(:max).to_i).round
|
@@ -67,20 +74,37 @@ module AmdgpuFan
|
|
67
74
|
(fan_speed_raw.to_f / fan_raw_speeds(:max).to_i * 100).round
|
68
75
|
end
|
69
76
|
|
77
|
+
##
|
78
|
+
# Return the fan speed in revolutions per minute
|
79
|
+
#
|
70
80
|
def fan_speed_rpm
|
71
|
-
File.read(fan_file(:input)).strip
|
81
|
+
File.read(fan_file(:input)).strip.to_i
|
72
82
|
end
|
73
83
|
|
84
|
+
##
|
85
|
+
# Return the current memory clock speed.
|
86
|
+
#
|
74
87
|
def memory_clock
|
75
88
|
clock_from_pp_file "#{base_card_dir}/pp_dpm_mclk"
|
76
89
|
end
|
77
90
|
|
91
|
+
##
|
92
|
+
# Return the total memory on the card in bytes
|
93
|
+
#
|
78
94
|
def memory_total
|
79
95
|
File.read("#{base_card_dir}/mem_info_vram_total").to_i
|
80
96
|
end
|
81
97
|
|
98
|
+
def model_id
|
99
|
+
@model_id ||= File.read(File.join(base_card_dir, '/subsystem_device')).gsub(/\A0x/, '').upcase
|
100
|
+
end
|
101
|
+
|
82
102
|
def name
|
83
|
-
|
103
|
+
return 'Unknown' unless PCI.vendor_name(vendor_id)
|
104
|
+
|
105
|
+
[PCI.vendor_name(vendor_id),
|
106
|
+
PCI.device_name(vendor_id, device_id, subdevice_id) || 'unknown']
|
107
|
+
.join(' ')
|
84
108
|
end
|
85
109
|
|
86
110
|
def power_dpm_state
|
@@ -135,15 +159,11 @@ module AmdgpuFan
|
|
135
159
|
end
|
136
160
|
|
137
161
|
def clock_from_pp_file(file)
|
138
|
-
File.read(file).slice(/\w+(?= \*)/)
|
139
|
-
end
|
140
|
-
|
141
|
-
def gpu_pci_id
|
142
|
-
@gpu_pci_id ||= `lspci -v | grep VGA`.split(' ').first
|
162
|
+
File.read(file).slice(/\w+(?= \*)/).to_i
|
143
163
|
end
|
144
164
|
|
145
|
-
def
|
146
|
-
@
|
165
|
+
def device_id
|
166
|
+
@device_id ||= File.read(File.join(base_card_dir, 'device')).to_i(16)
|
147
167
|
end
|
148
168
|
|
149
169
|
def power_avg_file
|
@@ -154,8 +174,16 @@ module AmdgpuFan
|
|
154
174
|
(raw_string.strip.to_f / 1_000_000).round(2)
|
155
175
|
end
|
156
176
|
|
177
|
+
def subdevice_id
|
178
|
+
@subdevice_id ||= File.read(File.join(base_card_dir, 'subsystem_device')).to_i(16)
|
179
|
+
end
|
180
|
+
|
157
181
|
def temperature_file
|
158
182
|
@temperature_file ||= Dir.glob("#{base_card_dir}/**/temp1_input").first
|
159
183
|
end
|
184
|
+
|
185
|
+
def vendor_id
|
186
|
+
@vendor_id ||= File.read(File.join(base_card_dir, 'vendor')).to_i(16)
|
187
|
+
end
|
160
188
|
end
|
161
189
|
end
|
data/lib/amdgpu_fan/stat_set.rb
CHANGED
@@ -7,18 +7,19 @@ module AmdgpuFan
|
|
7
7
|
attr_reader :unit
|
8
8
|
|
9
9
|
def initialize(unit)
|
10
|
+
super
|
10
11
|
@unit = unit
|
11
12
|
end
|
12
13
|
|
13
14
|
def stats
|
14
|
-
{ min
|
15
|
+
{ min:, avg:, max:, now: }
|
15
16
|
end
|
16
17
|
|
17
18
|
##
|
18
19
|
# Return a string containing all the stats with units.
|
19
20
|
#
|
20
21
|
def to_s
|
21
|
-
stats.map { |k,v| "#{k}: #{v.to_s.rjust(6)} #{unit.ljust(3)} " }.join
|
22
|
+
stats.map { |k, v| "#{k}: #{v.to_s.rjust(6)} #{unit.ljust(3)} " }.join
|
22
23
|
end
|
23
24
|
end
|
24
25
|
end
|
data/lib/amdgpu_fan/version.rb
CHANGED
data/lib/amdgpu_fan/watcher.rb
CHANGED
@@ -1,21 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'async'
|
4
|
+
|
3
5
|
require_relative 'stat_set'
|
4
6
|
|
5
7
|
module AmdgpuFan
|
6
8
|
# Keep track of stats over time.
|
7
9
|
class Watcher
|
8
|
-
attr_reader :core_clock, :
|
10
|
+
attr_reader :core_clock, :fan_speed_rpm, :num_measurements, :memory_clock, :power_draw,
|
11
|
+
:temperature
|
9
12
|
|
10
13
|
def initialize(amdgpu_service)
|
11
14
|
@amdgpu_service = amdgpu_service
|
12
15
|
@num_measurements = 0
|
13
16
|
|
14
17
|
@core_clock = StatSet.new 'MHz'
|
15
|
-
@
|
16
|
-
@
|
17
|
-
@
|
18
|
-
@
|
18
|
+
@memory_clock = StatSet.new 'MHz'
|
19
|
+
@fan_speed_rpm = StatSet.new 'RPM'
|
20
|
+
@power_draw = StatSet.new 'W'
|
21
|
+
@temperature = StatSet.new '°C'
|
19
22
|
end
|
20
23
|
|
21
24
|
##
|
@@ -24,19 +27,20 @@ module AmdgpuFan
|
|
24
27
|
def measure
|
25
28
|
@num_measurements += 1
|
26
29
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
calculate_stats(stat_set)
|
30
|
+
Async do |task|
|
31
|
+
%i[core_clock fan_speed_rpm memory_clock power_draw temperature].each do |stat|
|
32
|
+
task.async do
|
33
|
+
send(stat).now = amdgpu_service.send(stat)
|
34
|
+
calculate_stats(send(stat))
|
35
|
+
end
|
36
|
+
end
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
38
40
|
private
|
39
41
|
|
42
|
+
attr_reader :amdgpu_service
|
43
|
+
|
40
44
|
def calculate_stats(stat_set)
|
41
45
|
if num_measurements == 1
|
42
46
|
stat_set.min = stat_set.now
|
@@ -47,8 +51,8 @@ module AmdgpuFan
|
|
47
51
|
|
48
52
|
stat_set.min = stat_set.now if stat_set.now < stat_set.min
|
49
53
|
stat_set.avg =
|
50
|
-
|
51
|
-
|
54
|
+
((stat_set.now + (stat_set.avg * (num_measurements - 1))) / num_measurements.to_f)
|
55
|
+
.round(1)
|
52
56
|
stat_set.max = stat_set.now if stat_set.now > stat_set.max
|
53
57
|
end
|
54
58
|
end
|
metadata
CHANGED
@@ -1,57 +1,99 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amdgpu_fan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin McCormack
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: async
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: thor
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
16
30
|
requirements:
|
17
31
|
- - "~>"
|
18
32
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
33
|
+
version: '1.2'
|
20
34
|
type: :runtime
|
21
35
|
prerelease: false
|
22
36
|
version_requirements: !ruby/object:Gem::Requirement
|
23
37
|
requirements:
|
24
38
|
- - "~>"
|
25
39
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
40
|
+
version: '1.2'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: pry
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
|
-
- - "
|
45
|
+
- - "~>"
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
47
|
+
version: '0.14'
|
34
48
|
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
|
-
- - "
|
52
|
+
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
54
|
+
version: '0.14'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rspec
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
|
-
- - "
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.10'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.10'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
46
74
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
75
|
+
version: '1.24'
|
48
76
|
type: :development
|
49
77
|
prerelease: false
|
50
78
|
version_requirements: !ruby/object:Gem::Requirement
|
51
79
|
requirements:
|
52
|
-
- - "
|
80
|
+
- - "~>"
|
53
81
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
82
|
+
version: '1.24'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop-rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.7'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.7'
|
55
97
|
description: A CLI for interacting with the amdgpu Linux driver
|
56
98
|
email: harlemsquirrel@gmail.com
|
57
99
|
executables:
|
@@ -69,6 +111,7 @@ files:
|
|
69
111
|
- lib/amdgpu_fan/mixin/cli_output_format.rb
|
70
112
|
- lib/amdgpu_fan/mixin/fan.rb
|
71
113
|
- lib/amdgpu_fan/mixin/sys_write.rb
|
114
|
+
- lib/amdgpu_fan/pci.rb
|
72
115
|
- lib/amdgpu_fan/service.rb
|
73
116
|
- lib/amdgpu_fan/stat_set.rb
|
74
117
|
- lib/amdgpu_fan/version.rb
|
@@ -76,8 +119,9 @@ files:
|
|
76
119
|
homepage: https://github.com/HarlemSquirrel/amdgpu-fan-rb
|
77
120
|
licenses:
|
78
121
|
- MIT
|
79
|
-
metadata:
|
80
|
-
|
122
|
+
metadata:
|
123
|
+
rubygems_mfa_required: 'true'
|
124
|
+
post_install_message:
|
81
125
|
rdoc_options: []
|
82
126
|
require_paths:
|
83
127
|
- lib
|
@@ -85,15 +129,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
129
|
requirements:
|
86
130
|
- - ">="
|
87
131
|
- !ruby/object:Gem::Version
|
88
|
-
version:
|
132
|
+
version: 3.1.0
|
89
133
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
134
|
requirements:
|
91
135
|
- - ">="
|
92
136
|
- !ruby/object:Gem::Version
|
93
137
|
version: '0'
|
94
138
|
requirements: []
|
95
|
-
rubygems_version: 3.
|
96
|
-
signing_key:
|
139
|
+
rubygems_version: 3.3.7
|
140
|
+
signing_key:
|
97
141
|
specification_version: 4
|
98
142
|
summary: A CLI to view and set fan speeds for AMD graphics cards running on the open
|
99
143
|
source amdgpu Linux driver
|