add specs, basic gpu box

gpu
Jorge Barreto 2020-09-12 15:26:07 -04:00 committed by Lucas Zampieri
parent 900557ecb1
commit 4d35a36af1
2 changed files with 211 additions and 1 deletions

156
bpytop.py
View File

@ -282,6 +282,7 @@ DEFAULT_THEME: Dict[str, str] = {
"cpu_box" : "#3d7b46",
"mem_box" : "#8a882e",
"net_box" : "#423ba5",
"gpu_box" : "#ff33dd",
"proc_box" : "#923535",
"div_line" : "#30",
"temp_start" : "#4897d4",
@ -2416,7 +2417,7 @@ class NetBox(Box, SubBox):
class ProcBox(Box):
name = "proc"
num = 4
height_p = 68
height_p = 38
width_p = 55
min_w: int = 44
min_h: int = 16
@ -2467,6 +2468,7 @@ class ProcBox(Box):
cls.y = Box._b_cpu_h + 1
cls.current_y = cls.y
cls.current_h = cls.height
Box._b_proc_h = cls.current_h
cls.select_max = cls.height - 3
cls.redraw = True
cls.resized = True
@ -2874,6 +2876,91 @@ class ProcBox(Box):
Draw.buffer(cls.buffer, f'{out_misc}{out}{Term.fg}', only_save=Menu.active)
cls.redraw = cls.resized = cls.moved = False
class GpuBox(Box):
name = "gpu"
height_p = 30
width_p = 55
x = 1
y = 1
resized: bool = True
redraw: bool = True
graph_height: Dict[str, int] = {}
symbols: Dict[str, str] = {"download" : "", "upload" : ""}
buffer: str = "gpu"
Box.buffers.append(buffer)
@classmethod
def _calc_size(cls):
width_p: int
if cls.stat_mode:
width_p = 100
else:
width_p = cls.width_p
cls.width = round(Term.width * width_p / 100)
cls.height = Term.height - Box._b_proc_h - Box._b_cpu_h
cls.y = Box._b_cpu_h + 1
cls.x = Term.width - cls.width + 1
cls.box_width = 27 if cls.width > 45 else 19
cls.box_height = 9 if cls.height > 10 else cls.height - 2
cls.graph_height["download"] = round((cls.height - 2) / 2)
cls.graph_height["upload"] = cls.height - 2 - cls.graph_height["download"]
cls.redraw = True
@classmethod
def _draw_bg(cls) -> str:
if cls.proc_mode: return ""
return f'{create_box(box=cls, line_color=THEME.gpu_box)}'
@classmethod
def _draw_fg(cls):
if cls.proc_mode: return
gpu = GpuCollector
if gpu.redraw: cls.redraw = True
if not gpu.gpu: return
out: str = ""
out_misc: str = ""
x, y, w, h = cls.x + 1, cls.y + 1, cls.width - 2, cls.height - 2
reset: bool = bool(True)
if cls.resized or cls.redraw:
out_misc += cls._draw_bg()
out_misc += (f'{Mv.to(y-1, x+w - 25)}{THEME.gpu_box}{Symbol.h_line * (18 - len(gpu.gpu[:10]))}'
f'{Symbol.title_left}{Fx.b}{THEME.title(gpu.gpu[:10])}{Fx.ub}{THEME.gpu_box(Symbol.title_right)}{Term.fg}')
Draw.buffer("net_misc", out_misc, only_save=True)
cy = 0
# for direction in ["download", "upload"]:
# strings = gpu.strings[gpu.gpu][direction]
# stats = gpu.stats[gpu.gpu][direction]
# if cls.redraw: stats["redraw"] = True
# if stats["redraw"] or cls.resized:
# Graphs.net[direction] = Graph(w - bw - 3, cls.graph_height[direction], THEME.gradient[direction], stats["speed"], max_value=gpu.sync_top if CONFIG.net_sync else stats["graph_top"],
# invert=False if direction == "download" else True, color_max_value=gpu.net_min.get(direction) if CONFIG.net_color_fixed else None)
# out += f'{Mv.to(y if direction == "download" else y + cls.graph_height["download"], x)}{Graphs.net[direction](None if stats["redraw"] else stats["speed"][-1])}'
# out += (f'{Mv.to(by+cy, bx)}{THEME.main_fg}{cls.symbols[direction]} {strings["byte_ps"]:<10.10}' +
# ("" if bw < 20 else f'{Mv.to(by+cy, bx+bw - 12)}{"(" + strings["bit_ps"] + ")":>12.12}'))
# cy += 1 if bh != 3 else 2
# if bh >= 6:
# out += f'{Mv.to(by+cy, bx)}{cls.symbols[direction]} {"Top:"}{Mv.to(by+cy, bx+bw - 12)}{"(" + strings["top"] + ")":>12.12}'
# cy += 1
# if bh >= 4:
# out += f'{Mv.to(by+cy, bx)}{cls.symbols[direction]} {"Total:"}{Mv.to(by+cy, bx+bw - 10)}{strings["total"]:>10.10}'
# if bh > 2 and bh % 2: cy += 2
# else: cy += 1
# stats["redraw"] = False
# out += (f'{Mv.to(y, x)}{THEME.graph_text("amdgpu")}')
Draw.buffer(cls.buffer, f'{out_misc}{out}{Term.fg}', only_save=Menu.active)
cls.redraw = cls.resized = False
class Collector:
'''Data collector master class
* .start(): Starts collector thread
@ -3970,6 +4057,73 @@ class ProcCollector(Collector):
def _draw(cls):
ProcBox._draw_fg()
class GpuCollector(Collector):
'''Collects GPU stats'''
buffer: str = GpuBox.buffer
dir: str = "/sys/class/drm/"
hwmon: str = "/device/hwmon/hwmon0/"
gpus: List[str] = []
gpu_i: int = 0
gpu: str = ""
new_gpu: str = ""
gpu_error: bool = False
reset: bool = False
# graph_raise: Dict[str, int] = {"download" : 5, "upload" : 5}
# graph_lower: Dict[str, int] = {"download" : 5, "upload" : 5}
#min_top: int = 10<<10
#* Stats structure = stats[gpu device]
#[fans, clocks, mems, temps, power]
#[fanX_rpm, fanX_max, sclk, mclk, vddgfx, power, temp][total, last, top, graph_top, offset, speed, redraw, graph_raise, graph_low] = int, List[int], bool
stats: Dict[str, Dict[str, Dict[str, Any]]] = {}
#* Strings structure strings[network device][download, upload][total, byte_ps, bit_ps, top, graph_top] = str
strings: Dict[str, Dict[str, Dict[str, str]]] = {}
switched: bool = False
timestamp: float = time()
net_min: Dict[str, int] = {"download" : -1, "upload" : -1}
auto_min: bool = CONFIG.net_auto
sync_top: int = 0
sync_string: str = ""
@classmethod
def _get_dir(cls, name):
return cls.dir + name + cls.hwmon
@classmethod
def _get_gpus(cls):
'''Get a list of all network devices sorted by highest throughput'''
cls.gpu_i = 0
cls.gpu = ""
valid_gpu = re.compile('card\d$')
with os.scandir(cls.dir) as cards:
for card in cards:
if valid_gpu.match(card.name):
with open(cls._get_dir(card.name) + "name") as file:
cls.gpus.append(file.readline().strip())
file.close()
if not cls.gpus: cls.gpus = [""]
cls.gpu = cls.gpus[cls.gpu_i]
@classmethod
def _collect(cls):
speed: int
stat: Dict
if not cls.gpus: cls._get_gpus()
if not cls.gpu: return
cls.timestamp = time()
@classmethod
def _draw(cls):
GpuBox._draw_fg()
class Menu:
'''Holds all menus'''
active: bool = False

56
gpumon_specs.md Normal file
View File

@ -0,0 +1,56 @@
# GPU Monitor Specs
Should display:
- GPU Name
- GPU Temperature
- GPU Power Usage
- GPU Load %
- MEM Load %
- 'clocks' (please specify)
- 'vram usage' (please specify)
# Where It May Be Found
each `hwmon#` directory has a series of useful infos which may be parsed.
driver? name (i have `amdgpu`)
/sys/class/drm/card0/device/hwmon/hwmon0/name
current fan rpm can be found:
/sys/class/drm/card0/device/hwmon/hwmon0/fan1_input
freq label and value:
/sys/class/drm/card0/device/hwmon/hwmon0/freq1_label
/sys/class/drm/card0/device/hwmon/hwmon0/freq1_input
set power (VDDGFX):
/sys/class/drm/card0/device/hwmon/hwmon0/in0_label
/sys/class/drm/card0/device/hwmon/hwmon0/in0_input
temp (also has label? 'edge' on mine):
/sys/class/drm/card0/device/hwmon/hwmon0/temp1_label
/sys/class/drm/card0/device/hwmon/hwmon0/temp1_input
avg power (in W):
/sys/class/drm/card0/device/hwmon/hwmon0/power1_average
mem load %:
/sys/class/drm/card0/device/mem_busy_percent
gpu load %:
/sys/class/drm/card0/device/gpu_busy_percent
mem GTT total/used:
/sys/class/drm/card0/device/mem_info_gtt_used
/sys/class/drm/card0/device/mem_info_gtt_total
mem VRAM total/used:
/sys/class/drm/card0/device/mem_info_vram_used
/sys/class/drm/card0/device/mem_info_vram_total
potential:
chosen MCLK:
/sys/class/drm/card0/device/pp_dpm_mclk
chosen SCLK:
/sys/class/drm/card0/device/pp_dpm_sclk