Skip to content
Snippets Groups Projects
Commit d651eb54 authored by René Heß's avatar René Heß
Browse files

Merge branch 'feature/pandas-integration' into 'master'

Feature/pandas integration

Add a script that allows to calculates performance regressions

See merge request !24
parents b77b460a d402b204
No related branches found
No related tags found
No related merge requests found
dune_symlink_to_source_files(FILES make_graph.sh)
dune_symlink_to_source_files(FILES make_graph.sh
performance_regression.py
)
#!/usr/bin/env python
import pandas
import subprocess
import sys
class color:
GREEN = '\033[92m'
RED = '\033[91m'
ENDC = '\033[0m'
def parse_data():
frame = pandas.read_csv('timings.csv', header=None, names=('exec', 'kernel', 'time'), delimiter=' ')
data = frame.groupby(('exec', 'kernel'))['time'].min()
return data
def run():
subprocess.call("make -j2 build_tests".split())
subprocess.call("rm timings.csv".split())
for i in range(10):
subprocess.call("ctest".split())
def regression_summary():
# Get timings
run()
data1 = parse_data()
# Switch to reference data
subprocess.call(sys.argv[1:], shell=True)
# Get reference timings
run()
data2 = parse_data()
for key in data1.keys():
exe, kernel = key
diff = data1[exe][kernel] - data2[exe][kernel]
rel = abs(diff / data2[exe][kernel])
s = exe + '/' + kernel + ': ' + str(rel)
c = ''
if rel > 0.02:
if diff > 0.:
c = color.RED
else:
c = color.GREEN
print(c + s + color.ENDC)
if __name__ == '__main__':
regression_summary()
......@@ -103,6 +103,7 @@ function(add_generated_executable)
add_custom_command(OUTPUT ${GEN_OPERATOR} ${GEN_DRIVER}
COMMAND ${CMAKE_BINARY_DIR}/dune-env-2 ufl2pdelab
--project-basedir ${CMAKE_BINARY_DIR}
--operator-file ${GEN_OPERATOR}
--driver-file ${GEN_DRIVER}
${GEN_FORM_COMPILER_ARGS}
......
......@@ -49,7 +49,7 @@ function(dune_add_formcompiler_system_test)
add_generated_executable(TARGET ${tname}
UFLFILE ${SYSTEMTEST_UFLFILE}
FORM_COMPILER_ARGS --ini-file ${inifile}
FORM_COMPILER_ARGS --ini-file ${inifile} --timer
)
# Exclude the target from all
......
......@@ -72,13 +72,11 @@
#ifdef ENABLE_COUNTER
#define DUMP_TIMER(name,os,reset) \
os << "===== " #name " =====" << std::endl; \
os << "elapsed: " << HP_TIMER_ELAPSED(name) << std::endl; \
os << exec << " " << #name << " " << HP_TIMER_ELAPSED(name) << std::endl; \
HP_TIMER_OPCOUNTERS(name).reportOperations(os,reset);
#define DUMP_AND_ACCUMULATE_TIMER(name,os,reset,time,ops) \
os << "===== " #name " =====" << std::endl; \
os << "elapsed: " << HP_TIMER_ELAPSED(name) << std::endl; \
os << exec << " " << #name << " " << HP_TIMER_ELAPSED(name) << std::endl; \
time += HP_TIMER_ELAPSED(name); \
ops += HP_TIMER_OPCOUNTERS(name); \
HP_TIMER_OPCOUNTERS(name).reportOperations(os,reset);
......@@ -86,13 +84,11 @@
#elif defined ENABLE_HP_TIMERS
#define DUMP_TIMER(name,os,reset) \
os << "===== " #name " =====" << std::endl; \
os << "elapsed: " << HP_TIMER_ELAPSED(name) << std::endl; \
os << exec << " " << #name << " " << HP_TIMER_ELAPSED(name) << std::endl; \
if (reset) HP_TIMER_RESET(name);
#define DUMP_AND_ACCUMULATE_TIMER(name,os,reset,time,ops) \
os << "===== " #name " =====" << std::endl; \
os << "elapsed: " << HP_TIMER_ELAPSED(name) << std::endl; \
os << exec << " " << #name << " " << HP_TIMER_ELAPSED(name) << std::endl; \
time += HP_TIMER_ELAPSED(name); \
if (reset) HP_TIMER_RESET(name);
......
......@@ -22,10 +22,10 @@ def post_include(post, filetag=None, pre_include=True):
return gen(post)
def include_file(include, filetag=None):
def include_file(include, filetag=None, system=False):
assert filetag
from cgen import Include
gen = generator_factory(on_store=lambda i: Include(i), item_tags=("file", filetag, "include"), no_deco=True)
gen = generator_factory(on_store=lambda i: Include(i, system=system), item_tags=("file", filetag, "include"), no_deco=True)
return gen(include)
......@@ -82,7 +82,8 @@ def dump_accumulate_timer(name):
from dune.perftool.pdelab.localoperator import (name_time_dumper_os,
name_time_dumper_reset,
name_time_dumper_t,
name_time_dumper_counter)
name_time_dumper_counter,
name_time_dumper_exec,)
os = name_time_dumper_os()
reset = name_time_dumper_reset()
t = name_time_dumper_t()
......
......@@ -33,9 +33,9 @@ def get_form_compiler_arguments():
parser.add_argument("--print-transformations", action="store_true", help="print out dot files after ufl tree transformations")
parser.add_argument("--print-transformations-dir", type=str, help="place where to put dot files (can be omitted)")
parser.add_argument("--diagonal-transformation-matrix", action="store_true", help="set option if the jacoby of the transformation is diagonal (axiparallel grids)")
parser.add_argument("--ini-file", type=str, help="An inifile to use. A generated driver will be hard-coded to it, a [formcompiler] section will be usd as default values to form compiler arguments (use snake case)")
# The following option is no-op (because it is set by default), but we may want to remove that default in the future.
parser.add_argument("--timer", action="store_true", help="measure times", default=True)
parser.add_argument("--ini-file", type=str, help="An inifile to use. A generated driver will be hard-coded to it, a [formcompiler] section will be used as default values to form compiler arguments (use snake case)")
parser.add_argument("--timer", action="store_true", help="measure times")
parser.add_argument("--project-basedir", type=str, help="The base (build) directory of the dune-perftool project")
# Modify the positional argument to not be a list
args = vars(parser.parse_args())
......
......@@ -1103,6 +1103,24 @@ def name_explicitonestepmethod():
return "eosm"
@preamble
def define_timing_stream(name):
include_file('fstream', filetag='driver', system=True)
import os
tfile = os.path.join(get_option('project_basedir'), 'timings.csv')
return ["std::ofstream {};".format(name),
"{}.open(\"{}\", std::ios_base::app);".format(name, tfile),
]
@symbol
def name_timing_stream():
name = "timestream"
define_timing_stream(name)
return name
@preamble
def dune_solve():
# Test if form is linear in ansatzfunction
......@@ -1143,17 +1161,14 @@ def dune_solve():
print_times = []
for formdata in formdatas:
lop_name = name_localoperator(formdata)
print_times.append("{}.dump_timers(std::cout, true);".format(lop_name))
timestream = name_timing_stream()
print_times.append("{}.dump_timers({}, argv[0], true);".format(lop_name, timestream))
solve = ["HP_TIMER_START(total);",
"{}".format(solve),
"HP_TIMER_STOP(total);",
"",
"// Print timer results",
"std::cout << std::endl;",
"std::cout << \"=== Time for calling solve method ===\" << std::endl;",
"DUMP_TIMER({},{},{});".format('total', 'std::cout', 'true'),
"std::cout << std::endl;"
"std::cout << \"=== {} ===\" << std::endl;".format(lop_name)]
"char* exec = argv[0];"
"DUMP_TIMER(total, {}, true);".format(timestream),
]
solve.extend(print_times)
return solve
......
......@@ -306,13 +306,18 @@ def name_time_dumper_counter():
return "counter"
def name_time_dumper_exec():
return "exec"
class TimerMethod(ClassMember):
def __init__(self):
os = name_time_dumper_os()
reset = name_time_dumper_reset()
t = name_time_dumper_t()
ex = name_time_dumper_exec()
content = ["template <typename Stream>",
"void dump_timers(Stream& {}, bool {})".format(os, reset),
"void dump_timers(Stream& {}, char* {}, bool {})".format(os, ex, reset),
"{",
" double {} = 0.0;".format(t),
"#ifdef ENABLE_COUNTERS",
......@@ -322,9 +327,7 @@ class TimerMethod(ClassMember):
""]
dump_timers = [i for i in retrieve_cache_items(condition='dump_timers')]
content.extend(map(lambda x: ' ' + x, dump_timers))
content.extend([" {} <<\"===== all_kernels =====\" << std::endl".format(os),
" <<\"elapsed: \" << {} << std::endl;".format(t),
"#ifdef ENABLE_COUNTERS",
content.extend(["#ifdef ENABLE_COUNTERS",
" counter.reportOperations({});".format(os),
"#endif"])
content.append("}")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment