brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.4 KiB · d8666e2 Raw
219 lines · python
1#!/usr/bin/env python32import argparse3import os4import re5import shlex6import subprocess7import sys8import textwrap9 10msg_prefix = "\n> NFC-Mode:"11 12def get_relevant_bolt_changes(dir: str) -> str:13    # Return a list of bolt source changes that are relevant to testing.14    all_changes = subprocess.run(15        shlex.split("git show HEAD --name-only --pretty=''"),16        cwd=dir,17        text=True,18        stdout=subprocess.PIPE,19    )20    keep_bolt = subprocess.run(21        shlex.split("grep '^bolt'"),22        input=all_changes.stdout,23        text=True,24        stdout=subprocess.PIPE,25    )26    keep_relevant = subprocess.run(27        shlex.split(28            "grep -v -e '^bolt/docs' -e '^bolt/utils/docker' -e '^bolt/utils/dot2html'"29        ),30        input=keep_bolt.stdout,31        text=True,32        stdout=subprocess.PIPE,33    )34    return keep_relevant.stdout35 36def get_git_ref_or_rev(dir: str) -> str:37    # Run 'git symbolic-ref -q --short HEAD || git rev-parse --short HEAD'38    cmd_ref = "git symbolic-ref -q --short HEAD"39    ref = subprocess.run(40        shlex.split(cmd_ref), cwd=dir, text=True, stdout=subprocess.PIPE41    )42    if not ref.returncode:43        return ref.stdout.strip()44    cmd_rev = "git rev-parse --short HEAD"45    return subprocess.check_output(shlex.split(cmd_rev), cwd=dir, text=True).strip()46 47def switch_back(48    switch_back: bool, stash: bool, source_dir: str, old_ref: str, new_ref: str49):50    # Switch back to the current revision if needed and inform the user of where51    # the HEAD is. Must be called after checking out the previous commit on all52    # exit paths.53    if switch_back:54        print(f"{msg_prefix} Switching back to current revision..")55        if stash:56            subprocess.run(shlex.split("git stash pop"), cwd=source_dir)57        subprocess.run(shlex.split(f"git checkout {old_ref}"), cwd=source_dir)58    else:59        print(60            f"The repository {source_dir} has been switched from {old_ref} "61            f"to {new_ref}. Local changes were stashed. Switch back using\n\t"62            f"git checkout {old_ref}\n"63        )64 65def main():66    parser = argparse.ArgumentParser(67        description=textwrap.dedent(68            """69            This script builds two versions of BOLT:70            llvm-bolt.new, using the current revision, and llvm-bolt.old using71            the previous revision. These can be used to check whether the72            current revision changes BOLT's functional behavior.73            """74        )75    )76    parser.add_argument(77        "build_dir",78        nargs="?",79        default=os.getcwd(),80        help="Path to BOLT build directory, default is current " "directory",81    )82    parser.add_argument(83        "--create-wrapper",84        default=False,85        action="store_true",86        help="Sets up llvm-bolt as a symlink to llvm-bolt-wrapper. Passes the options through to llvm-bolt-wrapper.",87    )88    parser.add_argument(89        "--check-bolt-sources",90        default=False,91        action="store_true",92        help="Create a marker file (.llvm-bolt.changes) if any relevant BOLT sources are modified",93    )94    parser.add_argument(95        "--switch-back",96        default=False,97        action="store_true",98        help="Checkout back to the starting revision",99    )100    parser.add_argument(101        "--cmp-rev",102        default="HEAD^",103        help="Revision to checkout to compare vs HEAD",104    )105 106    # When creating a wrapper, pass any unknown arguments to it. Otherwise, die.107    args, wrapper_args = parser.parse_known_args()108    if not args.create_wrapper and len(wrapper_args) > 0:109        parser.parse_args()110 111    # Find the repo directory.112    source_dir = None113    try:114        CMCacheFilename = f"{args.build_dir}/CMakeCache.txt"115        with open(CMCacheFilename) as f:116            for line in f:117                m = re.match(r"LLVM_SOURCE_DIR:STATIC=(.*)", line)118                if m:119                    source_dir = m.groups()[0]120        if not source_dir:121            raise Exception(f"Source directory not found: '{CMCacheFilename}'")122    except Exception as e:123        sys.exit(e)124 125    # Clean the previous llvm-bolt if it exists.126    bolt_path = f"{args.build_dir}/bin/llvm-bolt"127    if os.path.exists(bolt_path):128        os.remove(bolt_path)129 130    # Build the current commit.131    print(f"{msg_prefix} Building current revision..")132    subprocess.run(133        shlex.split("cmake --build . --target llvm-bolt"), cwd=args.build_dir134    )135 136    if not os.path.exists(bolt_path):137        sys.exit(f"Failed to build the current revision: '{bolt_path}'")138 139    # Rename llvm-bolt and memorize the old hash for logging.140    os.replace(bolt_path, f"{bolt_path}.new")141    old_ref = get_git_ref_or_rev(source_dir)142 143    if args.check_bolt_sources:144        marker = f"{args.build_dir}/.llvm-bolt.changes"145        if os.path.exists(marker):146            os.remove(marker)147        file_changes = get_relevant_bolt_changes(source_dir)148        # Create a marker file if any relevant BOLT source files changed.149        if len(file_changes) > 0:150            print(f"BOLT source changes were found:\n{file_changes}")151            open(marker, "a").close()152 153    # Determine whether a stash is needed.154    stash = subprocess.run(155        shlex.split("git status --porcelain"),156        cwd=source_dir,157        stdout=subprocess.PIPE,158        stderr=subprocess.STDOUT,159        text=True,160    ).stdout161    if stash:162        # Save local changes before checkout.163        subprocess.run(shlex.split("git stash push -u"), cwd=source_dir)164 165    # Check out the previous/cmp commit and get its commit hash for logging.166    subprocess.run(shlex.split(f"git checkout -f {args.cmp_rev}"), cwd=source_dir)167    new_ref = get_git_ref_or_rev(source_dir)168 169    # Build the previous commit.170    print(f"{msg_prefix} Building previous revision..")171    subprocess.run(172        shlex.split("cmake --build . --target llvm-bolt"), cwd=args.build_dir173    )174 175    # Rename llvm-bolt.176    if not os.path.exists(bolt_path):177        print(f"Failed to build the previous revision: '{bolt_path}'")178        switch_back(args.switch_back, stash, source_dir, old_ref, new_ref)179        sys.exit(1)180    os.replace(bolt_path, f"{bolt_path}.old")181 182    # Symlink llvm-bolt-wrapper183    if args.create_wrapper:184        print(f"{msg_prefix} Creating llvm-bolt wrapper..")185        script_dir = os.path.dirname(os.path.abspath(__file__))186        wrapper_path = f"{script_dir}/llvm-bolt-wrapper.py"187        try:188            # Set up llvm-bolt-wrapper.ini189            ini = subprocess.check_output(190                shlex.split(f"{wrapper_path} {bolt_path}.old {bolt_path}.new")191                + wrapper_args,192                text=True,193            )194            with open(f"{args.build_dir}/bin/llvm-bolt-wrapper.ini", "w") as f:195                f.write(ini)196            os.symlink(wrapper_path, bolt_path)197        except Exception as e:198            print("Failed to create a wrapper:\n" + str(e))199            switch_back(args.switch_back, stash, source_dir, old_ref, new_ref)200            sys.exit(1)201 202    switch_back(args.switch_back, stash, source_dir, old_ref, new_ref)203 204    print(205        f"{msg_prefix} Completed!\nBuild directory {args.build_dir} is ready for"206        " NFC-Mode comparison between the two revisions."207    )208 209    if args.create_wrapper:210        print(211            "Can run BOLT tests using:\n"212            "\tbin/llvm-lit -sv tools/bolt/test\nor\n"213            "\tbin/llvm-lit -sv tools/bolttests"214        )215 216 217if __name__ == "__main__":218    main()219