Add a mean GPU view ('6' short key or --meangpu option)

This commit is contained in:
nicolargo 2016-12-29 17:21:14 +01:00
parent fee3f5d7f8
commit d11dbb9b7d
6 changed files with 118 additions and 33 deletions

1
NEWS
View File

@ -15,6 +15,7 @@ Changes:
Enhancements and new features:
* GPU monitoring (limited to NVidia) (issue #170)
* WebUI CPU consumption optimization (issue #836)
* Add ZeroMQ exporter (issue #939)
* Add CouchDB exporter (issue #928)

47
docs/aoa/gpu.rst Normal file
View File

@ -0,0 +1,47 @@
.. _gpu:
GPU
===
The GPU plugin is **only** compatible with NVIDIA GPU. You also need to
install the Python `pynvml`_ library on our system.
The GPU stats are shown as a percentage or value and for the configured
refresh time. The total GPU usage is displayed on the first line, the
memory consumption on the second one.
.. image:: ../_static/gpu.png
If you click on the ``6`` short key, the per GPU view is displayed:
.. image:: ../_static/pergpu.png
Note: you can also start Glances with the --meangpu option to display the
first view by default.
You can change the thresolds limits in the configuration file:
.. code-block:: ini
[gpu]
# Default processor values if not defined: 50/70/90
proc_careful=50
proc_warning=70
proc_critical=90
# Default memory values if not defined: 50/70/90
mem_careful=50
mem_warning=70
mem_critical=90
Legend:
================= ============
GPU (PROC/MEM) Status
================= ============
``<50%`` ``OK``
``>50%`` ``CAREFUL``
``>70%`` ``WARNING``
``>90%`` ``CRITICAL``
================= ============
.. _pynvml: https://pypi.python.org/pypi/nvidia-ml-py

View File

@ -123,6 +123,10 @@ Command-Line Options
disable top menu (QuickLook, CPU, MEM, SWAP and LOAD)
.. option:: -6, --meangpu
start Glances in mean GPU mode
.. option:: --enable-history
enable the history mode (matplotlib lib needed)

View File

@ -151,6 +151,8 @@ Start the client browser (browser mode):\n\
parser.add_argument('-5', '--disable-top', action='store_true',
default=False, dest='disable_top',
help='disable top menu (QL, CPU, MEM, SWAP and LOAD)')
parser.add_argument('-6', '--meangpu', action='store_true', default=False,
dest='meangpu', help='start Glances in mean GPU mode')
parser.add_argument('--disable-history', action='store_true', default=False,
dest='disable_history', help='disable stats history')
parser.add_argument('--disable-bold', action='store_true', default=False,

View File

@ -54,6 +54,7 @@ class _GlancesCurses(object):
'3': {'switch': 'disable_quicklook'},
'4': {'switch': 'full_quicklook'},
'5': {'switch': 'disable_top'},
'6': {'switch': 'meangpu'},
'/': {'switch': 'process_short_name'},
'd': {'switch': 'disable_diskio'},
'A': {'switch': 'disable_amps'},

View File

@ -83,9 +83,14 @@ class Plugin(GlancesPlugin):
# !!! JUST FOR TEST
# self.stats = [{"key": "gpu_id", "mem": None, "proc": 60, "gpu_id": 0, "name": "GeForce GTX 560 Ti"}]
# self.stats = [{"key": "gpu_id", "mem": 10, "proc": 60, "gpu_id": 0, "name": "GeForce GTX 560 Ti"}]
# self.stats = [{"key": "gpu_id", "mem": 48.64645, "proc": 60.73, "gpu_id": 0, "name": "GeForce GTX 560 Ti"},
# {"key": "gpu_id", "mem": 70.743, "proc": 80.28, "gpu_id": 1, "name": "GeForce GTX 560 Ti"}]
# !!! TO BE REMOVED
# {"key": "gpu_id", "mem": 70.743, "proc": 80.28, "gpu_id": 1, "name": "GeForce GTX 560 Ti"},
# {"key": "gpu_id", "mem": 0, "proc": 0, "gpu_id": 2, "name": "GeForce GTX 560 Ti"}]
# self.stats = [{"key": "gpu_id", "mem": 48.64645, "proc": 60.73, "gpu_id": 0, "name": "GeForce GTX 560 Ti"},
# {"key": "gpu_id", "mem": None, "proc": 80.28, "gpu_id": 1, "name": "GeForce GTX 560 Ti"},
# {"key": "gpu_id", "mem": 0, "proc": 0, "gpu_id": 2, "name": "ANOTHER GPU"}]
# !!! TO BE COMMENTED
if not self.nvml_ready:
return self.stats
@ -128,53 +133,78 @@ class Plugin(GlancesPlugin):
if not self.stats or (self.stats == []) or self.is_disable():
return ret
# Check if all GPU have the same name
same_name = all(s['name'] == self.stats[0]['name'] for s in self.stats)
# gpu_stats contain the first GPU in the list
gpu_stats = self.stats[0]
# Header
header = ''
if len(self.stats) > 1:
header += '{} '.format(len(self.stats))
if same_name:
header += '{} {}'.format('GPU', gpu_stats['name'])
else:
header += '{}'.format('GPU')
msg = header[:17]
ret.append(self.curse_add_line(msg, "TITLE"))
# Build the string message
if len(self.stats) == 1:
# Mono GPU
gpu_stats = self.stats[0]
# Header
header = '{} {}'.format('GPU', gpu_stats['name'])
msg = header[:16]
ret.append(self.curse_add_line(msg, "TITLE"))
if len(self.stats) == 1 or args.meangpu:
# GPU stat summary or mono GPU
# New line
ret.append(self.curse_new_line())
# GPU CPU
msg = '{:8}'.format('proc:')
ret.append(self.curse_add_line(msg))
if gpu_stats['proc'] is None:
msg = '{:>8}'.format('N/A')
# GPU PROC
try:
mean_proc = sum(s['proc'] for s in self.stats if s is not None) / len(self.stats)
except TypeError:
mean_proc_msg = '{:>4}'.format('N/A')
else:
msg = '{:>7.0f}%'.format(gpu_stats['proc'])
mean_proc_msg = '{:>3.0f}%'.format(mean_proc)
if len(self.stats) > 1:
msg = '{:13}'.format('proc mean:')
else:
msg = '{:13}'.format('proc:')
ret.append(self.curse_add_line(msg))
ret.append(self.curse_add_line(
msg, self.get_views(item=gpu_stats[self.get_key()],
key='proc',
option='decoration')))
mean_proc_msg, self.get_views(item=gpu_stats[self.get_key()],
key='proc',
option='decoration')))
# New line
ret.append(self.curse_new_line())
# GPU MEM
msg = '{:8}'.format('mem:')
ret.append(self.curse_add_line(msg))
if gpu_stats['mem'] is None:
msg = '{:>8}'.format('N/A')
try:
mean_mem = sum(s['mem'] for s in self.stats if s is not None) / len(self.stats)
except TypeError:
mean_mem_msg = '{:>4}'.format('N/A')
else:
msg = '{:>7.0f}%'.format(gpu_stats['mem'])
mean_mem_msg = '{:>3.0f}%'.format(mean_mem)
if len(self.stats) > 1:
msg = '{:13}'.format('mem mean:')
else:
msg = '{:13}'.format('mem:')
ret.append(self.curse_add_line(msg))
ret.append(self.curse_add_line(
msg, self.get_views(item=gpu_stats[self.get_key()],
key='mem',
option='decoration')))
mean_mem_msg, self.get_views(item=gpu_stats[self.get_key()],
key='mem',
option='decoration')))
else:
# Multi GPU
# Header
header = '{} {}'.format(len(self.stats), 'GPUs')
msg = header[:16]
ret.append(self.curse_add_line(msg, "TITLE"))
for gpu_stats in self.stats:
# New line
ret.append(self.curse_new_line())
# GPU ID + PROC + MEM
msg = '{}: {:>3.0f}% mem: {:>3.0f}%'.format(gpu_stats['gpu_id'],
gpu_stats['proc'],
gpu_stats['mem'],)
id_msg = '{}'.format(gpu_stats['gpu_id'])
try:
proc_msg = '{:>3.0f}%'.format(gpu_stats['proc'])
except ValueError:
proc_msg = '{:>4}'.format('N/A')
try:
mem_msg = '{:>3.0f}%'.format(gpu_stats['mem'])
except ValueError:
mem_msg = '{:>4}'.format('N/A')
msg = '{}: {} mem: {}'.format(id_msg, proc_msg, mem_msg)
ret.append(self.curse_add_line(msg))
return ret