@@ -29,6 +29,20 @@ def get(self):
2929 else : # mem_limit is an Int
3030 mem_limit = config .mem_limit
3131
32+ def get_cpu_percent (p ):
33+ try :
34+ return p .cpu_percent (interval = 0.1 )
35+ # Avoid littering logs with stack traces complaining
36+ # about dead processes having no CPU usage
37+ except :
38+ return 0
39+ cpu_percent = sum ([get_cpu_percent (p ) for p in all_processes ])
40+ # A better approach would use cpu_affinity to account for the
41+ # fact that the number of logical CPUs in the system is not
42+ # necessarily the same as the number of CPUs the process
43+ # can actually use. But cpu_affinity isn't available for OS X.
44+ cpu_count = psutil .cpu_count ()
45+
3246 limits = {}
3347
3448 if config .mem_limit != 0 :
@@ -37,8 +51,18 @@ def get(self):
3751 }
3852 if config .mem_warning_threshold != 0 :
3953 limits ['memory' ]['warn' ] = (config .mem_limit - rss ) < (config .mem_limit * config .mem_warning_threshold )
54+
55+ if config .cpu_limit != 0 :
56+ limits ['cpu' ] = {
57+ 'cpu' : config .cpu_limit
58+ }
59+ if config .cpu_warning_threshold != 0 :
60+ limits ['cpu' ]['warn' ] = (config .cpu_limit - cpu_percent ) < (config .cpu_limit * config .cpu_warning_threshold )
61+
4062 metrics = {
4163 'rss' : rss ,
64+ 'cpu_percent' : cpu_percent ,
65+ 'cpu_count' : cpu_count ,
4266 'limits' : limits ,
4367 }
4468 self .write (json .dumps (metrics ))
@@ -95,10 +119,39 @@ class ResourceUseDisplay(Configurable):
95119 """
96120 ).tag (config = True )
97121
122+ cpu_warning_threshold = Float (
123+ 0.1 ,
124+ help = """
125+ Warn user with flashing lights when CPU usage is within this fraction
126+ CPU usage limit.
127+
128+ For example, if memory limit is 150%, `cpu_warning_threshold` is 0.1,
129+ we will start warning the user when they use (150 - (150 * 0.1)) %.
130+
131+ Set to 0 to disable warning.
132+ """
133+ ).tag (config = True )
134+
135+ cpu_limit = Float (
136+ 0 ,
137+ help = """
138+ CPU usage limit to display to the user.
139+
140+ Note that this does not actually limit the user's CPU usage!
141+
142+ Defaults to reading from the `CPU_LIMIT` environment variable. If
143+ set to 0, no CPU usage limit is displayed.
144+ """
145+ ).tag (config = True )
146+
98147 @default ('mem_limit' )
99148 def _mem_limit_default (self ):
100149 return int (os .environ .get ('MEM_LIMIT' , 0 ))
101150
151+ @default ('cpu_limit' )
152+ def _cpu_limit_default (self ):
153+ return float (os .environ .get ('CPU_LIMIT' , 0 ))
154+
102155def load_jupyter_server_extension (nbapp ):
103156 """
104157 Called during notebook start
0 commit comments