11import json
2+ from concurrent .futures import ThreadPoolExecutor
23
34import psutil
45from notebook .base .handlers import IPythonHandler
56from tornado import web
7+ from tornado .concurrent import run_on_executor
68
79try :
810 # Traitlets >= 4.3.3
1214
1315
1416class ApiHandler (IPythonHandler ):
17+
18+ executor = ThreadPoolExecutor (max_workers = 5 )
19+
1520 @web .authenticated
1621 async def get (self ):
1722 """
@@ -38,4 +43,30 @@ async def get(self):
3843
3944 metrics = {"rss" : rss , "limits" : limits }
4045
46+ # Optionally get CPU information
47+ if config .track_cpu_percent :
48+ cpu_count = psutil .cpu_count ()
49+ cpu_percent = await self ._get_cpu_percent (all_processes )
50+
51+ if config .cpu_limit != 0 :
52+ limits ["cpu" ] = {"cpu" : config .cpu_limit }
53+ if config .cpu_warning_threshold != 0 :
54+ limits ["cpu" ]["warn" ] = (config .cpu_limit - self .cpu_percent ) < (
55+ config .cpu_limit * config .cpu_warning_threshold
56+ )
57+
58+ metrics .update (cpu_percent = cpu_percent , cpu_count = cpu_count )
59+
4160 self .write (json .dumps (metrics ))
61+
62+ @run_on_executor
63+ def _get_cpu_percent (self , all_processes ):
64+ def get_cpu_percent (p ):
65+ try :
66+ return p .cpu_percent (interval = 0.05 )
67+ # Avoid littering logs with stack traces complaining
68+ # about dead processes having no CPU usage
69+ except :
70+ return 0
71+
72+ return sum ([get_cpu_percent (p ) for p in all_processes ])
0 commit comments