mmtk 0.32.0

MMTk is a framework for the design and implementation of high-performance and portable memory managers.
Documentation
#!/usr/bin/env python3
from string import Template
from argparse import ArgumentParser
from pathlib import Path
import tempfile
import sys
import os


def get_args():
    parser = ArgumentParser()
    parser.add_argument("-b", "--bpftrace", type=str, default="bpftrace",
                        help="Path of the bpftrace executable")
    parser.add_argument("-m", "--mmtk", type=str, required=True,
                        help="Path of the MMTk binary")
    parser.add_argument("-H", "--harness", action="store_true",
                        help="Only collect data for the timing iteration (harness_begin/harness_end)")
    parser.add_argument("-p", "--print-script", action="store_true",
                        help="Print the content of the bpftrace script")
    parser.add_argument(
        "-f", "--format", choices=["text", "json"], default="text", help="bpftrace output format")
    parser.add_argument("tool", type=str, help="Name of the bpftrace tool")
    return parser.parse_args()


def main():
    args = get_args()
    here = Path(__file__).parent.resolve()
    bpftrace_script = here / f"{args.tool}.bt"
    if not bpftrace_script.exists():
        print(f"Tracing script {str(bpftrace_script)} not found.")
        sys.exit(1)
    mmtk_bin = Path(args.mmtk)
    if not mmtk_bin.exists():
        print(f"MMTk binary {str(mmtk_bin)} not found.")
        sys.exit(1)
    prologue_file = here / \
        ("prologue_with_harness.bt.fragment" if args.harness else "prologue_without_harness.bt.fragment")
    prologue = prologue_file.read_text()
    epilogue = (here / "epilogue.bt.fragment").read_text()
    template = Template(prologue + bpftrace_script.read_text() + epilogue)
    with tempfile.NamedTemporaryFile(mode="w+t") as tmp:
        content = template.safe_substitute(
            MMTK=mmtk_bin, TMP_FILE=tmp.name)
        if args.print_script:
            print(content)
        tmp.write(content)
        tmp.flush()
        # We use execvp to replace the current process instead of creating
        # a subprocess (or sh -c). This is so that when users invoke this from
        # the command line, Ctrl-C will be captured by bpftrace instead of the
        # outer Python script. The temporary file can then be cleaned up by
        # the END probe in bpftrace.
        #
        # In theory, you can implement this via pty, but it is very finicky
        # and doesn't work reliably.
        # See also https://github.com/anupli/running-ng/commit/b74e3a13f56dd97f73432d8a391e1d6cd9db8663
        os.execvp("sudo", ["sudo", args.bpftrace,
                           "--unsafe", "-f", args.format, tmp.name])


if __name__ == "__main__":
    main()