Skip to content

Commit a3f398c

Browse files
Merge pull request #8 from analysiscenter/run_notebook_improvements
`run_notebook` improvements
2 parents bc0aae1 + 935a5a1 commit a3f398c

File tree

8 files changed

+179
-30
lines changed

8 files changed

+179
-30
lines changed

nbtools/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
from .run_notebook import run_notebook
55
from .pylint_notebook import pylint_notebook
66

7-
__version__ = '0.9.9'
7+
__version__ = '0.9.10'

nbtools/core.py

100644100755
Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ def get_available_gpus(n=1, min_free_memory=0.9, max_processes=2, verbose=False,
162162
print(f'Device {i} | Free memory: {fraction_free:4.2f} | '
163163
f'Number of running processes: {num_processes:>2} | Free: {consider_available}')
164164

165+
nvidia_smi.nvmlShutdown()
166+
165167
if isinstance(n, str) and n.startswith('max'):
166168
n = len(available_devices)
167169

@@ -187,7 +189,7 @@ def get_gpu_free_memory(index):
187189
nvidia_smi.nvmlDeviceGetCount()
188190
handle = nvidia_smi.nvmlDeviceGetHandleByIndex(index)
189191
info = nvidia_smi.nvmlDeviceGetMemoryInfo(handle)
190-
192+
nvidia_smi.nvmlShutdown()
191193
return info.free / info.total
192194

193195
def set_gpus(n=1, min_free_memory=0.9, max_processes=2, verbose=False, raise_error=False):
@@ -225,3 +227,31 @@ def set_gpus(n=1, min_free_memory=0.9, max_processes=2, verbose=False, raise_err
225227
if verbose:
226228
print(f'{newline}`CUDA_VISIBLE_DEVICES` set to "{str_devices}"')
227229
return devices
230+
231+
def free_gpus(devices=None):
232+
""" Terminate all processes on gpu devices.
233+
234+
Parameters
235+
----------
236+
devices : iterable of ints
237+
Device indices to terminate processes.
238+
If None, than free all available gpus.
239+
"""
240+
import nvidia_smi
241+
import psutil
242+
243+
nvidia_smi.nvmlInit()
244+
245+
if devices is None:
246+
if 'CUDA_VISIBLE_DEVICES' in os.environ.keys():
247+
devices = [int(d) for d in os.environ["CUDA_VISIBLE_DEVICES"].split(',')]
248+
else:
249+
devices = range(0, nvidia_smi.nvmlDeviceGetCount())
250+
251+
for device_index in devices:
252+
handle = nvidia_smi.nvmlDeviceGetHandleByIndex(device_index)
253+
254+
for proc in nvidia_smi.nvmlDeviceGetComputeRunningProcesses(handle):
255+
psutil.Process(proc.pid).terminate()
256+
257+
nvidia_smi.nvmlShutdown()

nbtools/nbstat/cli.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ def output_looped(inspector, name, formatter, view_args,
118118
elif inkey == 'm':
119119
if formatter[Resource.DEVICE_UTIL]:
120120
formatter[Resource.DEVICE_UTIL_MA] = not formatter[Resource.DEVICE_UTIL_MA]
121+
elif inkey.code == 265:
122+
formatter[Resource.PID] = not formatter[Resource.PID]
123+
elif inkey.code == 266:
124+
formatter[Resource.CPU] = not formatter[Resource.CPU]
125+
elif inkey.code == 267:
126+
formatter[Resource.TYPE] = not formatter[Resource.TYPE]
121127
elif inkey == 'q':
122128
raise KeyboardInterrupt
123129
else:

nbtools/nbstat/resource.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
""" Resource -- a class to describe a property of an entry. Refer to class documentation for more. """
2-
from enum import Enum, auto
2+
from enum import Enum
3+
4+
# `enum.Auto` is bugged in Python 3.11
5+
int_generator = iter(range(0, 10000))
6+
auto = lambda: next(int_generator)
37

48

59
class Resource(Enum):

nbtools/nbstat/resource_entry.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,20 @@ def to_format_data(self, resource, terminal, **kwargs):
5050
Resource.DEVICE_PROCESS_PID,]:
5151
pass
5252

53-
elif resource in [Resource.NAME, Resource.TYPE]:
53+
elif resource == Resource.NAME:
5454
if data is not None:
55-
if 'zombie' in data or 'container' in data:
56-
style = terminal.red
5755
if '/' in data:
5856
data = '~' + data.split('/')[-1]
57+
if len(data) >= 60:
58+
data = data.replace('.ipynb', '').replace('.py', '')
59+
data = data[:30] + '[...]' + data[-30]
60+
61+
elif resource == Resource.TYPE:
62+
if data is not None:
63+
if 'zombie' in data or 'containerd' in data:
64+
style = terminal.red
65+
if 'run_notebook' in data:
66+
style = terminal.green
5967

6068
elif resource == Resource.CREATE_TIME:
6169
if data is not None:

nbtools/nbstat/resource_inspector.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
from .resource import Resource
1414
from .resource_table import ResourceTable
1515
from .utils import format_memory, pid_to_name, pid_to_ngid, true_len, true_rjust, true_center, FiniteList
16+
from ..run_notebook import get_run_notebook_name
1617

1718

1819

1920
KERNEL_ID_SEARCHER = re.compile('kernel-(.*).json').search
2021
VSCODE_KEY_SEARCHER = re.compile('key=b"(.*)"').search
2122
SCRIPT_NAME_SEARCHER = re.compile('python.* (.*).py').search
23+
RUN_NOTEBOOK_PATH_SEARCHER = re.compile('/tmp/.*.json.*--HistoryManager.hist_file=:memory:.*').search
2224

2325

2426
class ResourceInspector:
@@ -232,6 +234,7 @@ def get_process_table(self, formatter=None):
232234
kernel_id = KERNEL_ID_SEARCHER(cmdline)
233235
vscode_key = VSCODE_KEY_SEARCHER(cmdline)
234236
script_name = SCRIPT_NAME_SEARCHER(cmdline)
237+
run_notebook_path = RUN_NOTEBOOK_PATH_SEARCHER(cmdline)
235238

236239
if kernel_id:
237240
# The name will be changed by data from `notebook_table`.
@@ -245,6 +248,11 @@ def get_process_table(self, formatter=None):
245248
type_ = 'vscode'
246249
name = vscode_key.group(1).split('-')[0] + '.ipynb'
247250
path = kernel_id = vscode_key.group(1)
251+
elif run_notebook_path:
252+
type_ = 'run_notebook'
253+
name = get_run_notebook_name(process.ppid())
254+
path = cwd
255+
kernel_id = None
248256
elif script_name:
249257
type_ = 'script'
250258
name = script_name.group(1) + '.py'
@@ -258,7 +266,10 @@ def get_process_table(self, formatter=None):
258266

259267
# PYTHON_PPID = PPID if parent is Python process else -1
260268
ppid = process.ppid()
261-
if ppid in python_pids:
269+
if type_ == 'run_notebook':
270+
# Spawned by `run_notebook` function of the library
271+
python_ppid = ppid
272+
elif ppid in python_pids:
262273
# Spawned by one of other Python processes
263274
type_ = 'subprocess'
264275
python_ppid = ppid
@@ -495,6 +506,12 @@ def get_view(self, name='nbstat', formatter=None, index_condition=None, force_st
495506
else:
496507
raise ValueError('Wrong name of view to get!')
497508

509+
# Filter some processes
510+
if 'nb' in name and table:
511+
bad_names = ['lsp_server']
512+
function = lambda index_value, _: not any(name in index_value for name in bad_names)
513+
table.filter_on_index(function, inplace=True)
514+
498515
# Filter index of the table by a regular expression
499516
if table and index_condition is not None:
500517
function = lambda index_value, _: bool(re.search(index_condition, str(index_value)))

0 commit comments

Comments
 (0)