diff --git a/nvitop/gui/library/widestring.py b/nvitop/gui/library/widestring.py index 6e72a34..4f71579 100644 --- a/nvitop/gui/library/widestring.py +++ b/nvitop/gui/library/widestring.py @@ -41,7 +41,7 @@ def wcslen(string): class WideString: # pylint: disable=too-few-public-methods - def __init__(self, string, chars=None): + def __init__(self, string='', chars=None): if isinstance(string, WideString): string = string.string @@ -54,7 +54,7 @@ class WideString: # pylint: disable=too-few-public-methods else: self.chars = chars - def __add__(self, string): + def __add__(self, other): """ >>> (WideString('a') + WideString('b')).string 'ab' @@ -64,29 +64,35 @@ class WideString: # pylint: disable=too-few-public-methods ['a', 'f', 'd', 'b', 'c'] """ - if isinstance(string, str): - return WideString(self.string + string) - if isinstance(string, WideString): - return WideString(self.string + string.string, self.chars + string.chars) - return None + if isinstance(other, str): + return WideString(self.string + other) + if isinstance(other, WideString): + return WideString(self.string + other.string, self.chars + other.chars) + return NotImplemented - def __radd__(self, string): + def __radd__(self, other): """ >>> ('bc' + WideString('afd')).chars ['b', 'c', 'a', 'f', 'd'] """ - if isinstance(string, str): - return WideString(string + self.string) - if isinstance(string, WideString): - return WideString(string.string + self.string, string.chars + self.chars) - return None + if isinstance(other, str): + return WideString(other + self.string) + if isinstance(other, WideString): + return WideString(other.string + self.string, other.chars + self.chars) + return NotImplemented + + def __iadd__(self, other): + new = self + other + self.string = new.string + self.chars = new.chars + return self def __str__(self): return self.string def __repr__(self): - return "<{} '{}'>".format(self.__class__.__name__, self.string) + return '<{} {!r}>'.format(self.__class__.__name__, self.string) def __eq__(self, other): if not isinstance(other, (str, WideString)): diff --git a/nvitop/gui/screens/main/process.py b/nvitop/gui/screens/main/process.py index 5ad1dec..ec9a3fe 100644 --- a/nvitop/gui/screens/main/process.py +++ b/nvitop/gui/screens/main/process.py @@ -454,11 +454,13 @@ class ProcessPanel(Displayable): # pylint: disable=too-many-instance-attributes self.addstr( y, self.x, - '│{:>4} {:>7} {} {:>7} {:>8} {:>3} {} │'.format( + '│{:>4} {:>7} {} {} {:>8} {:>3} {} │'.format( device_display_index, cut_string(process.pid, maxlen=7, padstr='.'), process.type, - cut_string(process.username, maxlen=7, padstr='+'), + str( + WideString(cut_string(process.username, maxlen=7, padstr='+')).rjust(7) + ), process.gpu_memory_human, process.gpu_sm_utilization_string.replace('%', ''), WideString(host_info).ljust(self.width - 39)[: self.width - 39], @@ -578,10 +580,10 @@ class ProcessPanel(Displayable): # pylint: disable=too-many-instance-attributes host_info = cut_string(process.host_info, padstr='..', maxlen=self.width - 39) - info = '{:>7} {} {:>7} {:>8} {:>3} {}'.format( + info = '{:>7} {} {} {:>8} {:>3} {}'.format( cut_string(process.pid, maxlen=7, padstr='.'), process.type, - cut_string(process.username, maxlen=7, padstr='+'), + str(WideString(cut_string(process.username, maxlen=7, padstr='+')).rjust(7)), process.gpu_memory_human, process.gpu_sm_utilization_string.replace('%', ''), WideString(host_info).ljust(self.width - 39)[: self.width - 39], diff --git a/nvitop/gui/screens/metrics.py b/nvitop/gui/screens/metrics.py index 2c68392..408686a 100644 --- a/nvitop/gui/screens/metrics.py +++ b/nvitop/gui/screens/metrics.py @@ -394,8 +394,18 @@ class ProcessMetricsScreen(Displayable): # pylint: disable=too-many-instance-at process = self.process.snapshot columns = OrderedDict( [ - ('PID', str(process.pid).rjust(3)), - ('USER', WideString('{} {}'.format(process.type, process.username).rjust(6))), + (' GPU', self.process.device.display_index.rjust(4)), + ('PID ', '{} {}'.format(str(process.pid).rjust(3), process.type)), + ( + 'USER', + WideString( + cut_string( + WideString(process.username).rjust(4), + maxlen=32, + padstr='+', + ) + ), + ), (' GPU-MEM', process.gpu_memory_human.rjust(8)), (' %SM', str(process.gpu_sm_utilization).rjust(4)), ('%GMBW', str(process.gpu_memory_utilization).rjust(5)), @@ -407,39 +417,53 @@ class ProcessMetricsScreen(Displayable): # pylint: disable=too-many-instance-at ] ) - self.addstr(self.y + 4, self.x + 1, '{:>4} '.format(self.process.device.display_index)) + x = self.x + 1 + header = '' + fields = WideString() + no_break = True + for i, (col, value) in enumerate(columns.items()): + width = len(value) + if x + width < self.width - 2: + if i == 0: + header += col.rjust(width) + fields += value + else: + header += ' ' + col.rjust(width) + fields += ' ' + value + x = self.x + 1 + len(fields) + else: + no_break = False + break + + self.addstr(self.y + 2, self.x + 1, header.ljust(self.width - 2)) + self.addstr(self.y + 4, self.x + 1, str(fields.ljust(self.width - 2))) self.color_at( self.y + 4, self.x + 1, width=4, fg=self.process.device.snapshot.display_color ) - x = self.x + 7 - for col, value in columns.items(): - width = len(value) - self.addstr(self.y + 2, x, col.rjust(width) + ' ') - self.addstr(self.y + 4, x, str(value + ' ')) - x += width + 1 - x += 1 - if x + 4 < self.width - 2: - self.addstr( - self.y + 2, - x, - cut_string('COMMAND', self.width - x - 2, padstr='..').ljust( - self.width - x - 2 - ), - ) - if process.is_zombie or process.no_permissions: - self.color(fg='yellow') - elif process.is_gone: - self.color(fg='red') - self.addstr( - self.y + 4, - x, - cut_string( - WideString(process.command).ljust(self.width - x - 2), - self.width - x - 2, - padstr='..', - ), - ) + if no_break: + x = self.x + 1 + len(fields) + 2 + if x + 4 < self.width - 2: + self.addstr( + self.y + 2, + x, + cut_string('COMMAND', self.width - x - 2, padstr='..').ljust( + self.width - x - 2 + ), + ) + if process.is_zombie or process.no_permissions: + self.color(fg='yellow') + elif process.is_gone: + self.color(fg='red') + self.addstr( + self.y + 4, + x, + cut_string( + WideString(process.command).ljust(self.width - x - 2), + self.width - x - 2, + padstr='..', + ), + ) self.color(fg='cyan') for y, line in enumerate(self.cpu_percent.graph, start=self.y + 6): @@ -489,8 +513,6 @@ class ProcessMetricsScreen(Displayable): # pylint: disable=too-many-instance-at self.addstr(y, self.x + self.left_width + 2, line) self.color_reset() - self.addstr(self.y + 2, self.x + self.width - 2, ' │') # handle overflow - self.addstr(self.y + 4, self.x + self.width - 2, ' │') # handle overflow self.addstr(self.y + 6, self.x + 1, ' {} '.format(self.cpu_percent.max_value_string())) self.addstr(self.y + 7, self.x + 5, ' {} '.format(self.cpu_percent)) self.addstr(