Nektar++
Public Member Functions | Static Public Member Functions | Static Public Attributes | Protected Member Functions | Protected Attributes | List of all members
Nektar::MetricExecutionTime Class Reference

Metric that finds the execution time in an output and tests it against an accepted value and tolerance. More...

#include <MetricExecutionTime.h>

Inheritance diagram for Nektar::MetricExecutionTime:
[legend]

Public Member Functions

 ~MetricExecutionTime () override
 
- Public Member Functions inherited from Nektar::Metric
 Metric (TiXmlElement *metric, bool generate)
 Constructor. More...
 
virtual ~Metric ()=default
 
bool Test (std::istream &pStdout, std::istream &pStderr)
 Calls a metric's v_Test function (or v_Generate if m_generate). More...
 
void Generate (std::istream &pStdout, std::istream &pStderr)
 
std::string GetType ()
 Return metric type. More...
 
int GetID ()
 Return metric ID. More...
 
bool SupportsAverage () const
 Return whether this metric supports averaging results from multiple runs. More...
 

Static Public Member Functions

static MetricSharedPtr create (TiXmlElement *metric, bool generate)
 

Static Public Attributes

static std::string type
 

Protected Member Functions

 MetricExecutionTime (TiXmlElement *metric, bool generate)
 Construct a new MetricExecutionTime object. More...
 
bool v_Test (std::istream &pStdout, std::istream &pStderr) override
 Test output against a regular expression and its expected value. More...
 
void v_Generate (std::istream &pStdout, std::istream &pStderr) override
 Generate an accepted execution time value using a test output or error stream. More...
 
virtual bool v_Test (std::istream &pStdout, std::istream &pStderr)=0
 Virtual function to test the metric. Should be redefined in derived classes. More...
 
virtual void v_Generate (std::istream &pStdout, std::istream &pSrderr)=0
 Virtual function to generate the metric. Should be redefined in derived classes. More...
 

Protected Attributes

std::regex m_regex
 Regex used to match an execution time in a test output. More...
 
MetricExecutionTimeFieldValue m_match
 Stores each execution time found in the test output. More...
 
bool m_useStderr = false
 If true, use stderr for testing/generation instead of stdout. More...
 
- Protected Attributes inherited from Nektar::Metric
int m_id
 Stores the ID of this metric. More...
 
std::string m_type
 Stores the type of this metric (uppercase). More...
 
bool m_generate
 Determines whether to generate this metric or not. More...
 
bool m_average = false
 Indicates whether a metric supports averaging results from multiple runs. More...
 
TiXmlElement * m_metric
 Pointer to XML structure containing metric definition. More...
 

Detailed Description

Metric that finds the execution time in an output and tests it against an accepted value and tolerance.

Definition at line 71 of file MetricExecutionTime.h.

Constructor & Destructor Documentation

◆ ~MetricExecutionTime()

Nektar::MetricExecutionTime::~MetricExecutionTime ( )
inlineoverride

Definition at line 74 of file MetricExecutionTime.h.

75 {
76 }

◆ MetricExecutionTime()

Nektar::MetricExecutionTime::MetricExecutionTime ( TiXmlElement *  metric,
bool  generate 
)
protected

Construct a new MetricExecutionTime object.

If the metric is not a derived class, then this constructor will parse the regular expression from the metric's element in the test file, or use a default value if this doesn't exist. It will also see if an expected execution time and tolerance have been provided for the current computer's hostname. If this is the case, these will be used by v_Test. If not, then a skip flag m_skip will be set to true and the test will automatically pass.

Parameters
metric
generate

Definition at line 65 of file MetricExecutionTime.cpp.

66 : Metric(metric, generate)
67{
68 // If we are a derived class, do nothing
69 if (m_type != "EXECUTIONTIME")
70 {
71 return;
72 }
73
74 // Parse Regex expression
75 TiXmlElement *regex = metric->FirstChildElement("regex");
76
77 if (regex)
78 {
79 ASSERTL0(regex->GetText(), "Failed to read regex element.");
80 m_regex = regex->GetText();
81 }
82 else
83 {
84 // Set the regex to a default value.
85 m_regex = R"(^.*Total Computation Time\s*=\s*(\d+\.?\d*).*)";
86 }
87
88 // Inform the Tester this metric supports averaging data from multiple runs.
89 m_average = true;
90 m_match = MetricExecutionTimeFieldValue("nil");
91
92 // Parse matching values if not generating.
93 if (m_generate)
94 {
95 return;
96 }
97
98 TiXmlElement *value = metric->FirstChildElement("value");
99 ASSERTL0(value || m_generate, "Missing value tag for metric.");
100
101 bool hostnameMatch = false;
102 while (value)
103 {
104 ASSERTL0(value->Attribute("tolerance"),
105 "Missing tolerance in execution time metric.");
106 ASSERTL0(value->Attribute("hostname"),
107 "Missing hostname in execution time metric.");
108 ASSERTL0(!EmptyString(value->GetText()),
109 "Missing value in execution time metric.");
110
111 // Only use the value if it matches the runner's hostname.
112 if (value->Attribute("hostname") == boost::asio::ip::host_name())
113 {
114 MetricExecutionTimeFieldValue val;
115 val.m_value = value->GetText();
116 val.m_tolerance = atof(value->Attribute("tolerance"));
117 m_match = val;
118
119 hostnameMatch = true;
120
121 // No use finding any more values
122 break;
123 }
124
125 value = value->NextSiblingElement("value");
126 }
127
128 // If no hostname match was found, pass a skip flag to the test.
129 if (!hostnameMatch)
130 {
131 cerr << "WARNING: No execution time value provided for host "
132 << boost::asio::ip::host_name() << ". Skipping metric." << endl;
133 m_match.m_skip = true;
134 }
135}
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
std::regex m_regex
Regex used to match an execution time in a test output.
MetricExecutionTimeFieldValue m_match
Stores each execution time found in the test output.
Metric(TiXmlElement *metric, bool generate)
Constructor.
Definition: Metric.cpp:51
bool m_average
Indicates whether a metric supports averaging results from multiple runs.
Definition: Metric.h:99
std::string m_type
Stores the type of this metric (uppercase).
Definition: Metric.h:94
bool m_generate
Determines whether to generate this metric or not.
Definition: Metric.h:96
bool EmptyString(const char *s)
Check to see whether the given string s is empty (or null).
Definition: Metric.h:50
bool m_skip
Indicates whether the metric should be skipped. Defaults to false.

References ASSERTL0, Nektar::EmptyString(), Nektar::Metric::m_average, Nektar::Metric::m_generate, m_match, m_regex, Nektar::MetricExecutionTimeFieldValue::m_skip, Nektar::MetricExecutionTimeFieldValue::m_tolerance, Nektar::Metric::m_type, and Nektar::MetricExecutionTimeFieldValue::m_value.

Referenced by create().

Member Function Documentation

◆ create()

static MetricSharedPtr Nektar::MetricExecutionTime::create ( TiXmlElement *  metric,
bool  generate 
)
inlinestatic

Definition at line 78 of file MetricExecutionTime.h.

79 {
80 return MetricSharedPtr(new MetricExecutionTime(metric, generate));
81 }
MetricExecutionTime(TiXmlElement *metric, bool generate)
Construct a new MetricExecutionTime object.
std::shared_ptr< Metric > MetricSharedPtr
A shared pointer to an EquationSystem object.
Definition: Metric.h:124

References MetricExecutionTime().

◆ v_Generate()

void Nektar::MetricExecutionTime::v_Generate ( std::istream &  pStdout,
std::istream &  pStderr 
)
overrideprotectedvirtual

Generate an accepted execution time value using a test output or error stream.

This function generate an execution time match by finding the first execution time in the output that matches m_regex (provided in the test file).

Parameters
pStdoutReference to test output stream.
pStderrReference to test error stream.

Implements Nektar::Metric.

Definition at line 266 of file MetricExecutionTime.cpp.

267{
268 boost::ignore_unused(pStderr);
269
270 // Select istream to use
271 istream &is = m_useStderr ? pStderr : pStdout;
272
273 std::smatch matches;
274
275 string line;
276 // Vector of execution times found in the output
277 vector<double> sampleTimes;
278 bool matched = false;
279
280 // Process output file line by line searching for regex matches
281 while (getline(is, line))
282 {
283 // Test to see if we have a match on this line
284 if (std::regex_match(line, matches, m_regex))
285 {
286 // If no fields in regex then throw an error
287 ASSERTL0(matches.size() != 1, "No test sections in regex!");
288
289 // Check each regex capture group in turn
290 for (int i = 1; i < matches.size(); ++i)
291 {
292 // Extract the captured string
293 string match(matches[i].first, matches[i].second);
294 double val;
295 try
296 {
297 val = boost::lexical_cast<double>(match);
298
299 sampleTimes.push_back(val);
300 matched = true;
301 }
302 catch (boost::bad_lexical_cast &e)
303 {
304 cerr << "Could not convert match " << match << " to double"
305 << endl;
306 continue;
307 }
308 }
309 }
310 }
311
312 // Stores the accepted average execution time and a default tolerance.
313 MetricExecutionTimeFieldValue okValue;
314
315 if (matched)
316 {
317 // Average the found execution times and set it as the accepted value.
318 double minTime = sampleTimes[0];
319 for (unsigned int i = 0; i < sampleTimes.size(); ++i)
320 {
321 minTime = (sampleTimes[i] < minTime ? sampleTimes[i] : minTime);
322 }
323
324 okValue.m_value = to_string(minTime);
325 m_match = okValue;
326 }
327 else
328 {
329 cerr << "No execution times were found in the test output. Value set "
330 "to 'nil'."
331 << endl;
332 }
333
334 // If we are not a derived class then create a new structure.
335 if (m_type == "EXECUTIONTIME")
336 {
337 // Remove values if they already exist.
338 while (m_metric->FirstChildElement("value"))
339 {
340 ASSERTL0(
341 m_metric->RemoveChild(m_metric->FirstChildElement("value")),
342 "Couldn't remove value from metric!");
343 }
344
345 TiXmlElement *val = new TiXmlElement("value");
346
347 val->SetAttribute("tolerance",
348 boost::lexical_cast<string>(m_match.m_tolerance));
349 val->SetAttribute("hostname", boost::asio::ip::host_name());
350 val->LinkEndChild(new TiXmlText(m_match.m_value));
351 m_metric->LinkEndChild(val);
352 }
353}
bool m_useStderr
If true, use stderr for testing/generation instead of stdout.
TiXmlElement * m_metric
Pointer to XML structure containing metric definition.
Definition: Metric.h:101
double m_tolerance
The tolerance to use for checking the execution time. Defaults to 5.0.
std::string m_value
The value to match. Defaults to empty string.

References ASSERTL0, m_match, Nektar::Metric::m_metric, m_regex, Nektar::MetricExecutionTimeFieldValue::m_tolerance, Nektar::Metric::m_type, m_useStderr, and Nektar::MetricExecutionTimeFieldValue::m_value.

◆ v_Test()

bool Nektar::MetricExecutionTime::v_Test ( std::istream &  pStdout,
std::istream &  pStderr 
)
overrideprotectedvirtual

Test output against a regular expression and its expected value.

This function will find the execution time for each test run in the output, using m_regex (provided in the test file). It will then average these times and compare them to the expected execution time for the current computer's hostname (this behaviour is defined in the constructor). If the average execution time falls outside of the tolerance then the test will fail.

If no execution time value is provided for the current computer's hostname, m_skip will be set to true and the test will automatically pass.

Parameters
pStdoutReference to test output stream.
pStderrReference to test error stream.
Returns
true if the test passes, false otherwise.

Implements Nektar::Metric.

Definition at line 154 of file MetricExecutionTime.cpp.

