From 1219bd81ebf257c81f3e62266f0be38158202760 Mon Sep 17 00:00:00 2001 From: Raffaello Bonghi Date: Tue, 21 Feb 2023 22:57:00 +0000 Subject: [PATCH] Improve GUI and improve service --- jtop/core/timer_reader.py | 31 +++++++++++++++++--------- jtop/gui/jtopgui.py | 3 ++- jtop/gui/lib/process_table.py | 6 ++++- jtop/gui/pall.py | 42 +++++++++++++++++++++++++---------- jtop/gui/pcontrol.py | 3 ++- jtop/gui/pgpu.py | 3 ++- jtop/service.py | 2 +- services/jtop.service | 1 + 8 files changed, 63 insertions(+), 28 deletions(-) diff --git a/jtop/core/timer_reader.py b/jtop/core/timer_reader.py index ca369f52..4eaf3548 100644 --- a/jtop/core/timer_reader.py +++ b/jtop/core/timer_reader.py @@ -15,8 +15,9 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from threading import Thread, Event +import sys import time +from threading import Thread, Event # Logging import logging # Create logger @@ -49,14 +50,17 @@ def _timer_callback(self, interval, stop_event): if interval > delta: time.sleep(interval - delta) except (KeyboardInterrupt, SystemExit): - pass - except AttributeError: - pass - except IOError: - pass + logger.info("KeyboardInterrupt or SystemExit, exit timer_reader thread") + except Exception as e: + logger.fatal("Exception in 'timer_reader thread': {}".format(e)) + # Store error message + self._error = sys.exc_info() logger.debug("jtop timer stopped") def open(self, interval=0.5): + # Catch exception if exist + self._error_status() + # Check if not running if self._thread is not None: return False # Check if thread or process exist @@ -68,15 +72,20 @@ def open(self, interval=0.5): def close(self, timeout=None): # Catch exception if exist - if self._error: - # Extract exception and raise - ex_type, ex_value, tb_str = self._error - ex_value.__traceback__ = tb_str - raise ex_value + self._error_status() # Check if thread and process are already empty self._stop_event.clear() if self._thread is not None: self._thread.join(timeout) self._thread = None return True + + def _error_status(self): + # Catch exception if exist + if not self._error: + return + # Extract exception and raise + ex_type, ex_value, tb_str = self._error + ex_value.__traceback__ = tb_str + raise ex_value # EOF diff --git a/jtop/gui/jtopgui.py b/jtop/gui/jtopgui.py index 1b4e636f..6d072318 100644 --- a/jtop/gui/jtopgui.py +++ b/jtop/gui/jtopgui.py @@ -134,7 +134,8 @@ def run(self, loop, seconds): self.increase(loop=True) old = datetime.now() - @check_size(20, 50) + # TODO Remove completely + # @check_size(20, 50) def draw(self): # First, clear the screen self.stdscr.erase() diff --git a/jtop/gui/lib/process_table.py b/jtop/gui/lib/process_table.py index 1a68c598..83a5dfc4 100644 --- a/jtop/gui/lib/process_table.py +++ b/jtop/gui/lib/process_table.py @@ -72,4 +72,8 @@ def draw(self, pos_y, pos_x, width, height, key, mouse): counter += info['clm'] except curses.error: break - return len(self.processes) + # Stop loop if table is bigger than height + if nprocess > height - 2: + break + return nprocess +# EOF diff --git a/jtop/gui/pall.py b/jtop/gui/pall.py index a7649b9d..c319fcb4 100644 --- a/jtop/gui/pall.py +++ b/jtop/gui/pall.py @@ -98,15 +98,19 @@ def __init__(self, stdscr, jetson): # Add Process table self.process_table = ProcessTable(self.stdscr, self.jetson.processes) # Number columns + self._max_height_menu = 0 self._n_columns = 0 if jetson.engine: self._n_columns += 1 + self._max_height_menu = max(self._max_height_menu, 5) if jetson.temperature: self._n_columns += 1 + self._max_height_menu = max(self._max_height_menu, len(jetson.temperature)) if jetson.power: self._n_columns += 1 - # mini menu size - self._height_menu = 6 + self._max_height_menu = max(self._max_height_menu, len(jetson.power['rail']) + 1) + # End corner + self._max_height_menu += 2 def draw(self, key, mouse): """ @@ -128,32 +132,46 @@ def draw(self, key, mouse): # Status disk line_counter += disk_gauge(self.stdscr, line_counter, 0, width, self.jetson.disk) # Plot all processes - line_counter += self.process_table.draw(line_counter, 0, width, height, key, mouse) + height_free_area = height - line_counter - self._max_height_menu - 1 + line_counter += self.process_table.draw(line_counter, 0, width, height_free_area, key, mouse) # If empty return if self._n_columns == 0: return # Plot low bar background line - pos_y_mini_menu = height - 1 - self._height_menu - self.stdscr.addch(pos_y_mini_menu, 0, curses.ACS_ULCORNER) - self.stdscr.addch(pos_y_mini_menu, width - 1, curses.ACS_URCORNER) - self.stdscr.hline(pos_y_mini_menu, 1, curses.ACS_HLINE, width - 2) - self.stdscr.vline(pos_y_mini_menu + 1, 0, curses.ACS_VLINE, pos_y_mini_menu - 1) - self.stdscr.vline(pos_y_mini_menu + 1, width - 1, curses.ACS_VLINE, pos_y_mini_menu - 1) + pos_y_mini_menu = line_counter + 2 + if height_free_area > 2: + pos_y_mini_menu = height - self._max_height_menu - 1 + column_height = height - pos_y_mini_menu + # Upper block + try: + self.stdscr.addch(pos_y_mini_menu, 0, curses.ACS_ULCORNER) + self.stdscr.addch(pos_y_mini_menu, width - 1, curses.ACS_URCORNER) + self.stdscr.hline(pos_y_mini_menu, 1, curses.ACS_HLINE, width - 2) + except curses.error: + pass + # Lines + self.stdscr.vline(pos_y_mini_menu + 1, 0, curses.ACS_VLINE, column_height - 3) + self.stdscr.vline(pos_y_mini_menu + 1, width - 1, curses.ACS_VLINE, column_height - 3) + try: + self.stdscr.addch(pos_y_mini_menu + self._max_height_menu - 1, 0, curses.ACS_LLCORNER) + self.stdscr.addch(pos_y_mini_menu + self._max_height_menu - 1, width - 1, curses.ACS_LRCORNER) + self.stdscr.hline(pos_y_mini_menu + self._max_height_menu - 1, 1, curses.ACS_HLINE, width - 2) + except curses.error: + pass # Add engines, temperature and power column_width = (width) // (self._n_columns) - column_height = height - line_counter - 3 + first # Plot compact info column = 0 if self.jetson.engine: size_info = compact_engines(self.stdscr, 0, pos_y_mini_menu, column_width + 2, self.jetson) - if size_info > column_height: + if size_info >= column_height: for n_arrow in range(column_width + 1): self.stdscr.addch(first + height - 2, 1 + n_arrow, curses.ACS_DARROW, curses.A_REVERSE | curses.A_BOLD) column += column_width + 1 # Plot temperatures if self.jetson.temperature: size_temperatures = plot_temperatures(self.stdscr, column + 1, pos_y_mini_menu, column_width - 4, column_height, self.jetson) - if size_temperatures > column_height: + if size_temperatures > (column_height - 3): for n_arrow in range(column_width - 5): self.stdscr.addch(first + height - 2, column + n_arrow + 3, curses.ACS_DARROW, curses.A_REVERSE | curses.A_BOLD) column += column_width + 1 diff --git a/jtop/gui/pcontrol.py b/jtop/gui/pcontrol.py index a1f7dd6d..c6bb83c0 100644 --- a/jtop/gui/pcontrol.py +++ b/jtop/gui/pcontrol.py @@ -54,7 +54,7 @@ def plot_temperatures(stdscr, start, offset, width, height, jetson): # Print temperature value try: stdscr.addstr(offset + idx + 1, start, ("{name:<7}").format(name=name)) - stdscr.addstr(offset + idx + 1, start + offset // 2 + 1, ("{val:8.2f}C").format(val=value), color) + stdscr.addstr(offset + idx + 1, start + 12, ("{val:3.2f}C").format(val=value), color) except curses.error: pass counter = idx @@ -86,6 +86,7 @@ def plot_watts(stdscr, start, offset, width, height, jetson): stdscr.addstr(offset + len_power + 1, start + 3, unit_power, curses.A_BOLD) unit_avg = unit_to_string(total['avg'], total['unit'], 'W') stdscr.addstr(offset + len_power + 1, start + 10, unit_avg, curses.A_BOLD) + return len(power) + 1 class CTRL(Page): diff --git a/jtop/gui/pgpu.py b/jtop/gui/pgpu.py index f954226a..6d2c81ec 100644 --- a/jtop/gui/pgpu.py +++ b/jtop/gui/pgpu.py @@ -147,5 +147,6 @@ def draw(self, key, mouse): gpu_freq['name'] = "Frq" freq_gauge(self.stdscr, first + 1 + (idx + 1) * gpu_height, 1, frq_size, gpu_freq) # Draw all Processes - self.process_table.draw(first + 2 + gpu_height, 0, width, height, key, mouse) + height_table = height - first + 2 + gpu_height + self.process_table.draw(first + 2 + gpu_height, 0, width, height_table, key, mouse) # EOF diff --git a/jtop/service.py b/jtop/service.py index a99f304f..eb166982 100644 --- a/jtop/service.py +++ b/jtop/service.py @@ -85,7 +85,7 @@ def remove_service_pipe(): if os.path.isdir(JTOP_PIPE): logger.info("Remove folder {pipe}".format(pipe=JTOP_PIPE)) rmtree(JTOP_PIPE) - elif os.path.isfile(JTOP_PIPE): + elif os.path.exists(JTOP_PIPE): logger.info("Remove pipe {pipe}".format(pipe=JTOP_PIPE)) os.remove(JTOP_PIPE) diff --git a/services/jtop.service b/services/jtop.service index 4143874a..8dfdf78a 100644 --- a/services/jtop.service +++ b/services/jtop.service @@ -15,6 +15,7 @@ # along with this program. If not, see . [Unit] Description=jtop service +After=multi-user.target [Service] # Type=exec