11 #include "../src/benchmark_api_internal.h"
12 #include "../src/check.h"
13 #include "../src/log.h"
14 #include "../src/re.h"
23 using TestCaseList = std::vector<TestCase>;
30 using SubMap = std::vector<std::pair<std::string, std::string>>;
39 SubMap& GetSubstitutions() {
42 static std::string safe_dec_re =
"[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?";
44 static std::string percentage_re =
"[0-9]+[.][0-9]{2}";
46 {
"%float",
"[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?"},
48 {
"%hrfloat",
"[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?[kMGTPEZYmunpfazy]?"},
49 {
"%percentage", percentage_re},
50 {
"%int",
"[ ]*[0-9]+"},
52 {
"%time",
"[ ]*" + time_re +
"[ ]+ns"},
53 {
"%console_report",
"[ ]*" + time_re +
"[ ]+ns [ ]*" + time_re +
"[ ]+ns [ ]*[0-9]+"},
54 {
"%console_percentage_report",
"[ ]*" + percentage_re +
"[ ]+% [ ]*" + percentage_re +
"[ ]+% [ ]*[0-9]+"},
55 {
"%console_us_report",
"[ ]*" + time_re +
"[ ]+us [ ]*" + time_re +
"[ ]+us [ ]*[0-9]+"},
56 {
"%console_ms_report",
"[ ]*" + time_re +
"[ ]+ms [ ]*" + time_re +
"[ ]+ms [ ]*[0-9]+"},
57 {
"%console_s_report",
"[ ]*" + time_re +
"[ ]+s [ ]*" + time_re +
"[ ]+s [ ]*[0-9]+"},
58 {
"%console_time_only_report",
"[ ]*" + time_re +
"[ ]+ns [ ]*" + time_re +
"[ ]+ns"},
59 {
"%console_us_report",
"[ ]*" + time_re +
"[ ]+us [ ]*" + time_re +
"[ ]+us [ ]*[0-9]+"},
60 {
"%console_us_time_only_report",
"[ ]*" + time_re +
"[ ]+us [ ]*" + time_re +
"[ ]+us"},
62 "name,iterations,real_time,cpu_time,time_unit,bytes_per_second,"
63 "items_per_second,label,error_occurred,error_message"},
64 {
"%csv_report",
"[0-9]+," + safe_dec_re +
"," + safe_dec_re +
",ns,,,,,"},
65 {
"%csv_us_report",
"[0-9]+," + safe_dec_re +
"," + safe_dec_re +
",us,,,,,"},
66 {
"%csv_ms_report",
"[0-9]+," + safe_dec_re +
"," + safe_dec_re +
",ms,,,,,"},
67 {
"%csv_s_report",
"[0-9]+," + safe_dec_re +
"," + safe_dec_re +
",s,,,,,"},
69 "[0-9]+," + safe_dec_re +
"," + safe_dec_re +
",ns," + safe_dec_re +
",,,,"},
71 "[0-9]+," + safe_dec_re +
"," + safe_dec_re +
",ns,," + safe_dec_re +
",,,"},
72 {
"%csv_bytes_items_report",
73 "[0-9]+," + safe_dec_re +
"," + safe_dec_re +
",ns," + safe_dec_re +
74 "," + safe_dec_re +
",,,"},
75 {
"%csv_label_report_begin",
"[0-9]+," + safe_dec_re +
"," + safe_dec_re +
",ns,,,"},
76 {
"%csv_label_report_end",
",,"}};
82 SubMap
const&
subs = GetSubstitutions();
83 using SizeT = std::string::size_type;
84 for (
auto const& KV :
subs) {
87 while ((
pos = source.find(KV.first, next_start)) != std::string::npos) {
88 next_start =
pos + KV.second.size();
89 source.replace(
pos, KV.first.size(), KV.second);
95 void CheckCase(std::stringstream& remaining_output,
TestCase const& TC,
96 TestCaseList
const& not_checks) {
100 while (remaining_output.eof() ==
false) {
102 std::getline(remaining_output,
line);
107 for (
const auto& NC : not_checks) {
109 <<
"Unexpected match for line \"" <<
line <<
"\" for MR_Not regex \""
110 << NC.regex_str <<
"\""
112 <<
"\n started matching near: " << first_line;
116 <<
"Expected line \"" <<
line <<
"\" to match regex \"" << TC.
regex_str
119 <<
"\n started matching near: " << first_line;
121 BM_CHECK(remaining_output.eof() ==
false)
122 <<
"End of output reached before match for regex \"" << TC.
regex_str
125 <<
"\n started matching near: " << first_line;
128 void CheckCases(TestCaseList
const& checks, std::stringstream&
output) {
129 std::vector<TestCase> not_checks;
130 for (
size_t i = 0;
i < checks.size(); ++
i) {
131 const auto& TC = checks[
i];
133 not_checks.push_back(TC);
136 CheckCase(
output, TC, not_checks);
143 TestReporter(std::vector<benchmark::BenchmarkReporter*> reps)
147 bool last_ret =
false;
152 <<
"Reports return different values for ReportContext";
221 auto start = std::stringstream::pos_type(0);
231 bool on_first =
true;
232 while (
output.eof() ==
false) {
244 BM_VLOG(2) <<
"--------------------------------\n";
245 BM_VLOG(2) <<
"checking for benchmarks matching " << p.regex_str <<
"...\n";
247 if (!p.regex->Match(
r.name)) {
248 BM_VLOG(2) << p.regex_str <<
" is not matched by " <<
r.name <<
"\n";
251 BM_VLOG(2) << p.regex_str <<
" is matched by " <<
r.name <<
"\n";
253 BM_VLOG(1) <<
"Checking results of " <<
r.name <<
": ... \n";
255 BM_VLOG(1) <<
"Checking results of " <<
r.name <<
": OK.\n";
267 if (entry_csv_line.empty())
return;
273 for (
size_t i = 1, e =
vals.size();
i < e; ++
i) {
280 std::vector<std::string>
out;
283 size_t prev = 0,
pos =
line.find_first_of(
','), curr =
pos;
286 if (
line[prev] ==
'"') ++prev;
287 if (
line[curr - 1] ==
'"') --curr;
288 out.push_back(
line.substr(prev, curr - prev));
294 if (
line[prev] ==
'"') ++prev;
295 if (
line[curr - 1] ==
'"') --curr;
296 out.push_back(
line.substr(prev, curr - prev));
305 return rc.results.size();
309 auto pos =
name.find(
"/threads:");
310 if (
pos ==
name.npos)
return 1;
312 std::stringstream ss;
321 return GetAs<double>(
"iterations");
326 const char* which_str =
which ==
kCpuTime ?
"cpu_time" :
"real_time";
327 double val = GetAs<double>(which_str);
328 auto unit =
Get(
"time_unit");
332 }
else if (*unit ==
"us") {
334 }
else if (*unit ==
"ms") {
336 }
else if (*unit ==
"s") {
339 BM_CHECK(1 == 0) <<
"unknown time unit: " << *unit;
351 substituted_regex(
internal::PerformSubstitutions(regex_str)),
357 <<
"\n originally \"" <<
regex_str <<
"\""
358 <<
"\n got error: " << err_str;
362 auto&
L = internal::GetTestCaseList(ID);
363 L.insert(
L.end(), il);
368 std::initializer_list<std::pair<std::string, std::string>> il) {
369 auto&
subs = internal::GetSubstitutions();
372 KV.second = internal::PerformSubstitutions(KV.second);
373 for (
auto& EKV :
subs) {
374 if (EKV.first == KV.first) {
388 #pragma GCC diagnostic push
389 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
392 using internal::GetTestCaseList;
398 struct ReporterTest {
400 std::vector<TestCase>& output_cases;
401 std::vector<TestCase>& error_cases;
403 std::stringstream out_stream;
404 std::stringstream err_stream;
406 ReporterTest(
const char*
n, std::vector<TestCase>& out_tc,
407 std::vector<TestCase>& err_tc,
409 :
name(
n), output_cases(out_tc), error_cases(err_tc), reporter(br) {
423 std::cout <<
"Running benchmarks...\n";
424 internal::TestReporter test_rep({&CR, &JR, &CSVR});
427 for (
auto& rep_test : TestCases) {
430 std::cout << banner <<
msg << banner <<
"\n";
432 std::cerr << rep_test.err_stream.str();
433 std::cout << rep_test.out_stream.str();
435 internal::CheckCases(rep_test.error_cases, rep_test.err_stream);
436 internal::CheckCases(rep_test.output_cases, rep_test.out_stream);
443 auto& csv = TestCases[2];
445 BM_CHECK(std::strcmp(csv.name,
"CSVReporter") == 0);
450 #pragma GCC diagnostic pop
454 if (pat.length() == 0)
return 0;
456 for (
size_t offset = haystack.find(pat);
offset != std::string::npos;
463 return ch < 10 ? static_cast<char>(
'0' +
ch)
464 :
static_cast<char>(
'a' + (
ch - 10));
468 static std::mt19937 rd{std::random_device{}()};
469 static std::uniform_int_distribution<int> mrand{0, 15};
470 return ToHex(mrand(rd));
475 for (
auto &
ch : model) {
483 std::ifstream
in(
name.c_str());
497 std::cerr <<
"Failed to create unique temporary file name" << std::endl;
502 std::vector<char*> new_argv(argv, argv + argc);
503 assert(
static_cast<decltype(new_argv)::size_type
>(argc) == new_argv.size());
506 std::cout <<
"Will be using this as the tmp file: " << tmp_file_name <<
'\n';
509 tmp += tmp_file_name;
510 new_argv.emplace_back(
const_cast<char*
>(
tmp.c_str()));
512 argc =
int(new_argv.size());
518 std::ifstream tmp_stream(tmp_file_name);
520 std::istreambuf_iterator<char>());
521 std::remove(tmp_file_name.c_str());