diff -r 8a9b86071c15 perf.py --- a/perf.py Fri Dec 04 14:15:34 2015 -0800 +++ b/perf.py Wed Feb 03 14:46:01 2016 +0100 @@ -88,6 +88,30 @@ except ImportError: info = logging.info +def check_taskset(): + """Check the taskset command is available. + + Taskset specifies CPU affinity for a given workload, meaning that we can + run the benchmarks on a given core to minimize run to run variation. + + Return None on success. Return an error message on error. + """ + with open(os.devnull, "wb") as dev_null: + # Try to pin a temporary Python process to CPU #0 + command = ["taskset", "--cpu-list", "0", + sys.executable, "-c", "pass"] + try: + exitcode = subprocess.call(command, + stdout=dev_null, stderr=dev_null) + except OSError as exc: + return ("Command taskset not found: %s" % exc) + + if exitcode != 0: + return ("Command taskset failed with exit code %s" % exitcode) + + return None + + def interpreter_version(python, _cache={}): """Return the interpreter version for the given Python interpreter. *python* is the base command (as a list) to execute the interpreter. @@ -2557,6 +2581,11 @@ def main(argv, bench_funcs=BENCH_FUNCS, " Unladen Swallow binaries. This is useful for" " examining many benchmarks for optimization" " effects.")) + parser.add_option("--affinity", metavar="CPU_LIST", default=None, + help=("Specify CPU affinity for benchmark runs. This " + "way, benchmarks can be forced to run on a given " + "CPU to minimize run to run variation. This uses " + "the taskset command.")) options, args = parser.parse_args(argv) @@ -2575,6 +2604,17 @@ def main(argv, bench_funcs=BENCH_FUNCS, base_cmd_prefix = [base] + base_args changed_cmd_prefix = [changed] + changed_args + if options.affinity: + err_msg = check_taskset() + if not err_msg: + taskset_prefix = ["taskset", "--cpu-list", options.affinity] + base_cmd_prefix = taskset_prefix + base_cmd_prefix + changed_cmd_prefix = taskset_prefix + changed_cmd_prefix + else: + print("WARNING: Option --affinity not available. %s" % err_msg, + file=sys.stderr) + print(file=sys.stderr) + logging.basicConfig(level=logging.INFO) if options.track_memory: