amdgpu_fan 0.3.0 → 0.4.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 +4 -4
- data/README.md +22 -10
- data/config/environment.rb +2 -0
- data/lib/amdgpu_fan_cli.rb +81 -34
- data/lib/amdgpu_service.rb +28 -7
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f831dbba03b1f54f0ed55055eea94371b658b4e797dae7899f3954b55e755a28
|
|
4
|
+
data.tar.gz: 9fa6dd181fbcae74b6441fe9a62200fb2be98be59c88d470a434c2b2730ea691
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 92a2ab4778b838e1bbbe6607c8bb2ad4a5d9ec79f817f24fa03d5af460e73a857e2dd456b3fd0ca08ab58cc4a64924a981afd4a44c05be65dad449b65f56c1e9
|
|
7
|
+
data.tar.gz: 4b4d0cd42f4a0275e09230799c22c90eecf556a0adfa2918d579f43419878a2100f2230cb19491468b59dc1496badc71bfd9f6332c6fddb3d7cc7480f4c00b97
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# amdgpu-fan-rb
|
|
2
2
|
|
|
3
|
-
[](https://travis-ci.org/HarlemSquirrel/amdgpu-fan-rb)
|
|
3
|
+
[](https://travis-ci.org/HarlemSquirrel/amdgpu-fan-rb) [](https://codeclimate.com/github/HarlemSquirrel/amdgpu-fan-rb/maintainability)
|
|
4
4
|
|
|
5
5
|
A Ruby CLI to read and set the fan speed for AMD Radeon graphics cards running on the AMDGPU Linux driver.
|
|
6
6
|
|
|
@@ -28,13 +28,18 @@ gem install amdgpu_fan
|
|
|
28
28
|
## Usage
|
|
29
29
|
|
|
30
30
|
```
|
|
31
|
-
➤ amdgpu_fan
|
|
31
|
+
➤ bin/amdgpu_fan
|
|
32
32
|
Commands:
|
|
33
|
-
amdgpu_fan auto
|
|
34
|
-
amdgpu_fan
|
|
35
|
-
amdgpu_fan
|
|
36
|
-
amdgpu_fan
|
|
37
|
-
amdgpu_fan
|
|
33
|
+
amdgpu_fan auto # Set fan mode to automatic (requires sudo)
|
|
34
|
+
amdgpu_fan connectors # View the status of the display connectors
|
|
35
|
+
amdgpu_fan help [COMMAND] # Describe available commands or one specific command
|
|
36
|
+
amdgpu_fan profile # View power profile details.
|
|
37
|
+
amdgpu_fan profile_auto # Set the power profile to automatic mode.
|
|
38
|
+
amdgpu_fan profile_force [PROFILE_NUM] # Manually set a power profile.
|
|
39
|
+
amdgpu_fan set PERCENTAGE # Set fan speed to PERCENTAGE (requires sudo)
|
|
40
|
+
amdgpu_fan status [--logo] # View device info, current fan speed, and temperature
|
|
41
|
+
amdgpu_fan watch [SECONDS] # Watch fan speed, load, power, and temperature refreshed every n seconds
|
|
42
|
+
amdgpu_fan watch_csv [SECONDS] # Watch stats in CSV format refreshed every n seconds defaulting to 1 second
|
|
38
43
|
|
|
39
44
|
➤ amdgpu_fan status
|
|
40
45
|
📺 GPU: AMD Radeon (TM) R9 Fury Series
|
|
@@ -46,9 +51,16 @@ Commands:
|
|
|
46
51
|
➤ bin/amdgpu_fan watch 3
|
|
47
52
|
Watching Advanced Micro Devices, Inc. [AMD/ATI] Radeon R9 FURY X / NANO every 3 second(s)...
|
|
48
53
|
<Press Ctrl-C to exit>
|
|
49
|
-
2019-05-
|
|
50
|
-
2019-05-
|
|
51
|
-
2019-05-
|
|
54
|
+
2019-05-28 20:57:41 | Core: 724Mhz | Memory: 500Mhz | Fan: 948 rpm [* ]14% | Load: [** ]24% | Power: 16.07 W [* ]6% | Temp: 34.0°C
|
|
55
|
+
2019-05-28 20:57:45 | Core: 512Mhz | Memory: 500Mhz | Fan: 948 rpm [* ]14% | Load: [ ]0% | Power: 16.13 W [* ]7% | Temp: 34.0°C
|
|
56
|
+
2019-05-28 20:57:49 | Core: 892Mhz | Memory: 500Mhz | Fan: 948 rpm [* ]14% | Load: [ ]0% | Power: 25.22 W [* ]5% | Temp: 33.0°C
|
|
57
|
+
2019-05-28 20:57:53 | Core: 300Mhz | Memory: 500Mhz | Fan: 948 rpm [* ]14% | Load: [ ]0% | Power: 19.1 W [* ]6% | Temp: 33.0°C
|
|
58
|
+
2019-05-28 20:57:57 | Core: 1050Mhz | Memory: 500Mhz | Fan: 948 rpm [* ]14% | Load: [********* ]94% | Power: 103.04 W [*** ]31% | Temp: 36.0°C
|
|
59
|
+
2019-05-28 20:58:01 | Core: 1050Mhz | Memory: 500Mhz | Fan: 954 rpm [** ]15% | Load: [********* ]91% | Power: 158.07 W [***** ]53% | Temp: 38.0°C
|
|
60
|
+
2019-05-28 20:58:05 | Core: 1050Mhz | Memory: 500Mhz | Fan: 977 rpm [** ]16% | Load: [**********]100% | Power: 218.01 W [******* ]73% | Temp: 40.0°C
|
|
61
|
+
2019-05-28 20:58:09 | Core: 1050Mhz | Memory: 500Mhz | Fan: 1005 rpm [** ]16% | Load: [**********]100% | Power: 216.24 W [******* ]71% | Temp: 40.0°C
|
|
62
|
+
2019-05-28 20:58:13 | Core: 1050Mhz | Memory: 500Mhz | Fan: 1033 rpm [** ]17% | Load: [**********]97% | Power: 109.25 W [**** ]39% | Temp: 38.0°C
|
|
63
|
+
2019-05-28 20:58:17 | Core: 724Mhz | Memory: 500Mhz | Fan: 1058 rpm [** ]17% | Load: [ ]0% | Power: 17.17 W [* ]6% | Temp: 35.0°C
|
|
52
64
|
^C
|
|
53
65
|
And now the watch is ended.
|
|
54
66
|
```
|
data/config/environment.rb
CHANGED
data/lib/amdgpu_fan_cli.rb
CHANGED
|
@@ -4,22 +4,42 @@ require_relative '../config/environment'
|
|
|
4
4
|
|
|
5
5
|
# The main class
|
|
6
6
|
class AmdgpuFanCli < Thor
|
|
7
|
+
METER_CHAR = '*'
|
|
8
|
+
WATCH_FIELD_SEPARATOR = ' | '
|
|
9
|
+
|
|
7
10
|
desc 'auto', 'Set fan mode to automatic (requires sudo)'
|
|
8
11
|
def auto
|
|
9
|
-
amdgpu_service.
|
|
12
|
+
amdgpu_service.fan_mode = :auto
|
|
10
13
|
puts fan_status
|
|
11
14
|
end
|
|
12
15
|
|
|
13
16
|
desc 'connectors', 'View the status of the display connectors'
|
|
14
17
|
def connectors
|
|
15
|
-
amdgpu_service.connectors_status.each do |connector,status|
|
|
18
|
+
amdgpu_service.connectors_status.each do |connector, status|
|
|
16
19
|
puts "#{connector}: #{status}"
|
|
17
20
|
end
|
|
18
21
|
end
|
|
19
22
|
|
|
23
|
+
desc 'profile', 'View power profile details.'
|
|
24
|
+
def profile
|
|
25
|
+
puts amdgpu_service.profile_summary
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
desc 'profile_auto', 'Set the power profile to automatic mode.'
|
|
29
|
+
def profile_auto
|
|
30
|
+
amdgpu_service.profile_auto
|
|
31
|
+
puts amdgpu_service.profile_summary
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
desc 'profile_force [PROFILE_NUM]', 'Manually set a power profile.'
|
|
35
|
+
def profile_force(state)
|
|
36
|
+
amdgpu_service.profile_force = state
|
|
37
|
+
puts amdgpu_service.profile_summary
|
|
38
|
+
end
|
|
39
|
+
|
|
20
40
|
desc 'set PERCENTAGE', 'Set fan speed to PERCENTAGE (requires sudo)'
|
|
21
41
|
def set(percentage)
|
|
22
|
-
return puts
|
|
42
|
+
return puts 'Invalid percentage' unless (0..100).cover?(percentage.to_i)
|
|
23
43
|
|
|
24
44
|
amdgpu_service.set_fan_manual_speed! percent: percentage
|
|
25
45
|
puts fan_status
|
|
@@ -28,57 +48,60 @@ class AmdgpuFanCli < Thor
|
|
|
28
48
|
exit 1
|
|
29
49
|
end
|
|
30
50
|
|
|
31
|
-
desc 'status', 'View device info, current fan speed, and temperature'
|
|
32
|
-
def status
|
|
33
|
-
puts radeon_logo
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
clock_status,
|
|
37
|
-
fan_status,
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"#{amdgpu_service.
|
|
41
|
-
|
|
51
|
+
desc 'status [--logo]', 'View device info, current fan speed, and temperature'
|
|
52
|
+
def status(option = nil)
|
|
53
|
+
puts radeon_logo if option == '--logo'
|
|
54
|
+
puts "📺 #{'GPU:'.ljust(7)} #{amdgpu_service.name}",
|
|
55
|
+
"📄 #{'vBIOS:'.ljust(7)} #{amdgpu_service.vbios_version}",
|
|
56
|
+
"⏰ #{'Clocks:'.ljust(7)} #{clock_status}",
|
|
57
|
+
"🌀 #{'Fan:'.ljust(7)} #{fan_status}",
|
|
58
|
+
"🌞 #{'Temp:'.ljust(7)} #{amdgpu_service.temperature}°C",
|
|
59
|
+
"⚡ #{'Power:'.ljust(7)} #{amdgpu_service.profile_mode} profile in " \
|
|
60
|
+
"#{amdgpu_service.power_dpm_state} mode using " \
|
|
61
|
+
"#{amdgpu_service.power_draw} / #{amdgpu_service.power_max} Watts "\
|
|
62
|
+
"(#{amdgpu_service.power_draw_percent}%)",
|
|
63
|
+
"⚖ #{'Load:'.ljust(7)} #{percent_meter amdgpu_service.busy_percent, 20}"
|
|
42
64
|
end
|
|
43
65
|
|
|
44
66
|
desc 'watch [SECONDS]', 'Watch fan speed, load, power, and temperature ' \
|
|
45
67
|
'refreshed every n seconds'
|
|
46
|
-
def watch(seconds=1)
|
|
47
|
-
return puts
|
|
68
|
+
def watch(seconds = 1)
|
|
69
|
+
return puts 'Seconds must be from 1 to 600' unless (1..600).cover?(seconds.to_i)
|
|
48
70
|
|
|
49
71
|
puts "Watching #{amdgpu_service.name} every #{seconds} second(s)...",
|
|
50
72
|
' <Press Ctrl-C to exit>'
|
|
51
73
|
|
|
52
|
-
trap
|
|
74
|
+
trap 'SIGINT' do
|
|
53
75
|
puts "\nAnd now the watch is ended."
|
|
54
76
|
exit 0
|
|
55
77
|
end
|
|
56
78
|
|
|
57
79
|
loop do
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
80
|
+
time = Time.now
|
|
81
|
+
puts [time.strftime('%F %T'), summary_clock, summary_fan, summary_load, summary_power,
|
|
82
|
+
summary_temp].join(WATCH_FIELD_SEPARATOR)
|
|
83
|
+
|
|
84
|
+
# It can take a second or two to run the above so we remove them from the wait
|
|
85
|
+
# here to get a more consistant watch interval.
|
|
86
|
+
sec_left_to_wait = time.to_i + seconds.to_i - Time.now.to_i
|
|
87
|
+
sleep sec_left_to_wait if sec_left_to_wait.positive?
|
|
65
88
|
end
|
|
66
89
|
end
|
|
67
90
|
|
|
68
91
|
desc 'watch_csv [SECONDS]', 'Watch stats in CSV format ' \
|
|
69
92
|
'refreshed every n seconds defaulting to 1 second'
|
|
70
|
-
def watch_csv(seconds=1)
|
|
71
|
-
return puts
|
|
93
|
+
def watch_csv(seconds = 1)
|
|
94
|
+
return puts 'Seconds must be from 1 to 600' unless (1..600).cover?(seconds.to_i)
|
|
72
95
|
|
|
73
96
|
puts 'Timestamp, Core Clock (Mhz),Memory Clock (Mhz),Fan speed (rpm), '\
|
|
74
97
|
'Load (%),Power (Watts),Temp (°C)'
|
|
75
98
|
|
|
76
|
-
trap
|
|
99
|
+
trap 'SIGINT' do
|
|
77
100
|
exit 0
|
|
78
101
|
end
|
|
79
102
|
|
|
80
103
|
loop do
|
|
81
|
-
puts [Time.now.strftime(
|
|
104
|
+
puts [Time.now.strftime('%F %T'),
|
|
82
105
|
amdgpu_service.core_clock,
|
|
83
106
|
amdgpu_service.memory_clock,
|
|
84
107
|
amdgpu_service.fan_speed_rpm,
|
|
@@ -96,25 +119,49 @@ class AmdgpuFanCli < Thor
|
|
|
96
119
|
end
|
|
97
120
|
|
|
98
121
|
def clock_status
|
|
99
|
-
"
|
|
100
|
-
"#{amdgpu_service.memory_clock} Memory"
|
|
122
|
+
"#{amdgpu_service.core_clock} Core, #{amdgpu_service.memory_clock} Memory"
|
|
101
123
|
end
|
|
102
124
|
|
|
103
125
|
def current_time
|
|
104
|
-
Time.now.strftime(
|
|
126
|
+
Time.now.strftime('%F %T')
|
|
105
127
|
end
|
|
106
128
|
|
|
107
129
|
def fan_status
|
|
108
|
-
"
|
|
109
|
-
"#{amdgpu_service.
|
|
130
|
+
"#{amdgpu_service.fan_mode} mode running at " \
|
|
131
|
+
"#{amdgpu_service.fan_speed_rpm} rpm (#{amdgpu_service.fan_speed_percent}%)"
|
|
110
132
|
end
|
|
111
133
|
|
|
112
134
|
def percent_meter(percent, length = 10)
|
|
113
135
|
progress_bar_count = (length * percent.to_f / 100).round
|
|
114
|
-
|
|
136
|
+
percent_string = "#{percent}%".ljust(4)
|
|
137
|
+
"[#{METER_CHAR * progress_bar_count}#{' ' * (length - progress_bar_count)}]#{percent_string}"
|
|
115
138
|
end
|
|
116
139
|
|
|
117
140
|
def radeon_logo
|
|
118
141
|
File.read(File.join(__dir__, '../lib/radeon_r_black_red_100x100.ascii'))
|
|
119
142
|
end
|
|
143
|
+
|
|
144
|
+
def summary_clock
|
|
145
|
+
"Core: #{amdgpu_service.core_clock.ljust(7)} #{WATCH_FIELD_SEPARATOR}"\
|
|
146
|
+
"Memory: #{amdgpu_service.memory_clock.ljust(7)}"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def summary_fan
|
|
150
|
+
fan_speed_string = "#{amdgpu_service.fan_speed_rpm} rpm".ljust(8)
|
|
151
|
+
"Fan: #{fan_speed_string} #{percent_meter(amdgpu_service.fan_speed_percent)}"
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def summary_load
|
|
155
|
+
"Load: #{percent_meter amdgpu_service.busy_percent}"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def summary_power
|
|
159
|
+
power_string = "#{amdgpu_service.power_draw} W".ljust(amdgpu_service.power_max.to_s.length + 3)
|
|
160
|
+
"Power: #{power_string} #{percent_meter amdgpu_service.power_draw_percent}"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def summary_temp
|
|
164
|
+
temp_string = "#{amdgpu_service.temperature}°C".ljust(7)
|
|
165
|
+
"Temp: #{temp_string}"
|
|
166
|
+
end
|
|
120
167
|
end
|
data/lib/amdgpu_service.rb
CHANGED
|
@@ -27,14 +27,14 @@ class AmdgpuService
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def core_clock
|
|
30
|
-
clock_from_pp_file "
|
|
30
|
+
clock_from_pp_file "#{base_card_folder}/pp_dpm_sclk"
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def fan_mode
|
|
34
34
|
FAN_MODES[File.read(fan_mode_file).strip] || 'unknown'
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
def
|
|
37
|
+
def fan_mode=(mode)
|
|
38
38
|
`echo "#{FAN_MODES.key(mode.to_s)}" | sudo tee #{fan_mode_file}`
|
|
39
39
|
end
|
|
40
40
|
|
|
@@ -51,7 +51,7 @@ class AmdgpuService
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def memory_clock
|
|
54
|
-
clock_from_pp_file "
|
|
54
|
+
clock_from_pp_file "#{base_card_folder}/pp_dpm_mclk"
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def name
|
|
@@ -66,10 +66,31 @@ class AmdgpuService
|
|
|
66
66
|
power_raw_to_watts File.read(power_avg_file)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
def power_draw_percent
|
|
70
|
+
(power_draw.to_f / power_max.to_i * 100).round
|
|
71
|
+
end
|
|
72
|
+
|
|
69
73
|
def power_max
|
|
70
74
|
@power_max ||= power_raw_to_watts File.read(power_max_file)
|
|
71
75
|
end
|
|
72
76
|
|
|
77
|
+
def profile_auto
|
|
78
|
+
`echo "auto" | sudo tee "#{base_card_folder}/power_dpm_force_performance_level"`
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def profile_force=(state)
|
|
82
|
+
`echo "manual" | sudo tee "#{base_card_folder}/power_dpm_force_performance_level"`
|
|
83
|
+
`echo "#{state}" | sudo tee "#{base_card_folder}/pp_power_profile_mode"`
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def profile_mode
|
|
87
|
+
File.read("#{base_card_folder}/pp_power_profile_mode").slice(/\w+ \*/).delete('*').strip
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def profile_summary
|
|
91
|
+
File.read("#{base_card_folder}/pp_power_profile_mode")
|
|
92
|
+
end
|
|
93
|
+
|
|
73
94
|
def set_fan_manual_speed!(percent: nil, raw: nil)
|
|
74
95
|
if valid_fan_percent_speed?(percent)
|
|
75
96
|
new_raw = (percent.to_f / 100 * fan_speed_raw_max.to_i).round
|
|
@@ -79,7 +100,7 @@ class AmdgpuService
|
|
|
79
100
|
|
|
80
101
|
raise(self.class::Error, 'Invalid fan speed provided') if new_raw.to_s.empty?
|
|
81
102
|
|
|
82
|
-
|
|
103
|
+
fan_mode = :manual unless fan_mode == 'manual'
|
|
83
104
|
|
|
84
105
|
`echo "#{new_raw}" | sudo tee #{fan_power_file}`
|
|
85
106
|
end
|
|
@@ -99,7 +120,7 @@ class AmdgpuService
|
|
|
99
120
|
end
|
|
100
121
|
|
|
101
122
|
def clock_from_pp_file(file)
|
|
102
|
-
File.read(file).slice
|
|
123
|
+
File.read(file).slice(/\w+(?= \*)/)
|
|
103
124
|
end
|
|
104
125
|
|
|
105
126
|
def connectors_files
|
|
@@ -147,10 +168,10 @@ class AmdgpuService
|
|
|
147
168
|
end
|
|
148
169
|
|
|
149
170
|
def valid_fan_raw_speed?(raw)
|
|
150
|
-
(1..fan_speed_raw_max.to_i).
|
|
171
|
+
(1..fan_speed_raw_max.to_i).cover?(raw.to_i)
|
|
151
172
|
end
|
|
152
173
|
|
|
153
174
|
def valid_fan_percent_speed?(percent)
|
|
154
|
-
(1..100.to_i).
|
|
175
|
+
(1..100.to_i).cover?(percent.to_i)
|
|
155
176
|
end
|
|
156
177
|
end
|
metadata
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: amdgpu_fan
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kevin McCormack
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-
|
|
11
|
+
date: 2019-11-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
|
-
description: A CLI for amdgpu
|
|
13
|
+
description: A CLI for interacting with the amdgpu Linux driver
|
|
14
14
|
email: harlemsquirrel@gmail.com
|
|
15
15
|
executables:
|
|
16
16
|
- amdgpu_fan
|
|
@@ -42,7 +42,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
42
42
|
- !ruby/object:Gem::Version
|
|
43
43
|
version: '0'
|
|
44
44
|
requirements: []
|
|
45
|
-
rubygems_version: 3.0.
|
|
45
|
+
rubygems_version: 3.0.6
|
|
46
46
|
signing_key:
|
|
47
47
|
specification_version: 4
|
|
48
48
|
summary: A CLI to view and set fan speeds for AMD graphics cards running on the open
|