|
2 | 2 |
|
3 | 3 | import datetime
|
4 | 4 | import functools
|
| 5 | +import itertools |
5 | 6 | import logging
|
6 | 7 | import os
|
7 | 8 | import re
|
8 | 9 | import shutil
|
9 | 10 | import stat
|
10 | 11 | import sys
|
11 |
| -import time |
12 | 12 | import tempfile
|
| 13 | +import time |
13 | 14 | import uuid
|
14 | 15 | from abc import ABCMeta, abstractmethod
|
15 | 16 | from io import IOBase, open # pylint: disable=redefined-builtin
|
16 | 17 | from threading import Timer
|
17 | 18 | from typing import (IO, Any, AnyStr, Callable, Dict, Iterable, List, Tuple,
|
18 | 19 | MutableMapping, MutableSequence, Optional, Union, cast)
|
19 | 20 |
|
20 |
| -import shellescape |
21 | 21 | import psutil
|
| 22 | +import shellescape |
22 | 23 | from prov.model import PROV
|
| 24 | +from schema_salad.sourceline import SourceLine |
23 | 25 | from six import PY2, with_metaclass
|
24 | 26 | from typing_extensions import (TYPE_CHECKING, # pylint: disable=unused-import
|
25 | 27 | Text)
|
26 |
| -from schema_salad.sourceline import SourceLine |
27 | 28 |
|
28 | 29 | from .builder import Builder, HasReqsHints # pylint: disable=unused-import
|
29 | 30 | from .context import RuntimeContext # pylint: disable=unused-import
|
@@ -231,11 +232,11 @@ def _setup(self, runtimeContext): # type: (RuntimeContext) -> None
|
231 | 232 | for p in self.generatemapper.files()}, indent=4))
|
232 | 233 |
|
233 | 234 | def _execute(self,
|
234 |
| - runtime, # type: List[Text] |
235 |
| - env, # type: MutableMapping[Text, Text] |
236 |
| - runtimeContext, # type: RuntimeContext |
237 |
| - monitor_function=None # type: Optional[Callable] |
238 |
| - ): # type: (...) -> None |
| 235 | + runtime, # type: List[Text] |
| 236 | + env, # type: MutableMapping[Text, Text] |
| 237 | + runtimeContext, # type: RuntimeContext |
| 238 | + monitor_function=None, # type: Optional[Callable] |
| 239 | + ): # type: (...) -> None |
239 | 240 |
|
240 | 241 | scr, _ = self.get_requirement("ShellCommandRequirement")
|
241 | 242 |
|
@@ -383,6 +384,30 @@ def _execute(self,
|
383 | 384 | _logger.debug(u"[job %s] Removing temporary directory %s", self.name, self.tmpdir)
|
384 | 385 | shutil.rmtree(self.tmpdir, True)
|
385 | 386 |
|
| 387 | + def process_monitor(self, sproc): |
| 388 | + monitor = psutil.Process(sproc.pid) |
| 389 | + memory_usage = [None] # Value must be list rather than integer to utilise pass-by-reference in python |
| 390 | + |
| 391 | + def get_tree_mem_usage(memory_usage): |
| 392 | + children = monitor.children() |
| 393 | + rss = monitor.memory_info().rss |
| 394 | + while len(children): |
| 395 | + rss += sum([process.memory_info().rss for process in children]) |
| 396 | + children = list(itertools.chain(*[process.children() for process in children])) |
| 397 | + if memory_usage[0] is None or rss > memory_usage[0]: |
| 398 | + memory_usage[0] = rss |
| 399 | + |
| 400 | + mem_tm = Timer(interval=1, function=get_tree_mem_usage, args=(memory_usage,)) |
| 401 | + mem_tm.daemon = True |
| 402 | + mem_tm.start() |
| 403 | + sproc.wait() |
| 404 | + mem_tm.cancel() |
| 405 | + if memory_usage[0] is not None: |
| 406 | + _logger.info(u"[job %s] Max memory used: %iMiB", self.name, |
| 407 | + round(memory_usage[0] / (2 ** 20))) |
| 408 | + else: |
| 409 | + _logger.info(u"Could not collect memory usage, job ended before monitoring began.") |
| 410 | + |
386 | 411 |
|
387 | 412 | class CommandLineJob(JobBase):
|
388 | 413 | def run(self,
|
@@ -419,7 +444,9 @@ def run(self,
|
419 | 444 | self.generatemapper, self.outdir, self.builder.outdir,
|
420 | 445 | inplace_update=self.inplace_update)
|
421 | 446 |
|
422 |
| - self._execute([], env, runtimeContext) |
| 447 | + monitor_function = functools.partial(self.process_monitor) |
| 448 | + |
| 449 | + self._execute([], env, runtimeContext, monitor_function) |
423 | 450 |
|
424 | 451 |
|
425 | 452 | CONTROL_CODE_RE = r'\x1b\[[0-9;]*[a-zA-Z]'
|
@@ -621,6 +648,8 @@ def run(self, runtimeContext): # type: (RuntimeContext) -> None
|
621 | 648 | monitor_function = functools.partial(
|
622 | 649 | self.docker_monitor, cidfile, runtimeContext.tmpdir_prefix,
|
623 | 650 | not bool(runtimeContext.cidfile_dir))
|
| 651 | + elif runtimeContext.user_space_docker_cmd: |
| 652 | + monitor_function = functools.partial(self.process_monitor) |
624 | 653 | self._execute(runtime, env, runtimeContext, monitor_function)
|
625 | 654 |
|
626 | 655 | @staticmethod
|
|
0 commit comments