Kaydet (Commit) 7e875ec6 authored tarafından Hakan Dündar's avatar Hakan Dündar

New: GPU usage and GPU memory columns (AMD GPUs only)

üst dab20d1a
......@@ -208,12 +208,15 @@ class Config:
self.processes_disk_data_precision = 1
self.processes_disk_data_unit = 0
self.processes_disk_speed_bit = 0
self.processes_gpu_precision = 0
self.processes_gpu_memory_data_precision = 1
self.processes_gpu_memory_data_unit = 0
self.warn_before_stopping_processes = 1
self.processes_treeview_columns_shown = [0, 1, 2, 4, 5, 10, 11]
self.processes_data_row_sorting_column = 0
self.processes_data_row_sorting_order = 0
self.processes_data_column_order = [0, 1, 2, -1, 3, 4, -1, -1, -1, -1, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
self.processes_data_column_widths = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
self.processes_data_column_order = [0, 1, 2, -1, 3, 4, -1, -1, -1, -1, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
self.processes_data_column_widths = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
def config_default_users_func(self):
......@@ -345,6 +348,18 @@ class Config:
self.hide_kernel_threads = int(config_values[config_variables.index("hide_kernel_threads")])
else:
pass
if "processes_gpu_precision" in config_variables:
self.processes_gpu_precision = int(config_values[config_variables.index("processes_gpu_precision")])
else:
pass
if "processes_gpu_memory_data_precision" in config_variables:
self.processes_gpu_memory_data_precision = int(config_values[config_variables.index("processes_gpu_memory_data_precision")])
else:
pass
if "processes_gpu_memory_data_unit" in config_variables:
self.processes_gpu_memory_data_unit = int(config_values[config_variables.index("processes_gpu_memory_data_unit")])
else:
pass
self.users_treeview_columns_shown = [int(value) for value in config_values[config_variables.index("users_treeview_columns_shown")].strip("[]").split(", ")]
self.users_data_row_sorting_column = int(config_values[config_variables.index("users_data_row_sorting_column")])
......@@ -444,6 +459,9 @@ class Config:
config_write_text = config_write_text + "processes_disk_data_precision = " + str(self.processes_disk_data_precision) + "\n"
config_write_text = config_write_text + "processes_disk_data_unit = " + str(self.processes_disk_data_unit) + "\n"
config_write_text = config_write_text + "processes_disk_speed_bit = " + str(self.processes_disk_speed_bit) + "\n"
config_write_text = config_write_text + "processes_gpu_precision = " + str(self.processes_gpu_precision) + "\n"
config_write_text = config_write_text + "processes_gpu_memory_data_precision = " + str(self.processes_gpu_memory_data_precision) + "\n"
config_write_text = config_write_text + "processes_gpu_memory_data_unit = " + str(self.processes_gpu_memory_data_unit) + "\n"
config_write_text = config_write_text + "warn_before_stopping_processes = " + str(self.warn_before_stopping_processes) + "\n"
config_write_text = config_write_text + "processes_treeview_columns_shown = " + str(self.processes_treeview_columns_shown) + "\n"
config_write_text = config_write_text + "processes_data_row_sorting_column = " + str(self.processes_data_row_sorting_column) + "\n"
......
......@@ -3027,7 +3027,8 @@ def get_gpu_load_memory_frequency_power_broadcom_arm():
def get_gpu_load_memory_frequency_power_nvidia_arm(gpu_device_path):
"""
Get GPU load, video memory, GPU frequency, power usage if GPU vendor is NVIDIA and it is used on an ARM system.
Get GPU load, video memory, GPU frequency, power usage if GPU vendor is NVIDIA and
it is used on an ARM system (NVIDIA Tegra GPUs).
"""
# Define initial values
......@@ -3318,7 +3319,7 @@ def process_gpu_tool_output_amdgpu_top(gpu_pci_address, gpu_tool_output_amdgpu_t
gpu_encoder_load = "-"
gpu_decoder_load = "-"
not_supported_text = ["[Not Supported]", "[N/A]", "null", "Null", "NULL"]
not_supported_text = ["[Not Supported]", "[N/A]", "null", "Null", "NULL", "None"]
if gpu_tool_output_amdgpu_top != "-":
all_gpus_information = gpu_tool_output_amdgpu_top["devices"]
......@@ -3349,6 +3350,87 @@ def process_gpu_tool_output_amdgpu_top(gpu_pci_address, gpu_tool_output_amdgpu_t
return gpu_load_memory_frequency_power_dict
def get_process_gpu_information():
gpu_process_information_dict = {}
# Get encoder/decoder engine load of AMD GPU by using "amdgpu_top" tool.
threading.Thread(target=gpu_process_information_amd_func, daemon=True).start()
global gpu_tool_process_output_amdgpu_top
try:
check_value = gpu_tool_process_output_amdgpu_top
except NameError:
gpu_tool_process_output_amdgpu_top = "-"
# Update encoder/decoder engine load values. Because they are not get in "get_gpu_load_memory_frequency_power_amd" function.
gpu_process_information_dict = process_gpu_tool_process_output_amdgpu_top(gpu_tool_process_output_amdgpu_top, gpu_process_information_dict)
def gpu_process_information_amd_func():
command_list = ["amdgpu_top", "-J", "-s", "100ms", "-n", "1"]
if get_environment_type() == "flatpak":
command_list = ["flatpak-spawn", "--host"] + command_list
global gpu_tool_process_output_amdgpu_top
try:
gpu_tool_process_output_amdgpu_top = (subprocess.check_output(command_list, shell=False)).decode().strip()
import json
gpu_tool_process_output_amdgpu_top = json.loads(gpu_tool_process_output_amdgpu_top)
# Prevent errors because "amdgpu_top" may not be installed on systems.
except Exception:
pass
def process_gpu_tool_process_output_amdgpu_top(gpu_tool_process_output_amdgpu_top, gpu_process_information_dict):
"""
Get values from command output if there was no error when running the command.
"""
not_supported_text = ["[Not Supported]", "[N/A]", "null", "Null", "NULL", "None", 65535]
if gpu_tool_process_output_amdgpu_top != "-":
all_gpus_information = gpu_tool_process_output_amdgpu_top["devices"]
for gpu_information in all_gpus_information:
all_processes_gpu_information = gpu_information["fdinfo"]
for pid in all_processes_gpu_information:
process_gpu_information = all_processes_gpu_information[pid]["usage"]
try:
gpu_load_information = process_gpu_information["GFX"]
#gpu_load_unit = gpu_load_information["unit"]
gpu_usage = float(gpu_load_information["value"])
gpu_memory_information = process_gpu_information["VRAM"]
gpu_memory_unit = gpu_memory_information["unit"]
gpu_memory = float(gpu_memory_information["value"])
gpu_memory = get_memory_bytes_from_string(f'{gpu_memory} {gpu_memory_unit}')
except KeyError:
pass
if gpu_usage in not_supported_text:
gpu_usage = 0
if gpu_memory in not_supported_text:
gpu_memory = 0
pid = int(pid)
if pid not in gpu_process_information_dict:
gpu_process_information_dict[pid] = {"gpu_usage": gpu_usage, "gpu_memory": gpu_memory}
else:
gpu_process_information_dict[pid]["gpu_usage"] = gpu_process_information_dict[pid]["gpu_usage"] + gpu_usage
gpu_process_information_dict[pid]["gpu_memory"] = gpu_process_information_dict[pid]["gpu_memory"] + gpu_memory
return gpu_process_information_dict
def gpu_load_nvidia_func():
"""
Get GPU load average for NVIDIA (PCI) GPUs.
......
......@@ -1230,7 +1230,9 @@ class Processes:
[20, _tr('Memory'), 1, 1, 1, [GObject.TYPE_INT64], ['CellRendererText'], ['text'], [0], [1.0], [False], [cell_data_function_memory]],
[21, _tr('CPU') + " - " + _tr('Recursive'), 1, 1, 1, [float], ['CellRendererText'], ['text'], [0], [1.0], [False], [cell_data_function_cpu_usage_percent_recursive]],
[22, _tr('Memory (RSS)') + " - " + _tr('Recursive'), 1, 1, 1, [GObject.TYPE_INT64], ['CellRendererText'], ['text'], [0], [1.0], [False], [cell_data_function_memory_rss_recursive]],
[23, _tr('Memory') + " - " + _tr('Recursive'), 1, 1, 1, [GObject.TYPE_INT64], ['CellRendererText'], ['text'], [0], [1.0], [False], [cell_data_function_memory_recursive]]
[23, _tr('Memory') + " - " + _tr('Recursive'), 1, 1, 1, [GObject.TYPE_INT64], ['CellRendererText'], ['text'], [0], [1.0], [False], [cell_data_function_memory_recursive]],
[24, _tr('GPU'), 1, 1, 1, [float], ['CellRendererText'], ['text'], [0], [1.0], [False], [cell_data_function_gpu_usage_percent]],
[25, _tr('GPU Memory'), 1, 1, 1, [GObject.TYPE_INT64], ['CellRendererText'], ['text'], [0], [1.0], [False], [cell_data_function_memory_gpu]]
]
self.summable_column_dict = {_tr('CPU'): "cpu_usage", _tr('Memory (RSS)'): "memory_rss", _tr('Memory (VMS)'): "memory_vms",
......@@ -1285,6 +1287,7 @@ class Processes:
global processes_cpu_precision, processes_cpu_divide_by_core
global processes_memory_data_precision, processes_memory_data_unit
global processes_disk_data_precision, processes_disk_data_unit, processes_disk_speed_bit
global processes_gpu_precision, processes_gpu_memory_data_precision, processes_gpu_memory_data_unit
processes_cpu_precision = Config.processes_cpu_precision
processes_cpu_divide_by_core = Config.processes_cpu_divide_by_core
processes_memory_data_precision = Config.processes_memory_data_precision
......@@ -1292,6 +1295,9 @@ class Processes:
processes_disk_data_precision = Config.processes_disk_data_precision
processes_disk_data_unit = Config.processes_disk_data_unit
processes_disk_speed_bit = Config.processes_disk_speed_bit
processes_gpu_precision = Config.processes_gpu_precision
processes_gpu_memory_data_precision = Config.processes_gpu_memory_data_precision
processes_gpu_memory_data_unit = Config.processes_gpu_memory_data_unit
# Define global variables and get treeview columns, sort column/order, column widths, etc.
self.treeview_columns_shown = Config.processes_treeview_columns_shown
......@@ -1320,6 +1326,8 @@ class Processes:
cpu_usage_recursive_list = [0]
memory_rss_recursive_list = [0]
memory_recursive_list = [0]
gpu_usage_list = [0]
memory_gpu_list = [0]
# Get process information
global cmdline_list, application_image_dict
......@@ -1339,6 +1347,11 @@ class Processes:
ppid_list = self.rows_data_dict["ppid_list"]
username_list = self.rows_data_dict["username_list"]
cmdline_list = self.rows_data_dict["cmdline_list"]
if 24 in treeview_columns_shown or 25 in treeview_columns_shown:
try:
gpu_information_dict = Libsysmon.get_process_gpu_information()
except Exception:
gpu_information_dict = {}
# Get and append process data
tab_data_rows = []
......@@ -1417,6 +1430,20 @@ class Processes:
memory_list.append(memory)
if 20 in treeview_columns_shown:
tab_data_row.append(memory)
if 24 in treeview_columns_shown:
try:
gpu_usage = gpu_information_dict[pid]["gpu_usage"]
except Exception:
gpu_usage = 0
tab_data_row.append(gpu_usage)
gpu_usage_list.append(gpu_usage)
if 25 in treeview_columns_shown:
try:
gpu_memory = gpu_information_dict[pid]["gpu_memory"]
except Exception:
gpu_memory = 0
tab_data_row.append(gpu_memory)
memory_gpu_list.append(gpu_memory)
# Append process data into a list
tab_data_rows.append(tab_data_row)
......@@ -1434,7 +1461,9 @@ class Processes:
disk_write_speed_list,
cpu_usage_recursive_list,
memory_rss_recursive_list,
memory_recursive_list
memory_recursive_list,
gpu_usage_list,
memory_gpu_list
]
for cell_coloring_data_list in list_of_cell_coloring_data_lists:
......@@ -1487,6 +1516,7 @@ class Processes:
global max_value_cpu_usage_list, max_value_memory_rss_list, max_value_memory_vms_list, max_value_memory_shared_list, max_value_memory_list
global max_value_disk_read_data_list, max_value_disk_write_data_list, max_value_disk_read_speed_list, max_value_disk_write_speed_list
global max_value_cpu_usage_recursive_list, max_value_memory_rss_recursive_list, max_value_memory_recursive_list
global max_value_gpu_usage_list, max_value_memory_gpu_list
max_value_cpu_usage_list = max(cpu_usage_list)
max_value_memory_rss_list = max(memory_rss_list)
max_value_memory_vms_list = max(memory_vms_list)
......@@ -1499,6 +1529,8 @@ class Processes:
max_value_cpu_usage_recursive_list = max(cpu_usage_recursive_list)
max_value_memory_rss_recursive_list = max(memory_rss_recursive_list)
max_value_memory_recursive_list = max(memory_recursive_list)
max_value_gpu_usage_list = max(gpu_usage_list)
max_value_memory_gpu_list = max(memory_gpu_list)
# Show/Hide treeview expander arrows. If "child rows" are not used and there is no need for these expanders (they would be shown as empty spaces in this situation).
if self.show_processes_as_tree == 1:
......@@ -1685,6 +1717,16 @@ def cell_data_function_memory_recursive(tree_column, cell, tree_model, iter, dat
cell.set_property('text', data_unit_converter("data", "none", value, processes_memory_data_unit, processes_memory_data_precision))
cell_backround_color(cell, value, max_value_memory_recursive_list)
def cell_data_function_gpu_usage_percent(tree_column, cell, tree_model, iter, data):
value = tree_model.get(iter, data)[0]
cell.set_property('text', f'{value:.{processes_gpu_precision}f} %')
cell_backround_color(cell, value, max_value_gpu_usage_list)
def cell_data_function_memory_gpu(tree_column, cell, tree_model, iter, data):
value = tree_model.get(iter, data)[0]
cell.set_property('text', data_unit_converter("data", "none", value, processes_gpu_memory_data_unit, processes_gpu_memory_data_precision))
cell_backround_color(cell, value, max_value_memory_gpu_list)
def cell_backround_color(cell, value, max_value):
color = Gdk.RGBA()
color.red = 0.7
......
......@@ -213,51 +213,59 @@ class ProcessesMenu:
# CheckButton (Write Speed)
self.write_speed_cb = Common.checkbutton(_tr("Write Speed"), None)
grid.attach(self.write_speed_cb, 1, 1, 1, 1)
grid.attach(self.write_speed_cb, 0, 13, 1, 1)
# CheckButton (Priority)
self.priority_cb = Common.checkbutton(_tr("Priority"), None)
grid.attach(self.priority_cb, 1, 2, 1, 1)
grid.attach(self.priority_cb, 1, 1, 1, 1)
# CheckButton (Threads)
self.threads_cb = Common.checkbutton(_tr("Threads"), None)
grid.attach(self.threads_cb, 1, 3, 1, 1)
grid.attach(self.threads_cb, 1, 2, 1, 1)
# CheckButton (PPID)
self.ppid_cb = Common.checkbutton(_tr("PPID"), None)
grid.attach(self.ppid_cb, 1, 4, 1, 1)
grid.attach(self.ppid_cb, 1, 3, 1, 1)
# CheckButton (UID)
self.uid_cb = Common.checkbutton(_tr("UID"), None)
grid.attach(self.uid_cb, 1, 5, 1, 1)
grid.attach(self.uid_cb, 1, 4, 1, 1)
# CheckButton (GID)
self.gid_cb = Common.checkbutton(_tr("GID"), None)
grid.attach(self.gid_cb, 1, 6, 1, 1)
grid.attach(self.gid_cb, 1, 5, 1, 1)
# CheckButton (Start Time)
self.start_time_cb = Common.checkbutton(_tr("Start Time"), None)
grid.attach(self.start_time_cb, 1, 7, 1, 1)
grid.attach(self.start_time_cb, 1, 6, 1, 1)
# CheckButton (Command Line)
self.commandline_cb = Common.checkbutton(_tr("Command Line"), None)
grid.attach(self.commandline_cb, 1, 8, 1, 1)
grid.attach(self.commandline_cb, 1, 7, 1, 1)
# CheckButton (CPU Time)
self.cpu_time_cb = Common.checkbutton(_tr("CPU Time"), None)
grid.attach(self.cpu_time_cb, 1, 9, 1, 1)
grid.attach(self.cpu_time_cb, 1, 8, 1, 1)
# CheckButton (CPU - Recursive)
self.cpu_recursive_cb = Common.checkbutton(_tr("CPU") + " - " + _tr("Recursive"), None)
grid.attach(self.cpu_recursive_cb, 1, 10, 1, 1)
grid.attach(self.cpu_recursive_cb, 1, 9, 1, 1)
# CheckButton (Memory (RSS) - Recursive)
self.memory_rss_recursive_cb = Common.checkbutton(_tr("Memory (RSS)") + " - " + _tr("Recursive"), None)
grid.attach(self.memory_rss_recursive_cb, 1, 11, 1, 1)
grid.attach(self.memory_rss_recursive_cb, 1, 10, 1, 1)
# CheckButton (Memory - Recursive)
self.memory_recursive_cb = Common.checkbutton(_tr("Memory") + " - " + _tr("Recursive"), None)
grid.attach(self.memory_recursive_cb, 1, 12, 1, 1)
grid.attach(self.memory_recursive_cb, 1, 11, 1, 1)
# CheckButton (GPU Usage)
self.gpu_usage_cb = Common.checkbutton(_tr("GPU Usage"), None)
grid.attach(self.gpu_usage_cb, 1, 12, 1, 1)
# CheckButton (GPU Memory)
self.gpu_memory_cb = Common.checkbutton(_tr("GPU Memory"), None)
grid.attach(self.gpu_memory_cb, 1, 13, 1, 1)
def numbers_tab_gui(self):
......@@ -446,6 +454,8 @@ class ProcessesMenu:
self.cpu_recursive_cb.connect("toggled", self.on_add_remove_checkbuttons_toggled)
self.memory_rss_recursive_cb.connect("toggled", self.on_add_remove_checkbuttons_toggled)
self.memory_recursive_cb.connect("toggled", self.on_add_remove_checkbuttons_toggled)
self.gpu_usage_cb.connect("toggled", self.on_add_remove_checkbuttons_toggled)
self.gpu_memory_cb.connect("toggled", self.on_add_remove_checkbuttons_toggled)
self.cpu_precision_dd.connect("notify::selected-item", self.on_selected_item_notify)
self.memory_precision_dd.connect("notify::selected-item", self.on_selected_item_notify)
......@@ -492,6 +502,8 @@ class ProcessesMenu:
self.cpu_recursive_cb.disconnect_by_func(self.on_add_remove_checkbuttons_toggled)
self.memory_rss_recursive_cb.disconnect_by_func(self.on_add_remove_checkbuttons_toggled)
self.memory_recursive_cb.disconnect_by_func(self.on_add_remove_checkbuttons_toggled)
self.gpu_usage_cb.disconnect_by_func(self.on_add_remove_checkbuttons_toggled)
self.gpu_memory_cb.disconnect_by_func(self.on_add_remove_checkbuttons_toggled)
self.cpu_precision_dd.disconnect_by_func(self.on_selected_item_notify)
self.memory_precision_dd.disconnect_by_func(self.on_selected_item_notify)
......@@ -807,6 +819,18 @@ class ProcessesMenu:
self.memory_recursive_cb.set_active(True)
else:
self.memory_recursive_cb.set_active(False)
if 24 in Config.processes_treeview_columns_shown:
self.gpu_usage_cb.set_active(True)
else:
self.gpu_usage_cb.set_active(False)
if 25 in Config.processes_treeview_columns_shown:
self.gpu_memory_cb.set_active(True)
else:
self.gpu_memory_cb.set_active(False)
# Set GUI objects on Numbers tab
# Set data unit checkbuttons.
......@@ -885,6 +909,10 @@ class ProcessesMenu:
Config.processes_treeview_columns_shown.append(22)
if self.memory_recursive_cb.get_active() == True:
Config.processes_treeview_columns_shown.append(23)
if self.gpu_usage_cb.get_active() == True:
Config.processes_treeview_columns_shown.append(24)
if self.gpu_memory_cb.get_active() == True:
Config.processes_treeview_columns_shown.append(25)
# Apply changes immediately (without waiting update interval).
Common.treeview_column_order_width_row_sorting(None, None, Processes)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment