#!/usr/bin/env python import os import platform import optparse # TODO argparse from python 2.7 on import subprocess import resource import socket from datetime import datetime SCRIPT_VERSION="0.1" AUTHOR="Andreas Zwinkau " (KERNEL,HOSTNAME,KERNEL_VERSION,VERSION,HOST_ARCH,PROCESSOR) = platform.uname() LINUX_NAME, LINUX_VERSION, LINUX_CODENAME = platform.dist() BITSIZE = { "i686": 32, "x86_64": 64, "sparc" : 32, "sparc64": 64, }.get(HOST_ARCH, "unspecified for "+HOST_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, usage="Usage: %prog [options] [programs]") 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("--no-cpp", action="store_true", default=False, help="Exclude benchmark programs using C++") parser.add_option("--no-fortran", action="store_true", default=False, help="Exclude benchmark programs using Fortran") parser.add_option("--no-floating-point", action="store_true", default=False, help="Exclude CFP subset containing floating point-heavy benchmark programs") parser.add_option("--no-integer", action="store_true", default=False, help="Exclude CINT subset containing integer-heavy benchmark programs") parser.add_option("--no-medium", action="store_true", default=False, help="Exclude OMPM programs") parser.add_option("--no-large", action="store_true", default=False, help="Exclude OMPL programs") parser.add_option("-i", "--iterations", metavar="ITR", default=3, help="Evaluate ITR iterations per program, default=3") parser.add_option("--time-limit", metavar="TIMELIMIT", default=0, help="Set cpu time limit for each program run to TIMELIMIT seconds.") parser.add_option("--target-architecture", metavar="TARGET_ARCH", default=HOST_ARCH, help="Set target architecture, default=" + HOST_ARCH) parser.add_option("--c-compiler", metavar="CC", default="gcc", help="Use CC to build benchmark programs, default=gcc") 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="-march=native", help="Append CFLAGS to build benchmark programs for C compiler, default march=native") 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="-march=native", help="Append CFLAGS to build benchmark programs for C++ compiler, default march=native") 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 # Target architecture-dependent flags TARGET_ARCH_FLAGS = dict() i686_flags = dict() i686_flags["186.crafty"] = "-DLINUX_i386" i686_flags["253.perlbmk"] = "-DSPEC_CPU2000_LINUX_I386" i686_flags["400.perlbench"] = "-DSPEC_CPU_LINUX_IA32" i686_flags["403.gcc"] = "-DSPEC_CPU_LINUX_IA32" TARGET_ARCH_FLAGS["i686"] = i686_flags sparc_flags = dict() sparc_flags["176.gcc"] = "-DHOST_WORDS_BIG_ENDIAN" sparc_flags["186.crafty"] = "-DLINUX_SPARC" sparc_flags["253.perlbmk"] = "-DSPEC_CPU2000_LINUX_SPARC" TARGET_ARCH_FLAGS["sparc"] = sparc_flags # Compiler-dependent flags COMPILER_FLAGS = dict() cparser_flags = dict() cparser_flags["176.gcc"] = "-std=gnu89" cparser_flags["403.gcc"] = "-std=gnu89 -fno-if-conversion" COMPILER_FLAGS["cparser"] = cparser_flags # Compatibility/SPEC-specific flags, always needed compat_flags = dict() compat_flags["176.gcc"] = "-fno-strict-aliasing" compat_flags["252.eon"] = "-DHAS_ERRLIST" compat_flags["253.perlbmk"] = "-DSPEC_CPU2000_NEED_BOOL" compat_flags["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" compat_flags["255.vortex"] = "-fno-strict-aliasing" compat_flags["462.libquantum"] = "-DSPEC_CPU_LINUX" compat_flags["481.wrf"] = "-DSPEC_CPU_CASE_FLAG -DSPEC_CPU_LINUX" compat_flags["483.xalancbmk"] = "-DSPEC_CPU_LINUX" # Fortran stuff compat_flags["187.facerec"] = "-I../src" compat_flags["310.wupwise_m"] = "-ffixed-form" compat_flags["312.swim_m"] = "-ffixed-form" compat_flags["314.mgrid_m"] = "-ffixed-form" compat_flags["316.applu_m"] = "-ffixed-form" compat_flags["318.galgel_m"] = "-ffixed-form -ffixed-line-length-80" compat_flags["324.apsi_m"] = "-ffixed-form" compat_flags["326.gafort_m"] = "-qsuffix=f=f90" compat_flags["328.fma3d_m"] = "-qsuffix=f=f90" COMPATIBILITY_FLAGS = compat_flags BENCHMARK_PROPERTIES = [ ("SPEC CPU2000", "CINT", "164.gzip", "c"), ("SPEC CPU2000", "CINT", "175.vpr", "c"), ("SPEC CPU2000", "CINT", "176.gcc", "c"), ("SPEC CPU2000", "CINT", "181.mcf", "c"), ("SPEC CPU2000", "CINT", "186.crafty", "c"), ("SPEC CPU2000", "CINT", "197.parser", "c"), ("SPEC CPU2000", "CINT", "252.eon", "cpp"), ("SPEC CPU2000", "CINT", "253.perlbmk", "c"), ("SPEC CPU2000", "CINT", "254.gap", "c"), ("SPEC CPU2000", "CINT", "255.vortex", "c"), ("SPEC CPU2000", "CINT", "256.bzip2", "c"), ("SPEC CPU2000", "CINT", "300.twolf", "c"), ("SPEC CPU2000", "CFP", "168.wupwise", "fortran77"), ("SPEC CPU2000", "CFP", "171.swim", "fortran77"), ("SPEC CPU2000", "CFP", "172.mgrid", "fortran77"), ("SPEC CPU2000", "CFP", "173.applu", "fortran77"), ("SPEC CPU2000", "CFP", "177.mesa", "c"), ("SPEC CPU2000", "CFP", "178.galgel", "fortran90"), ("SPEC CPU2000", "CFP", "179.art", "c"), ("SPEC CPU2000", "CFP", "183.equake", "c"), ("SPEC CPU2000", "CFP", "187.facerec", "fortran90"), ("SPEC CPU2000", "CFP", "188.ammp", "c"), ("SPEC CPU2000", "CFP", "189.lucas", "fortran90"), ("SPEC CPU2000", "CFP", "191.fma3d", "fortran90"), ("SPEC CPU2000", "CFP", "200.sixtrack", "fortran77"), ("SPEC CPU2000", "CFP", "301.apsi", "fortran77"), ("SPEC OMP2001", "?", "310.wupwise_m", "?"), ("SPEC OMP2001", "?", "311.wupwise_l", "?"), ("SPEC OMP2001", "?", "312.swim_m", "?"), ("SPEC OMP2001", "?", "313.swim_l", "?"), ("SPEC OMP2001", "?", "314.mgrid_m", "?"), ("SPEC OMP2001", "?", "315.mgrid_l", "?"), ("SPEC OMP2001", "?", "316.applu_m", "?"), ("SPEC OMP2001", "?", "317.applu_l", "?"), ("SPEC OMP2001", "?", "318.galgel_m", "?"), ("SPEC OMP2001", "?", "330.art_m", "?"), ("SPEC OMP2001", "?", "331.art_l", "?"), ("SPEC OMP2001", "?", "320.equake_m", "?"), ("SPEC OMP2001", "?", "321.equake_l", "?"), ("SPEC OMP2001", "?", "332.ammp_m", "?"), ("SPEC OMP2001", "?", "328.fma3d_m", "?"), ("SPEC OMP2001", "?", "329.fma3d_l", "?"), ("SPEC OMP2001", "?", "324.apsi_m", "?"), ("SPEC OMP2001", "?", "325.apsi_l", "?"), ("SPEC OMP2001", "?", "326.gafort_m", "?"), ("SPEC OMP2001", "?", "327.gafort_l", "?"), ("SPEC CPU2006", "CINT", "400.perlbench", "c"), ("SPEC CPU2006", "CINT", "401.bzip2", "c"), ("SPEC CPU2006", "CINT", "403.gcc", "c"), ("SPEC CPU2006", "CINT", "429.mcf", "c"), ("SPEC CPU2006", "CINT", "445.gobmk", "c"), ("SPEC CPU2006", "CINT", "456.hmmer", "c"), ("SPEC CPU2006", "CINT", "458.sjeng", "c"), ("SPEC CPU2006", "CINT", "462.libquantum", "c"), ("SPEC CPU2006", "CINT", "464.h264ref", "c"), ("SPEC CPU2006", "CINT", "471.omnetpp", "cpp"), ("SPEC CPU2006", "CINT", "473.astar", "cpp"), ("SPEC CPU2006", "CINT", "483.xalancbmk", "cpp"), ("SPEC CPU2006", "CFP", "410.bwaves", "fortran"), ("SPEC CPU2006", "CFP", "416.gamess", "fortran"), ("SPEC CPU2006", "CFP", "433.milc", "c"), ("SPEC CPU2006", "CFP", "434.zeusmp", "fortran"), ("SPEC CPU2006", "CFP", "435.gromacs", "c,fortran"), ("SPEC CPU2006", "CFP", "436.cactusADM", "c,fortran"), ("SPEC CPU2006", "CFP", "437.leslie3d", "fortran"), ("SPEC CPU2006", "CFP", "444.namd", "cpp"), ("SPEC CPU2006", "CFP", "447.dealII", "cpp"), ("SPEC CPU2006", "CFP", "450.soplex", "cpp"), ("SPEC CPU2006", "CFP", "453.povray", "cpp"), ("SPEC CPU2006", "CFP", "454.calculix", "c,fortran"), ("SPEC CPU2006", "CFP", "459.GemsFDTD", "fortran"), ("SPEC CPU2006", "CFP", "465.tonto", "fortran"), ("SPEC CPU2006", "CFP", "470.lbm", "c"), ("SPEC CPU2006", "CFP", "481.wrf", "c,fortran"), ("SPEC CPU2006", "CFP", "482.sphinx3", "c"), ] def filter_progs(options,args): if args: programs = list() for progt in BENCHMARK_PROPERTIES: suite, subset, prog, langs = progt if prog in args: programs.append(progt) else: programs = BENCHMARK_PROPERTIES for suite, subset, prog, langs in programs: if suite != SPEC_SUITE: continue if options.no_cpp and "cpp" in langs: continue if options.no_fortran and "fortran" in langs: continue if options.no_floating_point and subset == "CFP": continue if options.no_integer and subset == "CINT": continue if options.no_medium and prog.endswith("_m"): continue if options.no_large and prog.endswith("_l"): continue yield prog # 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 setprocgroup = yes ignore_sigint = no 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 """ def get_portability(options, prog, lang): if lang == "c": port = "CPORTABILITY" compiler = os.path.basename(options.c_compiler) elif lang == "cpp": port = "CXXPORTABILITY" compiler = os.path.basename(options.cpp_compiler) # Currently no real handling of multi-language benchmarks elif "fortran" in lang: port = "FPORTABILITY" compiler = os.path.basename(options.fortran_compiler) else: print "Unknown benchmark language: ", lang exit(1) target_arch = options.target_architecture compat_flags = COMPATIBILITY_FLAGS.get(prog, "") if not TARGET_ARCH_FLAGS.has_key(target_arch): print "No architecture-dependent flags defined for architecture '%s'" % target_arch exit(1) target_flags = TARGET_ARCH_FLAGS[target_arch].get(prog, "") compiler_flags = "" for comp in COMPILER_FLAGS: if comp in compiler: # Also allow stuff like sparc-leon-linux-gnu-gcc or cparser-test compiler_flags = COMPILER_FLAGS[comp].get(prog, "") break flags = ' '.join(filter(None, [compat_flags, target_flags, compiler_flags])) if flags == '': return None return "%s = %s" % (port, flags) def check_options(options): # Convenience: always compile to 32-bit x86 code with cparser target_x86 = options.target_architecture == "i686" or options.target_architecture == "x86_64" is_cparser = "cparser" in options.c_compiler if HOST_ARCH == "x86_64" and is_cparser and target_x86 and not ("-m32" in options.c_compiler_args): options.target_architecture = "i686" def generate_spec_config(options, progs): """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" % int(options.iterations)) if SPEC_SUITE != "SPEC CPU2006": 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("machine_name = %s" % socket.getfqdn()) assert int(BITSIZE), "bitsize is "+BITSIZE contents.append("sw_base_ptrsize = %d-bit" % BITSIZE) contents.append("sw_peak_ptrsize = %d-bit" % BITSIZE) contents.append("") chips = (1+int(cpuinfo.get("processor", 0))) cores_per_chip = int(cpuinfo.get("cpu cores", cpuinfo.get("cpu cores", 1))) 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.get("cpu MHz", "?")) contents.append("hw_nchips = %d" % chips) contents.append("hw_ncoresperchip = %d" % cores_per_chip) contents.append("hw_vendor = %s" % cpuinfo.get("vendor_id", "?")) contents.append("hw_memory = %s" % meminfo["MemTotal"]) contents.append("hw_pcache = %s" % cpuinfo.get("cache size", "?")) contents.append("") time_limit = int(options.time_limit) if time_limit != 0: contents.append("use_submit_for_speed = 1") contents.append("submit =ulimit -t %d ; $command" % time_limit) 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) if HOST_ARCH == "x86_64" and options.target_architecture == "i686": contents.append("EXTRA_CFLAGS = -m32") contents.append("EXTRA_LDFLAGS = -m32") # Enforce big-endian for SPARC if options.target_architecture == "sparc": contents.append("\nendian = 4321") notes = 0 contents.append("\n\n#### Portability flags ####") for (suite, subset, prog, lang) in BENCHMARK_PROPERTIES: if prog in progs: port = get_portability(options, prog, lang) if port is not None: contents.append(prog + "=default=default=default:") contents.append(port) contents.append("notes%03d = %s: %s" % (notes, prog, port)) notes = notes + 1 return "\n".join(contents) if __name__ == "__main__": (options, args) = parser.parse_args() check_options(options) progs = [prog for prog in filter_progs(options, args)] conf = generate_spec_config(options, progs) fh = open("config/generated.cfg", 'w') fh.write(conf) fh.close() if options.config_only: exit(0) strprogs = " ".join(progs) cmd = "env bash -l -c 'source shrc && runspec %s -c generated'" % strprogs exit(os.system(cmd))