Peano
Loading...
Searching...
No Matches
Runner.py
Go to the documentation of this file.
1# This file is part of the Peano project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
4
5
6TEMPLATE_RUNNER_HEADER_FILE = """
7// This file is part of the ExaHyPE2 project. For conditions of distribution and
8// use, please see the copyright notice at www.peano-framework.org
9#pragma once
10
11#include "peano4/RunMultipleSteps.h"
12
13{% for item in NAMESPACE -%}
14namespace {{ item }} {
15{%- endfor %}
16 class {{CLASSNAME}};
17{% for item in NAMESPACE -%}
18}
19{%- endfor %}
20
21
22class {{NAMESPACE | join("::")}}::{{CLASSNAME}}: public peano4::RunMultipleSteps {
23 public:
24 {{CLASSNAME}}();
25
26 virtual void run() override;
27 private:
28 static tarch::logging::Log _log;
29};
30"""
31
32TEMPLATE_RUNNER_CPP_FILE = """
33#include "{{CLASSNAME}}.h"
34
35#include "{{SUBDIRECTORY}}repositories/StepRepository.h"
36#include "tarch/Assertions.h"
37#include "tarch/logging/LogFilter.h"
38#include "peano4/parallel/Node.h"
39#include "peano4/parallel/SpacetreeSet.h"
40
41{% for observer in OBSERVERS -%}
42#include "{{SUBDIRECTORY}}observers/{{observer}}.h"
43{% endfor %}
44
45tarch::logging::Log {{NAMESPACE | join("::")}}::{{CLASSNAME}}::_log( "{{NAMESPACE | join("::")}}::{{CLASSNAME}}" );
46
47{{NAMESPACE | join("::")}}::{{CLASSNAME}}::{{CLASSNAME}}():
48 peano4::RunMultipleSteps(
49 "{{CLASSNAME}}",
50 {{PROJECT_NAMESPACE | join("::")}}::{{SUBNAMESPACE}}repositories::StepRepository::toProgramStep(
51 {{PROJECT_NAMESPACE | join("::")}}::{{SUBNAMESPACE}}repositories::StepRepository::Steps::{{FIRST_STEP}}
52 )
53 ) {
54}
55
56
57void {{NAMESPACE | join("::")}}::{{CLASSNAME}}::run() {
58 _watch.start();
59 {% for step in STEPS %}
60 {% if loop.index0==0 %}
61 // The caller already had to set Node's program step to this, our very
62 // first step, before it could even decide to invoke run() on us in the
63 // first place (@see getFirstSubstep()) - so this is redundant, and we
64 // only assert on it instead of setting it again.
65 assertionEquals(
66 peano4::parallel::Node::getInstance().getCurrentProgramStep(),
67 {{PROJECT_NAMESPACE | join("::")}}::{{SUBNAMESPACE}}repositories::StepRepository::toProgramStep(
68 {{PROJECT_NAMESPACE | join("::")}}::{{SUBNAMESPACE}}repositories::StepRepository::Steps::{{step}}
69 )
70 );
71 {% else %}
72 peano4::parallel::Node::getInstance().setNextProgramStep(
73 {{PROJECT_NAMESPACE | join("::")}}::{{SUBNAMESPACE}}repositories::StepRepository::toProgramStep(
74 {{PROJECT_NAMESPACE | join("::")}}::{{SUBNAMESPACE}}repositories::StepRepository::Steps::{{step}}
75 )
76 );
77 {% endif %}
78 do {
79 tarch::logging::LogFilter::getInstance().switchProgramPhase("{{step}}");
80 {{PROJECT_NAMESPACE | join("::")}}::{{SUBNAMESPACE}}observers::{{OBSERVERS[loop.index0]}}::prepareTraversal();
81 {{PROJECT_NAMESPACE | join("::")}}::{{SUBNAMESPACE}}observers::{{OBSERVERS[loop.index0]}} observer;
82 peano4::parallel::SpacetreeSet::getInstance().traverse(observer);
83 {{PROJECT_NAMESPACE | join("::")}}::{{SUBNAMESPACE}}observers::{{OBSERVERS[loop.index0]}}::unprepareTraversal();
84 logDebug( "run()", "will rerun this step: {{REPEAT_CONDITIONS[loop.index0] or "false"}}=" << {{REPEAT_CONDITIONS[loop.index0] or "false"}} );
85 }
86 while ( {{REPEAT_CONDITIONS[loop.index0] or "false"}} );
87 {% endfor %}
88 _watch.stop();
89 _runtimeMeasurement.setValue(_watch.getCalendarTime());
90}
91"""
92
93
94def create_runner(peano_project, identifier, steps):
95 """!
96
97 Create the header/implementation file pair that represents one of a
98 project's algorithmic phases represented by a sequence of steps.
99 It yields one class of the classname identifier which is held in
100 the project's runners subdirectory/namespace. This class holds
101 exactly one method run() which toggles through the steps one by one.
102
103 Even though the runner seems to accept only a sequence of steps
104 (which are members of @ref peano4.api.solversteps), the runner
105 belongs into the task graph repository, as it assumes that each
106 step has a field has_to_repeat. This field is not defined within
107 @ref peano4.api.solversteps.Step. It is something graph compilers
108 add to the data model. Consult the compiler description in
109 @ref peano4.api.taskgraph.compiler.
110
111 peano_project: peano4.api.Project
112 The Peano 4 project to add the generated files to.
113
114 identifier: str
115 Same identifier used for the phase's Observers, e.g.
116 "SetupSimulation", "TimeStep", "Plot".
117
118 steps: [peano4.api.solversteps.Step]
119 The sequence of Observers realising this algorithmic phase, in the
120 order compiled from the phase's task graph (@see
121 peano4.api.taskgraph.compiler.Sequential.translate). Its first
122 element's name is the repositories::StepRepository::Steps enumerator
123 the generated runner hands to peano4::RunMultipleSteps's constructor
124 to kick the phase off. run() instantiates each step's Observer in
125 turn and traverses the spacetree set with it, switching the log
126 filter's program phase beforehand, bracketing the traversal itself
127 with that Observer's own static prepareTraversal()/
128 unprepareTraversal() (@see peano4.api.output.Observer - the spacetree
129 set never calls these itself, so the runner is exactly the "up to
130 the user" call site its own doc comment asks for), and timing the
131 traversal via the inherited _watch/_runtimeMeasurement. "Undef" (and
132 no traversals at all) if the phase has no steps, e.g. no solver
133 contributed to it, so the generated code still compiles.
134
135 Before every step but the first, run() also calls
136 peano4::parallel::Node::getInstance().setNextProgramStep(...) with
137 that step's own program step - whoever calls run() in the first
138 place already had to set Node's program step to this phase's first
139 step beforehand (@see getFirstSubstep(), used exactly that way in
140 exahype2.api.generators.DefaultSimulationMain), so run() only
141 asserts on it there rather than setting it again; every subsequent
142 step within the same phase has nothing else to set it, so run()
143 must do so itself. This is what makes
144 peano4::parallel::Node::getInstance().getCurrentProgramStep()
145 reliable for every step, not just a phase's first - in particular,
146 it is what the guard expressions
147 peano4.api.taskgraph.compiler.DeriveLoadStoreComputeFlag builds
148 actually depend on at runtime.
149
150 """
151 step_names = [step.name for step in steps]
152 observer_names = [step.get_observer_class_name() for step in steps]
153 first_step = step_names[0] if step_names else "Undef"
154 repeat_conditions = [step.has_to_repeat for step in steps]
155
157 headerfile_template = TEMPLATE_RUNNER_HEADER_FILE,
158 cppfile_template = TEMPLATE_RUNNER_CPP_FILE,
159 classname = identifier,
160 namespace = peano_project.namespace + ["runners"],
161 subdirectory = peano_project.subdirectory + "runners",
162 dictionary = {
163 "PROJECT_NAMESPACE": peano_project.namespace,
164 "SUBNAMESPACE": peano_project._subdirectory + "::" if peano_project._subdirectory else "",
165 "SUBDIRECTORY": peano_project.subdirectory,
166 "STEPS": step_names,
167 "OBSERVERS": observer_names,
168 "FIRST_STEP": first_step,
169 "REPEAT_CONDITIONS": repeat_conditions,
170 },
171 default_overwrite = True,
172 apply_iteratively = False,
173 )
174 peano_project.output.add(generated_files)
175 peano_project.output.makefile.add_cpp_file(
176 peano_project.subdirectory + "runners/" + identifier + ".cpp", generated=True
177 )