Skip to content

Commit 0ab288f

Browse files
authored
Merge pull request #805 from datalayer-externals/usage
Add usage_request and usage_reply based on psutil
2 parents 74dfaec + 1af5953 commit 0ab288f

File tree

1 file changed

+38
-1
lines changed

1 file changed

+38
-1
lines changed

ipykernel/kernelbase.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
import time
1717
import uuid
1818
import warnings
19+
try:
20+
import psutil
21+
except ImportError:
22+
psutil = None
1923

2024
try:
2125
# jupyter_client >= 5, use tz-aware now
@@ -204,7 +208,7 @@ def _parent_header(self):
204208
'apply_request',
205209
]
206210
# 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']
208212

209213
def __init__(self, **kwargs):
210214
super().__init__(**kwargs)
@@ -860,6 +864,39 @@ async def debug_request(self, stream, ident, parent):
860864
parent, ident)
861865
self.log.debug("%s", reply_msg)
862866

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+
863900
async def do_debug_request(self, msg):
864901
raise NotImplementedError
865902

0 commit comments

Comments
 (0)