import sys import logging import resource import socket import psutil def printflush(s: str, end: str = '\n') -> None: """Prints a string to the standard output and immediately flushes.""" print(s, end=end) sys.stdout.flush() def is_port_in_use(port: int) -> bool: """Determines whether a given port is in use on this machine. Credit: https://codereview.stackexchange.com/questions/116450/find-available-ports-on-localhost """ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: return sock.connect_ex(('localhost', port)) == 0 def bytes_to_gigabytes(x: int) -> float: return x / 1024 / 1024 / 1024 def report_system_resources(logger: logging.Logger) -> None: cores_physical = psutil.cpu_count(logical=False) cores_logical = psutil.cpu_count(logical=True) cores_s = "{} physical, {} logical".format(cores_physical, cores_logical) if psutil.cpu_freq(): cpu_freq_s = "{:.2f} GHz".format(psutil.cpu_freq().max / 1000) else: cpu_freq_s = "unknown" if psutil.virtual_memory(): vmem_total = bytes_to_gigabytes(psutil.virtual_memory().total) vmem_total_s = "{:.2f} GB".format(vmem_total) else: vmem_total_s = "unknown" if psutil.swap_memory(): swap_total = bytes_to_gigabytes(psutil.swap_memory().total) swap_free = bytes_to_gigabytes(psutil.swap_memory().free) swap_s = "{:.2f} GB ({:.2f} GB free)".format(swap_total, swap_free) else: swap_s = "unknown" disk_info = psutil.disk_usage('/') if disk_info: disk_size = bytes_to_gigabytes(disk_info.total) disk_free = bytes_to_gigabytes(disk_info.free) disk_s = "{:.2f} GB ({:.2f} GB free)".format(disk_size, disk_free) else: disk_s = "unknown" resource_s = '\n'.join([ '* CPU cores: {}'.format(cores_s), '* CPU frequency: {}'.format(cpu_freq_s), '* virtual memory: {}'.format(vmem_total_s), '* swap memory: {}'.format(swap_s), '* disk space: {}'.format(disk_s) ]) logger.info("system resources:\n%s", indent(resource_s, 2)) def report_resource_limits(logger: logging.Logger) -> None: resources = [ ('CPU time (seconds)', resource.RLIMIT_CPU), ('Heap size (bytes)', resource.RLIMIT_DATA), ('Num. process', resource.RLIMIT_NPROC), ('Num. files', resource.RLIMIT_NOFILE), ('Address space', resource.RLIMIT_AS), ('Locked address space', resource.RLIMIT_MEMLOCK) ] resource_limits = [ (name, resource.getrlimit(res)) for (name, res) in resources ] resource_s = '\n'.join([ '* {}: {}'.format(res, lim) for (res, lim) in resource_limits ]) logger.info("resource limits:\n%s", indent(resource_s, 2)) def print_task_start(task: str) -> None: s = '{}...'.format(task) printflush(s, end='\r') def print_task_end(task: str, outcome: str) -> None: width = 80 outcome = '[{}]'.format(outcome) left = '{}...'.format(task) right = outcome.rjust(width - len(left), ' ') s = left + right printflush(s, end='\n') def dedent(s: str) -> str: def num_leading_spaces(s: str) -> int: n = len(s) - len(s.lstrip(' ')) return n offset = 1 if s[0] == '\n' else 0 lines = s.split('\n') spaces = min(num_leading_spaces(ss) for ss in lines[offset:]) dedented = '\n'.join(l[spaces:] for l in lines) return dedented def indent(string: str, num_spaces: int) -> str: prefix = " " * num_spaces output = [] for line in string.splitlines(): output.append(prefix + line) return '\n'.join(output)