155{
156 boost::ignore_unused(pStdout, pStderr);
157
158 bool success = true;
159
160 // Select istream to use.
161 istream &is = m_useStderr ? pStderr : pStdout;
162
163 std::smatch matches;
164 string line;
165 // Vector of execution times found in the output.
166 vector<double> times;
167 bool matched = false;
168
169 // Process output file line by line searching for regex matches
170 while (getline(is, line))
171 {
172 // Test to see if we have a match on this line.
173 if (std::regex_match(line, matches, m_regex))
174 {
175 // If no matches are found then throw an error.
176 if (matches.size() == 1)
177 {
178 cerr << "No test sections in regex!" << endl;
179 return false;
180 }
181
182 // Check each regex capture group in turn
183 for (int i = 1; i < matches.size(); ++i)
184 {
185 // Extract the captured string
186 string match(matches[i].first, matches[i].second);
187 double val;
188 try
189 {
190 val = boost::lexical_cast<double>(match);
191
192 // Add value to the list of found execution times.
193 times.push_back(val);
194 matched = true;
195 }
196 catch (boost::bad_lexical_cast &e)
197 {
198 cerr << "Could not convert match " << match << " to double"
199 << endl;
200 success = false;
201 continue;
202 }
203 }
204 }
205 }
206
207 if (!matched)
208 {
209 cerr << "No execution times were found in the test output. Consider "
210 "providing a custom regex for this test metric."
211 << endl;
212 success = false;
213 }
214
215 // Find the minimum of the execution times.
216 double minTime = times[0];
217 for (unsigned int i = 0; i < times.size(); ++i)
218 {
219 minTime = (times[i] < minTime) ? times[i] : minTime;
220 }
221
222 // If a skip flag is set (due to no matching hostname) then return
223 // successful test and output the average time.
224 if (m_match.m_skip)
225 {
226 cerr << "Minimum execution time for host "
227 << boost::asio::ip::host_name() << ": " << minTime << endl;
228 return success;
229 }
230
231 ASSERTL0(m_match.m_value != "nil",
232 "No test conditions defined for execution time.");
233
234 // Check that the average time is within the tolerance.
235 if (fabs(minTime - boost::lexical_cast<double>(m_match.m_value)) >
238 {
239 cerr << endl;
240 cerr << "Failed tolerance match." << endl;
241 cerr << " Expected min execution time: " << m_match.m_value << " +/- "
242 << m_match.m_tolerance << endl;
243 cerr << " Actual min: " << minTime << endl;
244
245 for (unsigned int i = 0; i < times.size(); ++i)
246 {
247 cerr << " Run " << i << ": " << times[i] << endl;
248 }
249
250 success = false;
251 }
252
253 return success;
254}

References ASSERTL0, m_match, m_regex, Nektar::MetricExecutionTimeFieldValue::m_skip, Nektar::MetricExecutionTimeFieldValue::m_tolerance, m_useStderr, and Nektar::MetricExecutionTimeFieldValue::m_value.

Member Data Documentation

◆ m_match

MetricExecutionTimeFieldValue Nektar::MetricExecutionTime::m_match
protected

Stores each execution time found in the test output.

Definition at line 89 of file MetricExecutionTime.h.

Referenced by MetricExecutionTime(), v_Generate(), and v_Test().

◆ m_regex

std::regex Nektar::MetricExecutionTime::m_regex
protected

Regex used to match an execution time in a test output.

Definition at line 87 of file MetricExecutionTime.h.

Referenced by MetricExecutionTime(), v_Generate(), and v_Test().

◆ m_useStderr

bool Nektar::MetricExecutionTime::m_useStderr = false
protected

If true, use stderr for testing/generation instead of stdout.

Definition at line 91 of file MetricExecutionTime.h.

Referenced by v_Generate(), and v_Test().

◆ type

std::string Nektar::MetricExecutionTime::type
static
Initial value:
=
static MetricSharedPtr create(TiXmlElement *metric, bool generate)
std::string RegisterCreatorFunction(std::string key, CreatorFunction func)
Definition: Metric.h:133
MetricFactory & GetMetricFactory()
Definition: Metric.cpp:42

Definition at line 83 of file MetricExecutionTime.h.