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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d8bd1ed519a47f577ba017c94f03ac02101767434796821120aef3f9e12d9ba9
4
- data.tar.gz: 6d55c0d1c45d076d1409318332fade5d9038c8f4e64b86d8af2cb2d5eeb016df
3
+ metadata.gz: f831dbba03b1f54f0ed55055eea94371b658b4e797dae7899f3954b55e755a28
4
+ data.tar.gz: 9fa6dd181fbcae74b6441fe9a62200fb2be98be59c88d470a434c2b2730ea691
5
5
  SHA512:
6
- metadata.gz: dba9441882e19a730fe7863ac49ac196d6ac6b6ed4f55a1f086d2467c122cb58b7e57fb3dc27d0bfbddcaba9344a89992b59fce9c1f52edb44feb54e9a718b97
7
- data.tar.gz: 75b810c93258bbb39b2973f97e029cd602d70a61314da9e08af1a13fcaea5ec2ea7067e424aa0a3358d5a9b1863937cefa3a095897214f6ca8f0453757fd5250
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 help
31
+ bin/amdgpu_fan
32
32
  Commands:
33
- amdgpu_fan auto # Set mode to automatic (requires sudo)
34
- amdgpu_fan help [COMMAND] # Describe available commands or one specific command
35
- amdgpu_fan set PERCENTAGE # Set fan speed to PERCENTAGE (requires sudo)
36
- amdgpu_fan status # View device info, current fan speed, and temperature
37
- amdgpu_fan watch [SECONDS] # Watch current fan speed, and temperature refreshed every n seconds
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-10 20:36:01 - Clock: 512Mhz Core, 500Mhz Memory, Fan: 1838 rpm [||| ]27%, Load: [||| ]28%, Power: 15.12 W, Temp: 28.0°C
50
- 2019-05-10 20:36:05 - Clock: 300Mhz Core, 500Mhz Memory, Fan: 1837 rpm [||||| ]49%, Load: [ ]0%, Power: 16.18 W, Temp: 29.0°C
51
- 2019-05-10 20:36:09 - Clock: 512Mhz Core, 500Mhz Memory, Fan: 1837 rpm [||||| ]49%, Load: [ ]0%, Power: 15.11 W, Temp: 28.0°C
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
  ```
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thor'
2
4
 
3
5
  require_relative '../lib/amdgpu_service'
@@ -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.set_fan_mode! :auto
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 "Invalid percentage" unless (0..100).cover?(percentage.to_i)
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
- "📺\tGPU: #{amdgpu_service.name}",
35
- "📄\tvBIOS: #{amdgpu_service.vbios_version}",
36
- clock_status,
37
- fan_status,
38
- "🌡\tTemp: #{amdgpu_service.temperature}°C",
39
- "⚡\tPower: #{amdgpu_service.power_dpm_state} mode using " \
40
- "#{amdgpu_service.power_draw} / #{amdgpu_service.power_max} Watts",
41
- "⚖\tLoad: #{percent_meter amdgpu_service.busy_percent, 20}"
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 "Seconds must be from 1 to 600" unless (1..600).cover?(seconds.to_i)
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 "SIGINT" do
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
- puts "#{Time.now.strftime("%F %T")} - " \
59
- "Clock: #{amdgpu_service.core_clock} Core, #{amdgpu_service.memory_clock} Memory,\t" \
60
- "Fan: #{amdgpu_service.fan_speed_rpm} rpm #{percent_meter amdgpu_service.fan_speed_percent},\t" \
61
- "Load: #{percent_meter amdgpu_service.busy_percent},\t" \
62
- "Power: #{amdgpu_service.power_draw} W,\t" \
63
- "Temp: #{amdgpu_service.temperature}°C "
64
- sleep seconds.to_i
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 "Seconds must be from 1 to 600" unless (1..600).cover?(seconds.to_i)
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 "SIGINT" do
99
+ trap 'SIGINT' do
77
100
  exit 0
78
101
  end
79
102
 
80
103
  loop do
81
- puts [Time.now.strftime("%F %T"),
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
- "⏰\tClocks: #{amdgpu_service.core_clock} Core, " \
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("%F %T")
126
+ Time.now.strftime('%F %T')
105
127
  end
106
128
 
107
129
  def fan_status
108
- "🌀\tFan: #{amdgpu_service.fan_mode} mode running at " \
109
- "#{amdgpu_service.fan_speed_percent}% ~ #{amdgpu_service.fan_speed_rpm} rpm"
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
- "[#{'|' * progress_bar_count}#{' ' * (length - progress_bar_count)}]#{percent}%"
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
@@ -27,14 +27,14 @@ class AmdgpuService
27
27
  end
28
28
 
29
29
  def core_clock
30
- clock_from_pp_file "/sys/class/drm/card#{card_num}/device/pp_dpm_sclk"
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 set_fan_mode!(mode)
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 "/sys/class/drm/card#{card_num}/device/pp_dpm_mclk"
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
- set_fan_mode!(:manual) unless fan_mode == 'manual'
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 /\w+(?= \*)/
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).include?(raw.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).include?(percent.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.3.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-01-14 00:00:00.000000000 Z
11
+ date: 2019-11-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: A CLI for amdgpu fans
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.3
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