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

virtual ~MetricExecutionTime ()
 
- 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...
 
virtual bool v_Test (std::istream &pStdout, std::istream &pStderr)
 Test output against a regular expression and its expected value. More...
 
virtual void v_Generate (std::istream &pStdout, std::istream &pStderr)
 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

boost::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 70 of file MetricExecutionTime.h.

Constructor & Destructor Documentation

◆ ~MetricExecutionTime()

virtual Nektar::MetricExecutionTime::~MetricExecutionTime ( )
inlinevirtual

Definition at line 73 of file MetricExecutionTime.h.

74 {
75 }

◆ 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 = "^.*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:215
MetricExecutionTimeFieldValue m_match
Stores each execution time found in the test output.
boost::regex m_regex
Regex used to match an execution time in a 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:104
std::string m_type
Stores the type of this metric (uppercase).
Definition: Metric.h:99
bool m_generate
Determines whether to generate this metric or not.
Definition: Metric.h:101
bool EmptyString(const char *s)
Check to see whether the given string s is empty (or null).
Definition: Metric.h:55
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 77 of file MetricExecutionTime.h.

78 {
79 return MetricSharedPtr(new MetricExecutionTime(metric, generate));
80 }
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:129

References MetricExecutionTime().

◆ v_Generate()

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

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 267 of file MetricExecutionTime.cpp.

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

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 boost::cmatch 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 (boost::regex_match(line.c_str(), 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 // Average the found execution times.
216 double avgTime = 0.0;
217 for (unsigned int i = 0; i < times.size(); ++i)
218 {
219 avgTime += times[i];
220 }
221 avgTime /= times.size();
222
223 // If a skip flag is set (due to no matching hostname) then return
224 // successful test and output the average time.
225 if (m_match.m_skip)
226 {
227 cerr << "Average execution time for host "
228 << boost::asio::ip::host_name() << ": " << avgTime << endl;
229 return success;
230 }
231
232 ASSERTL0(m_match.m_value != "nil",
233 "No test conditions defined for execution time.");
234
235 // Check that the average time is within the tolerance.
236 if (fabs(avgTime - boost::lexical_cast<double>(m_match.m_value)) >
239 {
240 cerr << endl;
241 cerr << "Failed tolerance match." << endl;
242 cerr << " Expected avg execution time: " << m_match.m_value << " +/- "
243 << m_match.m_tolerance << endl;
244 cerr << " Actual avg: " << avgTime << endl;
245
246 for (unsigned int i = 0; i < times.size(); ++i)
247 {
248 cerr << " Run " << i << ": " << times[i] << endl;
249 }
250
251 success = false;
252 }
253
254 return success;
255}

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 88 of file MetricExecutionTime.h.

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

◆ m_regex

boost::regex Nektar::MetricExecutionTime::m_regex
protected

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

Definition at line 86 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 90 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:138
MetricFactory & GetMetricFactory()
Definition: Metric.cpp:42

Definition at line 82 of file MetricExecutionTime.h.