#!/usr/bin/env python import os import platform import optparse # TODO argparse from python 2.7 on import subprocess import resource from datetime import datetime SCRIPT_VERSION="0.1" (KERNEL,HOSTNAME,KERNEL_VERSION,VERSION,ARCH,PROCESSOR) = platform.uname() assert not PROCESSOR, PROCESSOR LINUX_NAME, LINUX_VERSION, LINUX_CODENAME = platform.dist() BITSIZE = { "i686": 32, "x86_64": 64, }.get(ARCH, "unspecified for "+ARCH) # assert spec dir for subdir in "benchspec config bin result".split(): assert os.path.isdir(subdir), "subdir missing: "+subdir for filename in "shrc README LICENSE MANIFEST".split(): assert os.path.isfile(filename), "file missing: "+filename def identify_suite(): """Which SPEC suite are we in?""" for line in file("README"): possibilities = ["SPEC CPU2000", "SPEC CPU2006", "SPEC OMP2001"] if line.startswith("---"): break for p in possibilities: if p in line: return p print "Error: Unknown SPEC suite (if at all)" exit(-1) SPEC_SUITE = identify_suite() parser = optparse.OptionParser(version=SCRIPT_VERSION) parser.add_option("--config-only", action="store_true", default=False, help="Just generate config file, but do not build or run") parser.add_option("--build-only", action="store_true", default=False, help="Just generate config file and build benchmark programs, but do not run") parser.add_option("-i", "--iterations", metavar="ITR", default=3, help="Evaluate ITR iterations per program, default=3") parser.add_option("--c-compiler", metavar="CC", default="cparser", help="Use CC to build benchmark programs, default=cparser") parser.add_option("--fortran-compiler", metavar="FC", default="gfortran", help="Use FC to build benchmark programs, default=gfortran") parser.add_option("--cpp-compiler", metavar="CXX", default="g++", help="Use CXX to build benchmark programs, default=g++") parser.add_option("--compiler-args", metavar="FLAGS", default="-O3", help="Append FLAGS to build benchmark programs for all compilers, default=-O3") parser.add_option("--c-compiler-args", metavar="CFLAGS", default="", help="Append CFLAGS to build benchmark programs for C compiler, default empty") parser.add_option("--fortran-compiler-args", metavar="FFLAGS", default="", help="Append FFLAGS to build benchmark programs for Fortran compiler, default empty") parser.add_option("--cpp-compiler-args", metavar="CFLAGS", default="", help="Append CFLAGS to build benchmark programs for C++ compiler, default empty") # http://www.spec.org/cpu2006/Docs/config.html _CONFIG_HEAD = """\ #### Automatically generated by spec.py script #### output_format = csv,html,raw,screen,config ignore_errors = yes makeflags = -j4 # allows multiple simultaneous compiles test_sponsor = IPD Snelting tester_name = IPD Snelting company_name = Karlsruhe Institute of Technology KIT prepared_by = spec.py script ## just assuming: hw_fpu = Integrated sw_state = Multi-user """ class SigKill(Exception): def __init__(self, retcode, name): self.retcode = retcode self.name = name _EXIT_CODES = { -2: "keyboard interrupt", -3: "keyboard quit", -4: "illegal instruction", -6: "aborted", -8: "floating point exception", -9: "kill", -11: "segfault", -13: "broken pipe", -14: "timeout", -15: "termination", } def execute(cmd, env=None, timeout=0): """Execute a command and return stderr and/or stdout data""" preexec_fn = None if timeout > 0.0: def set_timeout(): resource.setrlimit(resource.RLIMIT_CPU, (timeout, timeout)) preexec_fn = set_timeout cmd = filter(lambda x: x, cmd.split(' ')) proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, preexec_fn = preexec_fn, env=env) out, err = proc.communicate() try: for line in out.splitlines(): yield line except Exception, e: print "'%s' -> %s" % (c, e) if proc.returncode in _EXIT_CODES: raise SigKill(proc.returncode, _EXIT_CODES[proc.returncode]) elif proc.returncode < 0: # program aborted raise Exception(proc.returncode, cmd) def path_to_filesystem(path): for line in execute("stat -f ."): if "Type:" in line: i = line.index("Type:") return line[i+6:].strip() def _get_proc_info(path): """Extract data from proc files""" data = dict() for line in file(path): try: key, value = line.split(":") except ValueError: continue data[key.strip()] = value.strip() return data def get_mem_info(): """Return data about Memory as dict""" return _get_proc_info("/proc/meminfo") def get_cpu_info(): # TODO ignores multiple cpus """Return data about CPU as dict""" return _get_proc_info("/proc/cpuinfo") def get_compiler_version(compiler): """Get the version from a compiler executable""" try: d = execute(compiler+" --version") for line in d: return line except OSError: return "No compiler '%s' found." % compiler PORTABILITY_FLAGS = dict() PORTABILITY_FLAGS[("SPEC CPU2000", "Ubuntu", 32)] = """\ 176.gcc=default=default=default: CPORTABILITY = notes003 = CPORTABILITY 176.gcc: -fno-strict-aliasing 186.crafty=default=default=default: CPORTABILITY = -DLINUX_i386 notes004 = CPORTABILITY 186.crafty: -DLINUX_i386 252.eon=default=default=default: CXXPORTABILITY = -DHAS_ERRLIST notes005 = CXXPORTABILITY 252.eon: -DHAS_ERRLIST 253.perlbmk=default=default=default: CPORTABILITY = -DSPEC_CPU2000_NEED_BOOL -DSPEC_CPU2000_LINUX_I386 notes006 = CPORTABILITY 253.perlbmk: -DSPEC_CPU2000_NEED_BOOL -DSPEC_CPU2000_LINUX_I386 254.gap=default=default=default: CPORTABILITY = -DSYS_HAS_SIGNAL_PROTO -DSYS_HAS_MALLOC_PROTO -DSYS_HAS_CALLOC_PROTO -DSYS_IS_USG -DSYS_HAS_IOCTL_PROTO -DSYS_HAS_TIME_PROTO notes007 = CPORTABILITY 254.gap: -DSYS_HAS_SIGNAL_PROTO -DSYS_HAS_MALLOC_PROTO -DSYS_HAS_CALLOC_PROTO -DSYS_IS_USG -DSYS_HAS_IOCTL_PROTO -DSYS_HAS_TIME_PROTO 255.vortex=default=default=default: CPORTABILITY = -fno-strict-aliasing notes008 = CPORTABILITY 255.vortex: -fno-strict-aliasing 187.facerec=default=default=default: EXTRA_FFLAGS= -I../src """ PORTABILITY_FLAGS[("SPEC CPU2006", "Ubuntu", 32)] = """\ 400.perlbench=default=default=default: CPORTABILITY= -DSPEC_CPU_LINUX_IA32 462.libquantum=default=default=default: CPORTABILITY= -DSPEC_CPU_LINUX 483.xalancbmk=default=default=default: CXXPORTABILITY= -DSPEC_CPU_LINUX 481.wrf=default=default=default: CPORTABILITY = -DSPEC_CPU_CASE_FLAG -DSPEC_CPU_LINUX """ PORTABILITY_FLAGS[("SPEC CPU2006", "Ubuntu", 64)] = """\ default=base=default=default: PORTABILITY = -DSPEC_CPU_LP64 400.perlbench=default=default=default: CPORTABILITY = -DSPEC_CPU_LINUX_X64 462.libquantum=default=default=default: CPORTABILITY= -DSPEC_CPU_LINUX 483.xalancbmk=default=default=default: CXXPORTABILITY= -DSPEC_CPU_LINUX 481.wrf=default=default=default: CPORTABILITY = -DSPEC_CPU_CASE_FLAG -DSPEC_CPU_LINUX """ def get_portability(): """Get necessary portability flags""" contents = ["\n\n#### Portability Flags ####"] for (suite,os,bitsize),text in PORTABILITY_FLAGS.items(): if suite != SPEC_SUITE: continue if os != LINUX_NAME: continue if bitsize != BITSIZE: continue contents.append(text) return "\n".join(contents) def generate_spec_config(options): """Generate a config file for SPEC""" contents = [_CONFIG_HEAD] cpuinfo = get_cpu_info() meminfo = get_mem_info() if options.build_only: contents.append("action = build") else: contents.append("action = validate") # includes run contents.append("iterations = %d" % options.iterations) contents.append("test_date = %s" % datetime.now()) contents.append("") contents.append("sw_os = %s %s %s" % (LINUX_NAME, LINUX_VERSION, LINUX_CODENAME)) contents.append("sw_compiler1 = %s" % get_compiler_version(options.c_compiler)) contents.append("sw_compiler2 = %s" % get_compiler_version(options.cpp_compiler)) contents.append("sw_compiler3 = %s" % get_compiler_version(options.fortran_compiler)) contents.append("sw_file = %s" % path_to_filesystem(".")) contents.append("sw_base_ptrsize = %d-bit" % BITSIZE) contents.append("sw_peak_ptrsize = %d-bit" % BITSIZE) contents.append("") chips = (1+int(cpuinfo["processor"])) cores_per_chip = int(cpuinfo["cpu cores"]) cores = cores_per_chip * chips if SPEC_SUITE == "SPEC CPU2006": contents.append("hw_cpu_name = %s" % cpuinfo["model name"]) contents.append("hw_ncores = %d" % cores) elif SPEC_SUITE == "SPEC CPU2000": contents.append("hw_model = %s" % cpuinfo["model name"]) contents.append("hw_ncpu = %d" % cores) contents.append("hw_cpu_mhz = %s" % cpuinfo["cpu MHz"]) contents.append("hw_nchips = %d" % chips) contents.append("hw_ncoresperchip = %d" % cores_per_chip) contents.append("hw_vendor = %s" % cpuinfo["vendor_id"]) contents.append("hw_memory = %s" % meminfo["MemTotal"]) contents.append("hw_pcache = %s" % cpuinfo["cache size"]) contents.append("") contents.append("CC = %s" % options.c_compiler) contents.append("CXX = %s" % options.cpp_compiler) contents.append("FC = %s" % options.fortran_compiler) contents.append("") contents.append("OPTIMIZE = %s" % options.compiler_args) contents.append("notes_comp_001 OPTIMIZE = %s" % options.compiler_args) contents.append("COPTIMIZE = %s" % options.c_compiler_args) contents.append("notes_comp_002 COPTIMIZE = %s" % options.c_compiler_args) contents.append("CXXOPTIMIZE = %s" % options.cpp_compiler_args) contents.append("notes_comp_003 CXXOPTIMIZE = %s" % options.cpp_compiler_args) contents.append("FOPTIMIZE = %s" % options.fortran_compiler_args) contents.append("notes_comp_004 FOPTIMIZE = %s" % options.fortran_compiler_args) contents.append(get_portability()) return "\n".join(contents) if __name__ == "__main__": (options, args) = parser.parse_args() conf = generate_spec_config(options) with open("config/generated.cfg", 'w') as fh: fh.write(conf) if options.config_only: exit(0) cmd = "env bash -l -c 'source shrc && runspec all -c generated'" os.system(cmd)