| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | help_text = """%(prog)s [reference.json compare.json | reference_dir/ compare_dir/] |
| | |
| | This script: |
| | |
| | 1. Runs `top -bco RES`, continuously extracting the memory usage of each process. |
| | 2. If a process uses more than `log_threshold` GiB and exceeds any other recorded |
| | entry for the process, it is stored in `entries`. |
| | 3. When this script receives SIGINT, it writes two files: |
| | * `log_file` will contain all recorded max-memory-per-process entries |
| | * `fail_file` will contain all entries that exceed `fail_threshold` |
| | """ |
| |
|
| | import argparse |
| | import os |
| | import re |
| | import signal |
| | import sys |
| |
|
| | from subprocess import Popen, PIPE, STDOUT |
| |
|
| | parser = argparse.ArgumentParser(prog='memmon.py', usage=help_text) |
| | parser.add_argument('--log-threshold', type=float, dest='log_threshold', |
| | default=0.5, |
| | help='Logging threshold in GiB.') |
| | parser.add_argument('--fail-threshold', type=float, dest='fail_threshold', |
| | default=2, |
| | help='Failure threshold in GiB.') |
| | parser.add_argument('--log-file', type=str, dest='log_file', default='memmon_log', |
| | help='Output file for log entries.') |
| | args, unused = parser.parse_known_args() |
| |
|
| | entries = {} |
| |
|
| |
|
| | def signal_handler(sig, frame): |
| | |
| | sortentries = sorted(entries.items(), key=lambda x: x[1], reverse=True) |
| |
|
| | lf = open(args.log_file, "w") |
| |
|
| | for com, mem in sortentries: |
| | status = "PASS" |
| | if mem >= args.fail_threshold: |
| | status = "FAIL" |
| | line = "%4s | %3.1f GiB | %s\n" % (status, mem, com) |
| | lf.write(line) |
| |
|
| | lf.close() |
| | sys.exit(0) |
| |
|
| |
|
| | signal.signal(signal.SIGINT, signal_handler) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | script_dir = os.path.dirname(os.path.realpath(__file__)) |
| | config_dir = os.path.join(script_dir, 'memmon_config') |
| |
|
| | proc = Popen(["top", "-b", "-w", "512"], |
| | stdin=PIPE, stdout=PIPE, stderr=STDOUT, |
| | env={"XDG_CONFIG_HOME": config_dir}) |
| |
|
| | regex = re.compile("^\\s*([0-9.]+[kmgtp]?)\\s+(.+)\\s*$") |
| |
|
| |
|
| | |
| | def parse_mem(mem_str): |
| | if mem_str[-1] == "k": |
| | return float(mem_str[:-1]) / (1024 * 1024) |
| | elif mem_str[-1] == "m": |
| | return float(mem_str[:-1]) / (1024) |
| | elif mem_str[-1] == "g": |
| | return float(mem_str[:-1]) |
| | elif mem_str[-1] == "t": |
| | return float(mem_str[:-1]) * 1024 |
| | elif mem_str[-1] == "p": |
| | return float(mem_str[:-1]) * 1024 * 1024 |
| | |
| | return float(mem_str) / (1024 * 1024 * 1024) |
| |
|
| |
|
| | for line in proc.stdout: |
| | line = line.decode() |
| | match = regex.match(line) |
| | if match: |
| | mem = parse_mem(match.group(1)) |
| | if mem < args.log_threshold and mem < args.fail_threshold: |
| | continue |
| | com = match.group(2) |
| | if com in entries and entries[com] > mem: |
| | continue |
| | if mem >= args.fail_threshold: |
| | |
| | |
| | print("memmon.py failure: Build step exceed memory threshold:\n" |
| | " - Threshold: %3.1f GiB\n" |
| | " - Usage: %3.1f GiB\n" |
| | " - Command: %s" % (args.fail_threshold, mem, com)) |
| | entries[com] = mem |
| |
|