Skip to content
Snippets Groups Projects
compile_analyses.py 3.73 KiB
Newer Older
#!/usr/bin/env python3

"""
Compile all root analysis scripts under
benchmarks/<BENCHMARK>/analysis/*.cxx

Doing this step here rather than during the main benchmark script has
multiple advantages:
    1. Get feedback on syntax errors early on, without wasting compute resources
    2. Avoid race conditions for large benchmarks run in parallel
    3. Make it easier to properly handle the root build directory, as
       this has to exist prior to our attempt to compile, else all will
       fail (this is probably an old bug in root...)

Analysis scripts are expected to have extension 'cxx' and be located in the analysis
subdirectory
"""

## Our analysis path and file extension for glob
ANALYSIS_PATH=r'benchmarks/{}/analysis'
ANALYSIS_EXT = r'cxx'

import argparse
import os
from pathlib import Path

## Exceptions for this module
class Error(Exception):
    '''Base class for exceptions in this module.'''
    pass

class PathNotFoundError(Exception):
    '''Path does not exist.

    Attributes:
        path: the path name
        message: error message
    '''
    def __init__(self, path):
        self.file = file
        self.message = 'No such directory: {}'.format(file)
class NoAnalysesFoundError(Exception):
    '''Did not find any analysis scripts to complile

    Attributes:
        path: the analysis path
        message: error message
    '''
    def __init__(self, path):
        self.file = file
        self.message = 'No analysis found (extension \'{}\' in path: {}'.format(file,
                ANALYSIS_EXT)

class CompilationError(Exception):
    '''Raised when we failed to compile an analysis script

    Attributes:
        file: analysis file name
        path: analysis path
        message: error message
    '''
    def __init__(self, file):
        self.file = file
        self.message = "Analysis '{}' failed to compile".format(file)

parser = argparse.ArgumentParser()
parser.add_argument(
        'benchmark',
        help='A benchmarks for which to compile the analysis scripts.')

def compile_analyses(benchmark):
    '''Compile all analysis scripts for a benchmark.'''
    print("Compiling all analyis scripts for '{}'".format(benchmark))

    ## Ensure our build directory exists
    _init_build_dir(benchmark)

    ## Get a list of all analysis scripts
    _compile_all(benchmark)

    ## All done!
    print('All analyses for', benchmark, 'compiled successfully')

def _init_build_dir(benchmark):
    '''Initialize our ROOT build directory (if using one).'''
    print(' --> Initializing ROOT build directory ...')
    build_prefix = os.getenv('ROOT_BUILD_DIR')
    if build_prefix is None:
        print('    --> ROOT_BUILD_DIR not set, no action needed.')
        return
    ## deduce the root build directory
    pwd = os.getenv('PWD')
    build_dir = '{}/{}/{}'.format(build_prefix, pwd, ANALYSIS_PATH.format(benchmark))
    print("    --> Ensuring directory '{}' exists".format(build_dir))
    os.system('mkdir -p {}'.format(build_dir))

def _compile_all(benchmark):
    '''Compile all analysis for this benchmark.'''
    print(' --> Compiling analysis scripts')
    anadir = Path(ANALYSIS_PATH.format(benchmark))
    if not anadir.exists():
        raise PathNotFoundError(anadir)
    ana_list = []
    for file in anadir.glob('*.{}'.format(ANALYSIS_EXT)):
        ana_list.append(file)
        print('    --> Compiling:', file, flush=True)
        err = os.system(_compile_cmd(file))
        if err:
            raise CompilationError(file)
    if len(ana_list) == 0:
        raise NoAnalysesFoundError(anadir)

def _compile_cmd(file):
    '''Return a one-line shell command to compile an analysis script.'''
    return r'bash -c "root -q -b -e \".L {}+\""'.format(file)

if __name__ == "__main__":
    args = parser.parse_args()
    compile_analyses(args.benchmark)