From 0690f5adc62e8bc867d18bc5c1af621c9296d83b Mon Sep 17 00:00:00 2001 From: Martin Bauer <martin.bauer@fau.de> Date: Wed, 29 May 2019 15:39:28 +0200 Subject: [PATCH] Added function to run compiled C benchmark code --- pystencils/kerncraft_coupling/__init__.py | 3 +- .../kerncraft_coupling/generate_benchmark.py | 79 +++++++++++++++++-- 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/pystencils/kerncraft_coupling/__init__.py b/pystencils/kerncraft_coupling/__init__.py index 33a2ed21f..7822b3b54 100644 --- a/pystencils/kerncraft_coupling/__init__.py +++ b/pystencils/kerncraft_coupling/__init__.py @@ -1,3 +1,4 @@ from .kerncraft_interface import PyStencilsKerncraftKernel, KerncraftParameters +from .generate_benchmark import generate_benchmark, run_c_benchmark -__all__ = ['PyStencilsKerncraftKernel', 'KerncraftParameters'] +__all__ = ['PyStencilsKerncraftKernel', 'KerncraftParameters', 'generate_benchmark', 'run_c_benchmark'] diff --git a/pystencils/kerncraft_coupling/generate_benchmark.py b/pystencils/kerncraft_coupling/generate_benchmark.py index 339e1bb30..f63be049a 100644 --- a/pystencils/kerncraft_coupling/generate_benchmark.py +++ b/pystencils/kerncraft_coupling/generate_benchmark.py @@ -1,4 +1,8 @@ from jinja2 import Template +import os +import subprocess +from pystencils.include import get_pystencils_include_path +from pystencils.cpu.cpujit import get_compiler_config, run_compile_step from pystencils.backends.cbackend import generate_c, get_headers from pystencils.sympyextensions import prod from pystencils.data_types import get_base_type @@ -10,6 +14,8 @@ benchmark_template = Template(""" #include <stdint.h> #include <stdbool.h> #include <math.h> +#include <stdio.h> + {{ includes }} {%- if likwid %} @@ -18,7 +24,8 @@ benchmark_template = Template(""" #define RESTRICT __restrict__ #define FUNC_PREFIX -void dummy(double *); +void dummy(void *); +void timing(double* wcTime, double* cpuTime); extern int var_false; @@ -72,19 +79,30 @@ int main(int argc, char **argv) likwid_markerStartRegion("loop"); {%- endif %} } - + + {%- if timing %} + double wcStartTime, cpuStartTime, wcEndTime, cpuEndTime; + timing(&wcStartTime, &cpuStartTime); + {%- endif %} + for (; repeat > 0; --repeat) { {{kernelName}}({{call_argument_list}}); // Dummy calls {%- for field_name, dataType, size in fields %} - if(var_false) dummy({{field_name}}); + if(var_false) dummy((void*){{field_name}}); {%- endfor %} {%- for constantName, dataType in constants %} - if(var_false) dummy(&{{constantName}}); + if(var_false) dummy((void*)&{{constantName}}); {%- endfor %} } + {%- if timing %} + timing(&wcEndTime, &cpuEndTime); + if( warmup == 0) + printf("%e\\n", (wcEndTime - wcStartTime) / atoi(argv[1]) ); + {%- endif %} + } {%- if likwid %} @@ -101,7 +119,18 @@ int main(int argc, char **argv) """) -def generate_benchmark(ast, likwid=False, openmp=False): +def generate_benchmark(ast, likwid=False, openmp=False, timing=False): + """Return C code of a benchmark program for the given kernel. + + Args: + ast: the pystencils AST object as returned by create_kernel + likwid: if True likwid markers are added to the code + openmp: relevant only if likwid=True, to generated correct likwid initialization code + timing: add timing output to the code, prints time per iteration to stdout + + Returns: + C code as string + """ accessed_fields = {f.name: f for f in ast.fields_accessed} constants = [] fields = [] @@ -135,5 +164,45 @@ def generate_benchmark(ast, likwid=False, openmp=False): 'constants': constants, 'call_argument_list': ",".join(call_parameters), 'includes': includes, + 'timing': timing, } return benchmark_template.render(**args) + + +def run_c_benchmark(ast, inner_iterations, outer_iterations=3): + """Runs the given kernel with outer loop in C + + Args: + ast: + inner_iterations: timings are recorded around this many iterations + outer_iterations: number of timings recorded + + Returns: + list of times per iterations for each outer iteration + """ + import kerncraft + + benchmark_code = generate_benchmark(ast, timing=True) + with open('bench.c', 'w') as f: + f.write(benchmark_code) + + kerncraft_path = os.path.dirname(kerncraft.__file__) + + extra_flags = ['-I' + get_pystencils_include_path(), + '-I' + os.path.join(kerncraft_path, 'headers')] + + compiler_config = get_compiler_config() + compile_cmd = [compiler_config['command']] + compiler_config['flags'].split() + compile_cmd += [*extra_flags, + os.path.join(kerncraft_path, 'headers', 'timing.c'), + os.path.join(kerncraft_path, 'headers', 'dummy.c'), + 'bench.c', + '-o', 'bench', + ] + run_compile_step(compile_cmd) + + results = [] + for _ in range(outer_iterations): + benchmark_time = float(subprocess.check_output(['./bench', str(inner_iterations)])) + results.append(benchmark_time) + return results -- GitLab