amdgpu_fan 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Build Status](https://travis-ci.org/HarlemSquirrel/amdgpu-fan-rb.svg?branch=master)](https://travis-ci.org/HarlemSquirrel/amdgpu-fan-rb)
|
3
|
+
[![Build Status](https://travis-ci.org/HarlemSquirrel/amdgpu-fan-rb.svg?branch=master)](https://travis-ci.org/HarlemSquirrel/amdgpu-fan-rb) [![Maintainability](https://api.codeclimate.com/v1/badges/27233cee17ef6a2c14fd/maintainability)](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
|