amdgpu_fan 0.3.0 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d8bd1ed519a47f577ba017c94f03ac02101767434796821120aef3f9e12d9ba9
4
- data.tar.gz: 6d55c0d1c45d076d1409318332fade5d9038c8f4e64b86d8af2cb2d5eeb016df
3
+ metadata.gz: a499ce52639612b25843b04c3497c7c36f23f3a960d0946b7dc2e249e9a18874
4
+ data.tar.gz: fa87ca342988d97a91773b1272829a3b825b88dbd65420d6abd26fed8d97ac92
5
5
  SHA512:
6
- metadata.gz: dba9441882e19a730fe7863ac49ac196d6ac6b6ed4f55a1f086d2467c122cb58b7e57fb3dc27d0bfbddcaba9344a89992b59fce9c1f52edb44feb54e9a718b97
7
- data.tar.gz: 75b810c93258bbb39b2973f97e029cd602d70a61314da9e08af1a13fcaea5ec2ea7067e424aa0a3358d5a9b1863937cefa3a095897214f6ca8f0453757fd5250
6
+ metadata.gz: 06b3bd73191b39da57ac9c14e7ada8fa2cf1a069e8401f45af10eab6ede0bf79a5ebd2f80ba5c464e60f960e24d11783cf20d698c640a38e36c80846b305772e
7
+ data.tar.gz: 794e28fd6ae71a898b1e897a0fd612add4585e901ece8bc3928e62de9d8245107767848352fe7203d4aa5b6ec60c4e78b28523cc0c893d4d0bcb2f67fdd52044
data/README.md CHANGED
@@ -1,10 +1,17 @@
1
- # amdgpu-fan-rb
1
+ # amdgpu_fan
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
+ [![Gem Version](https://badge.fury.io/rb/amdgpu_fan.svg)](https://badge.fury.io/rb/amdgpu_fan)
4
+ [![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
5
 
5
- A Ruby CLI to read and set the fan speed for AMD Radeon graphics cards running on the AMDGPU Linux driver.
6
+ A Ruby CLI to read and set fan speed, power profiles, and more for AMD Radeon graphics cards running on the AMDGPU Linux driver.
6
7
 
7
- See https://wiki.archlinux.org/index.php/Fan_speed_control#AMDGPU_sysfs_fan_control
8
+ **amdgpu_fan** aims to provide a more user friendly interface on top of [sysfs](https://en.wikipedia.org/wiki/Sysfs) for displaying statistics and interacting with AMD Radeon graphics hardware running on the [AMDgpu](https://dri.freedesktop.org/docs/drm/gpu/amdgpu.html) driver.
9
+
10
+ #### Further reading
11
+
12
+ - https://wiki.archlinux.org/index.php/AMDGPU#Overclocking
13
+ - https://wiki.archlinux.org/index.php/Fan_speed_control#AMDGPU_sysfs_fan_control
14
+ - https://phoronix.com/scan.php?page=news_item&px=AMDGPU-Quick-WattMan-Cap-Test
8
15
 
9
16
  ## Installation
10
17
 
@@ -28,27 +35,56 @@ gem install amdgpu_fan
28
35
  ## Usage
29
36
 
30
37
  ```
31
- ➤ amdgpu_fan help
38
+ bin/amdgpu_fan help
32
39
  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
38
-
39
- amdgpu_fan status
40
- 📺 GPU: AMD Radeon (TM) R9 Fury Series
41
- 📄 vBIOS: 113-C8800100-102
42
- 🌀 Fan: auto mode running at 48% ~ 1828 rpm
43
- 🌡 Temp: 28.0°C
44
- ⚡ Power: 19.26 / 300.0 Watts
40
+ amdgpu_fan connectors # View the status of the display connectors.
41
+ amdgpu_fan fan # View fan details.
42
+ amdgpu_fan fan_set PERCENTAGE/AUTO # Set fan speed to percentage or automatic mode. (requires sudo)
43
+ amdgpu_fan help [COMMAND] # Describe available commands or one specific command
44
+ amdgpu_fan profile # View power profile details.
45
+ amdgpu_fan profile_auto # Set the power profile to automatic mode.
46
+ amdgpu_fan profile_force PROFILE_NUM # Manually set a power profile. (requires sudo)
47
+ amdgpu_fan status [--logo] # View device info, current fan speed, and temperature.
48
+ amdgpu_fan watch [SECONDS] # Watch fan speed, load, power, and temperature refreshed every n seconds.
49
+ amdgpu_fan watch_csv [SECONDS] # Watch stats in CSV format refreshed every n seconds defaulting to 1 second.
50
+
51
+ ➤ bin/amdgpu_fan status
52
+ 📺 GPU: Advanced Micro Devices, Inc. [AMD/ATI] Radeon R9 FURY X / NANO
53
+ 📄 vBIOS: 113-C8800100-102
54
+ ⏰ Clocks: 724Mhz Core, 500Mhz Memory
55
+ 💾 Memory: 4096 MiB
56
+ 🌀 Fan: auto mode running at 1809 rpm (48%)
57
+ 🌞 Temp: 21.0°C
58
+ ⚡ Power: 3D_FULL_SCREEN profile in performance mode using 16.2 / 300.0 Watts (5%)
59
+ ⚖ Load: [ ]0%
45
60
 
46
61
  ➤ bin/amdgpu_fan watch 3
47
62
  Watching Advanced Micro Devices, Inc. [AMD/ATI] Radeon R9 FURY X / NANO every 3 second(s)...
48
63
  <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
64
+ 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
65
+ 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
66
+ 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
67
+ 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
68
+ 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
69
+ 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
70
+ 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
71
+ 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
72
+ 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
73
+ 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
74
+ ^C
75
+ And now the watch is ended.
76
+ ```
77
+
78
+ ```
79
+ ➤ bin/amdgpu_fan watch_avg
80
+ Watching Sapphire Technology Limited Vega 10 XL/XT [Radeon RX Vega 56/64] min, max and averges since
81
+ 2020-06-02 23:05:20 -0400...
82
+ <Press Ctrl-C to exit>
83
+ ⏰ Core clock min: 852 MHz avg: 887.0 MHz max: 1200 MHz now: 852 MHz
84
+ 💾 Memory clk min: 167 MHz avg: 227.1 MHz max: 945 MHz now: 167 MHz
85
+ 🌀 Fan speed min: 1231 RPM avg: 1231.0 RPM max: 1231 RPM now: 1231 RPM
86
+ ⚡ Power usage min: 6.0 W avg: 21.8 W max: 141.0 W now: 6.0 W
87
+ 🌡 Temperature min: 30 °C avg: 31.3 °C max: 35 °C now: 32 °C
52
88
  ^C
53
89
  And now the watch is ended.
54
90
  ```
@@ -57,4 +93,12 @@ And now the watch is ended.
57
93
 
58
94
  - [Ruby](https://www.ruby-lang.org) with [Bundler](https://bundler.io)
59
95
  - [Thor](http://whatisthor.com/) (installed with `bundle install`)
60
- - [`lspci`](https://linux.die.net/man/8/lspci) (included with most Linux distributions)
96
+ - Internet connection - Device info is retrieved from https://pci-ids.ucw.cz/
97
+
98
+ ## Building a binary
99
+
100
+ [Ruby Packer](https://github.com/pmq20/ruby-packer) provides a convenient way to compile this into a single executable. For the best results, compile Ruby Packer from source from the lastest master branch.
101
+
102
+ ```sh
103
+ rubyc amdgpu_fan --output amdgpu_fan
104
+ ```
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative '../lib/amdgpu_fan_cli'
4
+ require_relative '../lib/amdgpu_fan'
5
5
 
6
- AmdgpuFanCli.start ARGV
6
+ AmdgpuFan::Cli.start ARGV
@@ -1,3 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thor'
2
4
 
3
- require_relative '../lib/amdgpu_service'
5
+ require_relative '../lib/amdgpu_fan'
6
+ require_relative '../lib/amdgpu_fan/version'
7
+
8
+ require_relative '../lib/amdgpu_fan/mixin/cli_output_format'
9
+ require_relative '../lib/amdgpu_fan/mixin/sys_write'
10
+
11
+ require_relative '../lib/amdgpu_fan/service'
12
+ require_relative '../lib/amdgpu_fan/cli'
13
+ require_relative '../lib/amdgpu_fan/pci'
14
+ require_relative '../lib/amdgpu_fan/stat_set'
15
+ require_relative '../lib/amdgpu_fan/watcher'
@@ -0,0 +1,10 @@
1
+ ---
2
+ clock: ⏰
3
+ display: 📺
4
+ fan: 🌀
5
+ gpu: 👾
6
+ load: "⚖ "
7
+ memory: 💾
8
+ power: ⚡
9
+ temp: "🌡 "
10
+ vbios: 📄
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../config/environment'
4
+
5
+ # The main module
6
+ module AmdgpuFan
7
+ end
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module AmdgpuFan
6
+ # The command-line interface class
7
+ class Cli < Thor
8
+ include CliOutputFormat
9
+
10
+ ICONS = YAML.safe_load(File.read(File.join(__dir__, '../../config/icons.yml')))
11
+ .transform_keys(&:to_sym).freeze
12
+ WATCH_FIELD_SEPARATOR = ' | '
13
+
14
+ desc 'connectors', 'View the status of the display connectors.'
15
+ def connectors
16
+ amdgpu_service.connectors.each do |connector|
17
+ puts "#{connector.type} #{connector.index}:\t" +
18
+ (connector.connected? ? connector.display_name : connector.status)
19
+ end
20
+ end
21
+
22
+ desc 'profile', 'View power profile details.'
23
+ def profile
24
+ puts amdgpu_service.profile_summary
25
+ end
26
+
27
+ desc 'profile_auto', 'Set the power profile to automatic mode.'
28
+ def profile_auto
29
+ amdgpu_service.profile_auto
30
+ puts amdgpu_service.profile_summary
31
+ end
32
+
33
+ desc 'profile_force PROFILE_NUM', 'Manually set a power profile. (requires sudo)'
34
+ def profile_force(state)
35
+ amdgpu_service.profile_force = state
36
+ puts amdgpu_service.profile_summary
37
+ end
38
+
39
+ desc 'fan', 'View fan details.'
40
+ def fan
41
+ puts fan_status
42
+ end
43
+
44
+ desc 'fan_set PERCENTAGE/AUTO', 'Set fan speed to percentage or automatic mode. (requires sudo)'
45
+ def fan_set(value)
46
+ if value.strip.casecmp('auto').zero?
47
+ amdgpu_service.fan_mode = :auto
48
+ else
49
+ return puts 'Invalid percentage' unless (0..100).cover?(value.to_i)
50
+
51
+ amdgpu_service.fan_speed = value
52
+ end
53
+ puts fan_status
54
+ end
55
+
56
+ desc 'status [--logo]', 'View device info, current fan speed, and temperature.'
57
+ def status(option = nil)
58
+ puts radeon_logo if option == '--logo'
59
+ puts ICONS[:gpu] + ' GPU:'.ljust(9) + amdgpu_service.name,
60
+ ICONS[:vbios] + ' vBIOS:'.ljust(9) + amdgpu_service.vbios_version,
61
+ ICONS[:display] + ' Displays:' + amdgpu_service.display_names.join(', '),
62
+ ICONS[:clock] + ' Clocks:'.ljust(9) + clock_status,
63
+ ICONS[:memory] + ' Memory:'.ljust(9) + mem_total_mibibyes,
64
+ ICONS[:fan] + ' Fan:'.ljust(9) + fan_status,
65
+ ICONS[:temp] + ' Temp:'.ljust(9) + "#{amdgpu_service.temperature}°C",
66
+ ICONS[:power] + ' Power:'.ljust(9) + "#{amdgpu_service.profile_mode} profile in " \
67
+ "#{amdgpu_service.power_dpm_state} mode using " \
68
+ "#{amdgpu_service.power_draw} / #{amdgpu_service.power_max} Watts "\
69
+ "(#{amdgpu_service.power_draw_percent}%)",
70
+ ICONS[:load] + ' Load:'.ljust(9) + percent_meter(amdgpu_service.busy_percent, 20)
71
+ end
72
+
73
+ desc 'version', 'Print the application version.'
74
+ def version
75
+ puts AmdgpuFan::VERSION
76
+ end
77
+
78
+ desc 'watch [SECONDS]', 'Watch fan speed, load, power, and temperature ' \
79
+ 'refreshed every n seconds.'
80
+ def watch(seconds = 1)
81
+ return puts 'Seconds must be from 1 to 600' unless (1..600).cover?(seconds.to_i)
82
+
83
+ puts "Watching #{amdgpu_service.name} every #{seconds} second(s)...",
84
+ ' <Press Ctrl-C to exit>'
85
+
86
+ trap 'SIGINT' do
87
+ puts "\nAnd now the watch is ended."
88
+ exit 0
89
+ end
90
+
91
+ loop do
92
+ time = Time.now
93
+ puts [time.strftime('%F %T'), summary_clock, summary_fan, summary_load, summary_power,
94
+ summary_temp].join(WATCH_FIELD_SEPARATOR)
95
+
96
+ # It can take a second or two to run the above so we remove them from the wait
97
+ # here to get a more consistant watch interval.
98
+ sec_left_to_wait = time.to_i + seconds.to_i - Time.now.to_i
99
+ sleep sec_left_to_wait if sec_left_to_wait.positive?
100
+ end
101
+ end
102
+
103
+ desc 'watch_avg',
104
+ <<~DOC
105
+ Watch min, max, average, and current stats.
106
+ DOC
107
+ def watch_avg
108
+ puts "Watching #{amdgpu_service.name} min, max and averges since #{Time.now}...",
109
+ ' <Press Ctrl-C to exit>',
110
+ "\n\n\n\n\n"
111
+
112
+ trap 'SIGINT' do
113
+ puts "\nAnd now the watch is ended."
114
+ exit 0
115
+ end
116
+
117
+ watcher = Watcher.new amdgpu_service
118
+
119
+ loop do
120
+ watcher.measure
121
+ 5.times { print "\033[K\033[A" } # move up a line and clear to end of line
122
+
123
+ puts ICONS[:clock] + ' Core clock ' + watcher.core_clock.to_s,
124
+ ICONS[:memory] + ' Memory clk ' + watcher.mem_clock.to_s,
125
+ ICONS[:fan] + ' Fan speed ' + watcher.fan_speed.to_s,
126
+ ICONS[:power] + ' Power usage ' + watcher.power.to_s,
127
+ ICONS[:temp] + ' Temperature ' + watcher.temp.to_s
128
+ sleep 1
129
+ end
130
+ end
131
+
132
+ desc 'watch_csv [SECONDS]', 'Watch stats in CSV format ' \
133
+ 'refreshed every n seconds defaulting to 1 second.'
134
+ def watch_csv(seconds = 1)
135
+ return puts 'Seconds must be from 1 to 600' unless (1..600).cover?(seconds.to_i)
136
+
137
+ puts 'Timestamp, Core Clock (Mhz),Memory Clock (Mhz),Fan speed (rpm), '\
138
+ 'Load (%),Power (Watts),Temp (°C)'
139
+
140
+ trap 'SIGINT' do
141
+ exit 0
142
+ end
143
+
144
+ loop do
145
+ puts [Time.now.strftime('%F %T'),
146
+ amdgpu_service.core_clock,
147
+ amdgpu_service.memory_clock,
148
+ amdgpu_service.fan_speed_rpm,
149
+ amdgpu_service.busy_percent,
150
+ amdgpu_service.power_draw,
151
+ amdgpu_service.temperature].join(',')
152
+ sleep seconds.to_i
153
+ end
154
+ end
155
+
156
+ private
157
+
158
+ def amdgpu_service
159
+ @amdgpu_service ||= AmdgpuFan::Service.new
160
+ end
161
+
162
+ def clock_status
163
+ "#{amdgpu_service.core_clock} Core, #{amdgpu_service.memory_clock} Memory"
164
+ end
165
+
166
+ def fan_status
167
+ "#{amdgpu_service.fan_mode} mode running at " \
168
+ "#{amdgpu_service.fan_speed_rpm} rpm (#{amdgpu_service.fan_speed_percent}%)"
169
+ end
170
+
171
+ def mem_total_mibibyes
172
+ "#{amdgpu_service.memory_total / (2**20)} MiB"
173
+ end
174
+
175
+ def power_max
176
+ format('%<num>0.2f', num: amdgpu_service.power_max)
177
+ end
178
+
179
+ def summary_clock
180
+ "Core: #{amdgpu_service.core_clock.rjust(7)}#{WATCH_FIELD_SEPARATOR}"\
181
+ "Memory: #{amdgpu_service.memory_clock.rjust(7)}"
182
+ end
183
+
184
+ def summary_fan
185
+ fan_speed_string = "#{amdgpu_service.fan_speed_rpm} rpm".rjust(8)
186
+ "Fan: #{fan_speed_string} #{percent_meter(amdgpu_service.fan_speed_percent)}"
187
+ end
188
+
189
+ def summary_load
190
+ "Load: #{percent_meter amdgpu_service.busy_percent}"
191
+ end
192
+
193
+ def summary_power
194
+ "Power: #{format('%<num>0.02f', num: amdgpu_service.power_draw).rjust(power_max.length)} W" \
195
+ " #{percent_meter amdgpu_service.power_draw_percent}"
196
+ end
197
+
198
+ def summary_temp
199
+ temp_string = "#{amdgpu_service.temperature}°C".rjust(7)
200
+ "Temp: #{temp_string}"
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AmdgpuFan
4
+ ## Connector
5
+ #
6
+ # A model class for a GPU connector
7
+ class Connector
8
+ EDID_DESCRIPTORS_CONF = {
9
+ display_name_leading_bytes: String.new('\x00\xFC\x00', encoding: 'ascii-8bit'),
10
+ unspecified_text_leading_bytes: String.new('\x00\xFE\x00', encoding: 'ascii-8bit'),
11
+ index_range: (54..125)
12
+ }.freeze
13
+
14
+ attr_reader :card_num, :dir_path, :index, :type
15
+
16
+ class << self
17
+ ##
18
+ # Return an array of connector objects for the provided card number.
19
+ # The files are sorted to improve how they are displayed to the user.
20
+ def where(card_num:)
21
+ Dir["/sys/class/drm/card#{card_num}/card#{card_num}-*"].sort.map do |dir_path|
22
+ Connector.new card_num: card_num,
23
+ dir_path: dir_path,
24
+ index: dir_path[-1],
25
+ type: dir_path.slice(/(?<=card#{card_num}-)[A-z]+/)
26
+ end
27
+ end
28
+ end
29
+
30
+ def initialize(card_num:, dir_path:, index:, type:)
31
+ @card_num = card_num
32
+ @dir_path = dir_path
33
+ @index = index
34
+ @type = type
35
+ end
36
+
37
+ def connected?
38
+ status.casecmp('connected').zero?
39
+ end
40
+
41
+ def display_name
42
+ return if edid.to_s.empty?
43
+
44
+ (display_name_text + unspecified_text).join(' ').strip
45
+ end
46
+
47
+ def status
48
+ File.read(File.join(dir_path, 'status')).strip
49
+ end
50
+
51
+ private
52
+
53
+ def display_descriptors_raw
54
+ edid.slice EDID_DESCRIPTORS_CONF[:index_range]
55
+ end
56
+
57
+ def display_name_text
58
+ display_descriptors_raw
59
+ .scan(/(?<=#{EDID_DESCRIPTORS_CONF[:display_name_leading_bytes]}).{1,13}/)
60
+ end
61
+
62
+ def edid
63
+ File.read("#{dir_path}/edid", encoding: 'ascii-8bit')
64
+ end
65
+
66
+ def unspecified_text
67
+ display_descriptors_raw
68
+ .scan(/(?<=#{EDID_DESCRIPTORS_CONF[:unspecified_text_leading_bytes]}).{1,13}/)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AmdgpuFan
4
+ # A mixin to help with CLI output formatting
5
+ module CliOutputFormat
6
+ METER_CHAR = '*'
7
+ TIME_FORMAT = '%F %T'
8
+
9
+ private
10
+
11
+ def current_time
12
+ Time.now.strftime(TIME_FORMAT)
13
+ end
14
+
15
+ def percent_meter(percent, length = 10)
16
+ progress_bar_count = (length * percent.to_f / 100).round
17
+ percent_string = "#{format '%<num>0.2i', num: percent}%".ljust(3)
18
+ "[#{METER_CHAR * progress_bar_count}#{' ' * (length - progress_bar_count)}]#{percent_string}"
19
+ end
20
+
21
+ def radeon_logo
22
+ File.read(File.join(__dir__, '../../../assets/radeon_r_black_red_100x100.ascii'))
23
+ end
24
+ end
25
+ end