|
16 | 16 | import time
|
17 | 17 | import uuid
|
18 | 18 | import warnings
|
| 19 | +try: |
| 20 | + import psutil |
| 21 | +except ImportError: |
| 22 | + psutil = None |
19 | 23 |
|
20 | 24 | try:
|
21 | 25 | # jupyter_client >= 5, use tz-aware now
|
@@ -204,7 +208,7 @@ def _parent_header(self):
|
204 | 208 | 'apply_request',
|
205 | 209 | ]
|
206 | 210 | # add deprecated ipyparallel control messages
|
207 |
| - control_msg_types = msg_types + ['clear_request', 'abort_request', 'debug_request'] |
| 211 | + control_msg_types = msg_types + ['clear_request', 'abort_request', 'debug_request', 'usage_request'] |
208 | 212 |
|
209 | 213 | def __init__(self, **kwargs):
|
210 | 214 | super().__init__(**kwargs)
|
@@ -860,6 +864,39 @@ async def debug_request(self, stream, ident, parent):
|
860 | 864 | parent, ident)
|
861 | 865 | self.log.debug("%s", reply_msg)
|
862 | 866 |
|
| 867 | + # Taken from https://github.com/jupyter-server/jupyter-resource-usage/blob/e6ec53fa69fdb6de8e878974bcff006310658408/jupyter_resource_usage/metrics.py#L16 |
| 868 | + def get_process_metric_value(self, process, name, attribute=None): |
| 869 | + try: |
| 870 | + # psutil.Process methods will either return... |
| 871 | + metric_value = getattr(process, name)() |
| 872 | + if attribute is not None: # ... a named tuple |
| 873 | + return getattr(metric_value, attribute) |
| 874 | + else: # ... or a number |
| 875 | + return metric_value |
| 876 | + # Avoid littering logs with stack traces |
| 877 | + # complaining about dead processes |
| 878 | + except BaseException: |
| 879 | + return None |
| 880 | + |
| 881 | + async def usage_request(self, stream, ident, parent): |
| 882 | + reply_content = {} |
| 883 | + if psutil is None: |
| 884 | + return reply_content |
| 885 | + current_process = psutil.Process() |
| 886 | + all_processes = [current_process] + current_process.children(recursive=True) |
| 887 | + process_metric_value = self.get_process_metric_value |
| 888 | + reply_content['kernel_cpu'] = sum([process_metric_value(process, 'cpu_percent', None) for process in all_processes]) |
| 889 | + reply_content['kernel_memory'] = sum([process_metric_value(process, 'memory_info', 'rss') for process in all_processes]) |
| 890 | + cpu_percent = psutil.cpu_percent() |
| 891 | + # https://psutil.readthedocs.io/en/latest/index.html?highlight=cpu#psutil.cpu_percent |
| 892 | + # The first time cpu_percent is called it will return a meaningless 0.0 value which you are supposed to ignore. |
| 893 | + if cpu_percent != None and cpu_percent != 0.0: |
| 894 | + reply_content['host_cpu_percent'] = cpu_percent |
| 895 | + reply_content['host_virtual_memory'] = dict(psutil.virtual_memory()._asdict()) |
| 896 | + reply_msg = self.session.send(stream, 'usage_reply', reply_content, |
| 897 | + parent, ident) |
| 898 | + self.log.debug("%s", reply_msg) |
| 899 | + |
863 | 900 | async def do_debug_request(self, msg):
|
864 | 901 | raise NotImplementedError
|
865 | 902 |
|
|
0 commit comments