From 5a7c2c36f1ef0623d95268e05ca767653d82d676 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sat, 11 Jul 2020 20:37:44 +0200 Subject: replace directory string constants in globalvars with Path objects from allocbench.directory --- allocbench/allocator.py | 15 +++--- allocbench/allocators/bumpptr.py | 6 ++- allocbench/allocators/tcmalloc.py | 7 +-- allocbench/artifact.py | 28 ++++++----- allocbench/benchmark.py | 37 ++++++++------- allocbench/benchmarks/espresso.py | 4 +- allocbench/directories.py | 97 +++++++++++++++++++++++++++++++++++++++ allocbench/facter.py | 4 +- allocbench/globalvars.py | 35 +------------- bench.py | 39 ++++++++-------- 10 files changed, 174 insertions(+), 98 deletions(-) create mode 100644 allocbench/directories.py diff --git a/allocbench/allocator.py b/allocbench/allocator.py index 8e4f041..1906a1e 100644 --- a/allocbench/allocator.py +++ b/allocbench/allocator.py @@ -28,8 +28,10 @@ import sys from typing import List, Optional from allocbench.artifact import Artifact, ArchiveArtifact, GitArtifact -from allocbench.globalvars import ALLOCBUILDDIR, ALLOCSRCDIR from allocbench.util import print_status, print_debug, print_error, print_info2, run_cmd +from allocbench.directories import (get_allocbench_build_dir, + get_allocbench_allocator_src_dir, + get_allocbench_allocator_build_dir) LIBRARY_PATH = "" for line in run_cmd(["ldconfig", "-v", "-N"], @@ -38,8 +40,7 @@ for line in run_cmd(["ldconfig", "-v", "-N"], if not line.startswith('\t'): LIBRARY_PATH += line -BUILDDIR = Path(ALLOCBUILDDIR) -SRCDIR = BUILDDIR / "src" +SRCDIR = Path(get_allocbench_build_dir()) / "src" SRCDIR.mkdir(parents=True, exist_ok=True) @@ -73,7 +74,7 @@ class Allocator: self.class_file = Path(inspect.getfile(self.__class__)) self.name = name self.srcdir = SRCDIR / self.name - self.dir = BUILDDIR / self.name + self.dir = get_allocbench_allocator_build_dir() / self.name self.patchdir = Path(self.class_file.parent, self.class_file.stem) # Update attributes @@ -158,7 +159,9 @@ class Allocator: cmd = cmd.format(dir=self.dir, srcdir=self.srcdir) try: - run_cmd(cmd, cwd=BUILDDIR, shell=True) + run_cmd(cmd, + cwd=get_allocbench_allocator_build_dir(), + shell=True) except CalledProcessError as err: print_debug(err.stderr, file=sys.stderr) print_error(f"Builing {self.name} failed") @@ -228,7 +231,7 @@ def collect_available_allocators(): available_allocators = {} - for alloc_def_path in Path(ALLOCSRCDIR).glob('*.py'): + for alloc_def_path in get_allocbench_allocator_src_dir().glob('*.py'): alloc_module_name = f'allocbench.allocators.{alloc_def_path.stem}' module = importlib.import_module(alloc_module_name) for name, obj in module.__dict__.items(): diff --git a/allocbench/allocators/bumpptr.py b/allocbench/allocators/bumpptr.py index 1d9d111..84097b1 100644 --- a/allocbench/allocators/bumpptr.py +++ b/allocbench/allocators/bumpptr.py @@ -22,9 +22,11 @@ See allocbench/bumpptr.c for the actual implementation. """ import os -from allocbench.allocator import Allocator, BUILDDIR +from allocbench.allocator import Allocator +from allocbench.directories import get_allocbench_allocator_build_dir # pylint: disable=invalid-name bumpptr = Allocator("bumpptr", - ld_preload=os.path.join(BUILDDIR, "bumpptr_alloc.so"), + ld_preload=str(get_allocbench_allocator_build_dir() / + "bumpptr_alloc.so"), color="xkcd:black") diff --git a/allocbench/allocators/tcmalloc.py b/allocbench/allocators/tcmalloc.py index 2c026a5..ee15a9d 100644 --- a/allocbench/allocators/tcmalloc.py +++ b/allocbench/allocators/tcmalloc.py @@ -16,8 +16,9 @@ # along with allocbench. """TCMalloc definition for allocbench""" -from allocbench.allocator import Allocator, BUILDDIR +from allocbench.allocator import Allocator from allocbench.artifact import GitArtifact +from allocbench.directories import get_allocbench_allocator_build_dir class TCMalloc(Allocator): @@ -47,7 +48,7 @@ tcmalloc_align = TCMalloc("TCMalloc-Aligned", version="1676100265bd189df6b5513feac15f102542367e", color="xkcd:light blue") -tcmalloc_align.ld_preload = f"{BUILDDIR}/align_to_cl.so {tcmalloc_align.ld_preload}" +tcmalloc_align.ld_preload = f"{get_allocbench_allocator_build_dir()}/align_to_cl.so {tcmalloc_align.ld_preload}" # pylint: enable=invalid-name @@ -85,7 +86,7 @@ tcmalloc_gperftools_align = TCMallocGperftools("TCMalloc-Gperftools-Aligned", color="xkcd:navy blue") tcmalloc_gperftools_align.ld_preload = ( - f"{BUILDDIR}/align_to_cl.so " + f"{get_allocbench_allocator_build_dir()}/align_to_cl.so " f"{tcmalloc_gperftools_align.ld_preload}") tcmalloc_gperftools_cacheline_exclusive = TCMallocGperftools( diff --git a/allocbench/artifact.py b/allocbench/artifact.py index 22e50f3..06c08f2 100644 --- a/allocbench/artifact.py +++ b/allocbench/artifact.py @@ -22,24 +22,23 @@ Both flavours are version controlled archive with a checksum and git repositorie with a specific checkout. """ -import os from subprocess import CalledProcessError -from allocbench.globalvars import ALLOCBENCHDIR +from allocbench.directories import get_allocbench_base_dir from allocbench.util import print_status, print_info, print_debug, print_error, run_cmd, sha1sum -ARTIFACT_STORE_DIR = os.path.join(ALLOCBENCHDIR, "cache") +ARTIFACT_STORE_DIR = get_allocbench_base_dir() / "cache" class Artifact: """Base class for external ressources""" def __init__(self, name): self.name = name - self.basedir = os.path.join(ARTIFACT_STORE_DIR, name) + self.basedir = ARTIFACT_STORE_DIR / name def _retrieve(self, cmd): """Run cmd to retrieve the artifact""" - os.makedirs(self.basedir, exist_ok=True) + self.basedir.mkdir(exist_ok=True) print_status(f'Retrieving artifact "{self.name}" ...') print_debug(f"By running: {cmd} in {self.basedir}") @@ -54,7 +53,7 @@ class GitArtifact(Artifact): def __init__(self, name, url): super().__init__(name) self.url = url - self.repo = os.path.join(self.basedir, "repo") + self.repo = self.basedir / "repo" def retrieve(self): """clone the git repo""" @@ -64,10 +63,10 @@ class GitArtifact(Artifact): def provide(self, checkout, location=None): """checkout new worktree at location""" if not location: - location = os.path.join(self.basedir, checkout) + location = self.basedir / checkout # check if we have already provided this checkout - if os.path.exists(location): + if location.exists(): try: run_cmd(GIT_FETCH_CMD, output_verbosity=1, cwd=location) except CalledProcessError: @@ -83,7 +82,7 @@ class GitArtifact(Artifact): return location # check if we have already retrieved the repo - if not os.path.exists(self.repo): + if not self.repo.exists(): self.retrieve() worktree_cmd = ["git", "worktree", "add", location, checkout] @@ -127,8 +126,7 @@ class ArchiveArtifact(Artifact): f'Archive format "{format}" not in supported list {self.supported_formats}' ) self.archive_format = archive_format - self.archive = os.path.join(self.basedir, - f"{self.name}.{self.archive_format}") + self.archive = self.basedir / f"{self.name}.{self.archive_format}" self.checksum = checksum def retrieve(self): @@ -139,7 +137,7 @@ class ArchiveArtifact(Artifact): """extract the archive""" # Download archive - if not os.path.exists(self.archive): + if not self.archive.exists(): self.retrieve() # compare checksums @@ -149,13 +147,13 @@ class ArchiveArtifact(Artifact): f"Archive {self.archive} does not match provided checksum") if not location: - location = os.path.join(self.basedir, "content") + location = self.basedir / "content" # Check if we already provided the archive at location - if os.path.exists(location): + if location.exists(): return location - os.makedirs(location, exist_ok=True) + location.mkdir(exist_ok=True) # Extract archive if self.archive_format == "tar": diff --git a/allocbench/benchmark.py b/allocbench/benchmark.py index 923b84f..e886ac5 100644 --- a/allocbench/benchmark.py +++ b/allocbench/benchmark.py @@ -33,6 +33,10 @@ from typing import Dict, Iterable, List, Optional import numpy as np +from allocbench.directories import (get_allocbench_benchmark_src_dir, + get_current_result_dir, + get_allocbench_benchmark_build_dir, + get_allocbench_build_dir) import allocbench.facter as facter import allocbench.globalvars from allocbench.util import print_status, print_error, print_warn @@ -183,13 +187,16 @@ class Benchmark: # Set result_dir if not hasattr(self, "result_dir"): - self.result_dir = os.path.abspath( - os.path.join(allocbench.globalvars.RESDIR or "", self.name)) + res_dir = get_current_result_dir() + if res_dir: + self.result_dir = (res_dir / self.name).absolute() + else: + self.result_dir = self.name + # Set build_dir if not hasattr(self, "build_dir"): - self.build_dir = os.path.abspath( - os.path.join(allocbench.globalvars.BUILDDIR, "benchmarks", - self.name)) + self.build_dir = (get_allocbench_benchmark_build_dir() / + self.name).absolute() self.Perm = namedtuple("Perm", self.args.keys()) @@ -299,8 +306,7 @@ class Benchmark: def check_requirements(self): """raise an error if a requirement is not found""" - os.environ[ - "PATH"] += f"{os.pathsep}{allocbench.globalvars.BUILDDIR}/benchmarks/{self.name}" + os.environ["PATH"] += f"{os.pathsep}{self.build_dir}" for requirement in self.requirements: exe = find_cmd(requirement) @@ -369,22 +375,23 @@ class Benchmark: argv = [] if prepend: + build_dir = get_allocbench_build_dir() if "cmd_prefix" in alloc: prefix_argv = alloc["cmd_prefix"].format( **substitutions).split() argv.extend(prefix_argv) # add exec wrapper so that a possible prefixed loader can execute shell scripts - argv.append(f"{allocbench.globalvars.BUILDDIR}/exec") + argv.append(f"{build_dir / 'exec'}") if self.measure_cmd != "": measure_argv = self.measure_cmd.format(**substitutions) measure_argv = prefix_cmd_with_abspath(measure_argv).split() argv.extend(measure_argv) - argv.append(f"{allocbench.globalvars.BUILDDIR}/exec") + argv.append(f"{build_dir / 'exec'}") - ld_preload = f"{allocbench.globalvars.BUILDDIR}/print_status_on_exit.so" - ld_preload += f" {allocbench.globalvars.BUILDDIR}/sig_handlers.so" + ld_preload = f"{build_dir / 'print_status_on_exit.so'}" + ld_preload += f" {build_dir / 'sig_handlers.so'}" if "LD_PRELOAD" in env or alloc.get("LD_PRELOAD", ""): ld_preload += f" {alloc.get('LD_PRELOAD', '')}" @@ -419,7 +426,7 @@ class Benchmark: substitutions = { "alloc": alloc_name, "perm": alloc_name, - "builddir": allocbench.globalvars.BUILDDIR + "builddir": get_allocbench_build_dir() } substitutions.update(self.__dict__) @@ -516,8 +523,7 @@ class Benchmark: Benchmark.is_perf_allowed() # add benchmark dir to PATH - os.environ[ - "PATH"] += f"{os.pathsep}{allocbench.globalvars.BUILDDIR}/benchmarks/{self.name}" + os.environ["PATH"] += f"{os.pathsep}{self.build_dir}" # save one valid result to expand invalid results valid_result = {} @@ -669,8 +675,7 @@ class Benchmark: # reset PATH os.environ["PATH"] = os.environ["PATH"].replace( - f"{os.pathsep}{allocbench.globalvars.BUILDDIR}/benchmarks/{self.name}", - "") + f"{os.pathsep}{self.build_dir}", "") # expand invalid results if valid_result != {}: diff --git a/allocbench/benchmarks/espresso.py b/allocbench/benchmarks/espresso.py index dbc099b..8ce4256 100644 --- a/allocbench/benchmarks/espresso.py +++ b/allocbench/benchmarks/espresso.py @@ -58,7 +58,7 @@ API function as well as memory placement strategies with good data locality. import os from allocbench.benchmark import Benchmark -from allocbench.globalvars import BENCHSRCDIR +from allocbench.directories import get_allocbench_benchmark_src_dir import allocbench.plots as plt @@ -71,7 +71,7 @@ class BenchmarkEspresso(Benchmark): self.args = {"file": ["largest.espresso"]} self.requirements = ["espresso"] - self.run_dir = os.path.join(BENCHSRCDIR, name) + self.run_dir = get_allocbench_benchmark_src_dir() / name super().__init__(name) def summary(self): diff --git a/allocbench/directories.py b/allocbench/directories.py new file mode 100644 index 0000000..3c76f0f --- /dev/null +++ b/allocbench/directories.py @@ -0,0 +1,97 @@ +# Copyright 2020 Florian Fischer +# +# This file is part of allocbench. +# +# allocbench is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# allocbench is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with allocbench. If not, see . +"""Functions to obtain specific directories in the allocbench directory tree""" + +from pathlib import Path +from typing import Optional, Union + +# /.../allocbench/allocbench +SRCDIR = Path(__file__).parent + + +def get_allocbench_src_dir() -> Path: + """Return path to allocbench's sources""" + return SRCDIR + + +# /.../allocbench/ +BASEDIR = SRCDIR.parent + + +def get_allocbench_base_dir() -> Path: + """Return path to allocbench's root directory""" + return BASEDIR + + +# /.../allocbench/allocbench/benchmarks +BENCHSRCDIR = SRCDIR / "benchmarks" + + +def get_allocbench_benchmark_src_dir() -> Path: + """Return path to benchmark definitions and sources""" + return BENCHSRCDIR + + +# /.../allocbench/allocbench/allocators +ALLOCSRCDIR = SRCDIR / "allocators" + + +def get_allocbench_allocator_src_dir() -> Path: + """Return path to allocator definitions""" + return ALLOCSRCDIR + + +# /.../allocbench/build +BUILDDIR = BASEDIR / "build" + + +def get_allocbench_build_dir() -> Path: + """Return path to allocbench's build directory""" + return BUILDDIR + + +# /.../allocbench/build/allocators +ALLOCBUILDDIR = BUILDDIR / "allocators" + + +def get_allocbench_allocator_build_dir() -> Path: + """Return path to the allocators build directory""" + return ALLOCBUILDDIR + + +# /.../allocbench/build/allocators +BENCHMARKBUILDDIR = BUILDDIR / "benchmarks" + + +def get_allocbench_benchmark_build_dir() -> Path: + """Return path to the benchmarks build directory""" + return BENCHMARKBUILDDIR + + +RESDIR = None + + +def set_current_result_dir(resdir: Union[Path, str]): + """Set the path to the result directory of the current invocation and silently create it""" + global RESDIR + RESDIR = Path(resdir) + RESDIR.mkdir(parents=True, exist_ok=True) + + +def get_current_result_dir() -> Optional[Path]: + """Return the path to the results of the current invocation""" + return RESDIR diff --git a/allocbench/facter.py b/allocbench/facter.py index 374c881..8aefbd8 100644 --- a/allocbench/facter.py +++ b/allocbench/facter.py @@ -25,7 +25,7 @@ import os import platform from subprocess import CalledProcessError -from allocbench.globalvars import BUILDDIR +from allocbench.directories import get_allocbench_build_dir from allocbench.util import print_debug, print_info, print_warn, run_cmd FACTS = {} @@ -42,7 +42,7 @@ def collect_facts(): FACTS["cpus"] = multiprocessing.cpu_count() FACTS["LD_PRELOAD"] = os.environ.get("LD_PRELOAD", None) - with open(os.path.join(BUILDDIR, "ccinfo"), "r") as ccinfo: + with open(get_allocbench_build_dir() / "ccinfo", "r") as ccinfo: FACTS["cc"] = ccinfo.readlines()[-1][:-1] # get commit info from git diff --git a/allocbench/globalvars.py b/allocbench/globalvars.py index 1b3e5fb..7a84a40 100644 --- a/allocbench/globalvars.py +++ b/allocbench/globalvars.py @@ -19,46 +19,13 @@ VERBOSITY: Verbosity level -1: quiet, 0: status, 1: info, 2: stdout of subcommands, 3: debug info ALLOCATORS: Dict holding the allocators to compare BENCHMARKS: List of available benchmarks - -ALLOCBENCHDIR: Root directory of allocbench -SRCDIR: Directory of allocbench sources -BENCHSRCDIR: Source directory for all benchmarks -ALLOCSRCDIR: Source directory for all benchmarks -BUILDDIR: Path of the build directory -ALLOCBUILDDIR: Path of the allocators build directory -RESDIR: Directory were the benchmark results are stored """ -import inspect -import os from typing import Dict -import allocbench.allocator - VERBOSITY = 0 -ALLOCATORS: Dict[str, allocbench.allocator.Allocator] = {} - -# /.../allocbench/allocbench -SRCDIR = os.path.dirname( - os.path.abspath(inspect.getfile(inspect.currentframe()))) - -# /.../allocbench/allocbench/benchmarks -BENCHSRCDIR = os.path.join(SRCDIR, "benchmarks") - -# /.../allocbench/allocbench/allocators -ALLOCSRCDIR = os.path.join(SRCDIR, "allocators") - -# /.../allocbench -ALLOCBENCHDIR = os.path.dirname(SRCDIR) - -# /.../allocbench/build -BUILDDIR = os.path.join(ALLOCBENCHDIR, "build") - -# /.../allocbench/build/allocators -ALLOCBUILDDIR = os.path.join(BUILDDIR, "allocators") - -RESDIR = None +ALLOCATORS = {} BENCHMARKS = [ e[:-3] for e in os.listdir(os.path.join(ALLOCBENCHDIR, BENCHSRCDIR)) diff --git a/bench.py b/bench.py index 4458681..8d786d5 100755 --- a/bench.py +++ b/bench.py @@ -28,6 +28,7 @@ import traceback from allocbench.allocator import collect_allocators from allocbench.analyse import analyze_bench, analyze_allocators from allocbench.benchmark import get_benchmark_object +from allocbench.directories import get_current_result_dir, set_current_result_dir import allocbench.facter as facter import allocbench.globalvars from allocbench.util import run_cmd @@ -40,21 +41,24 @@ from summarize import summarize def epilog(): """Run tasks on exit""" - # After early errors resdir may not be set - if allocbench.globalvars.RESDIR is not None: - if os.listdir(allocbench.globalvars.RESDIR) == []: - print_warn("Remove empty resultdir") - os.removedirs(allocbench.globalvars.RESDIR) - else: - endtime = datetime.datetime.now().isoformat() - endtime = endtime[:endtime.rfind(':')] - facter.FACTS["endtime"] = endtime - facter.store_facts(allocbench.globalvars.RESDIR) - # remove a left over status file if some is present if os.path.exists("status"): os.remove("status") + res_dir = get_current_result_dir() + # After early errors resdir may not be set + if not res_dir: + return + + if not res_dir.iterdir(): + print_warn("Remove empty resultdir") + res_dir.rmdir() + else: + endtime = datetime.datetime.now().isoformat() + endtime = endtime[:endtime.rfind(':')] + facter.FACTS["endtime"] = endtime + facter.store_facts(res_dir) + def check_dependencies(): """Check if known requirements of allocbench are met""" @@ -149,14 +153,13 @@ def main(): # Create result directory if args.resultdir: - allocbench.globalvars.RESDIR = os.path.join(args.resultdir) + set_current_result_dir(args.resultdir) else: - allocbench.globalvars.RESDIR = os.path.join("results", - facter.FACTS["hostname"], - facter.FACTS["starttime"]) + set_current_result_dir( + os.path.join("results", facter.FACTS["hostname"], + facter.FACTS["starttime"])) - print_status("Writing results to:", allocbench.globalvars.RESDIR) - os.makedirs(allocbench.globalvars.RESDIR, exist_ok=True) + print_status("Writing results to:", get_current_result_dir()) cwd = os.getcwd() @@ -214,7 +217,7 @@ def main(): start_time).total_seconds() # Save results in resultdir - bench.save(allocbench.globalvars.RESDIR) + bench.save(get_current_result_dir()) if hasattr(bench, "cleanup"): print_status("Cleaning up", bench.name, "...") -- cgit v1.2.3