37#include <pybind11/embed.h>
38#include <unordered_map>
48 bool is_run_only =
false;
49 bool is_full_output_mode =
false;
58 void _start_test_print(details::Test &test,
u32 test_num,
u32 test_count) {
64 output += shambase::format(
"- [{}/{}] :", test_num + 1, test_count);
67 bool any_node_cnt = test.node_count == -1;
69 output += (
" [any] ");
71 output += shambase::format(
" [{:03}] ", test.node_count);
74 output +=
"\033[;34m" + test.name +
"\033[0m\n";
84 void _end_test_print(std::vector<details::TestResult> &rank_results,
shambase::Timer &timer) {
86 for (
int rank = 0; rank < rank_results.size(); rank++) {
87 auto &res = rank_results[rank];
89 for (
unsigned int j = 0; j < res.asserts.asserts.size(); j++) {
91 if (is_full_output_mode || (!res.asserts.asserts[j].value)) {
92 printf(
" Rank %3d [%d/%zu] : ", rank, j + 1, res.asserts.asserts.size());
93 printf(
"%-20s", res.asserts.asserts[j].name.c_str());
95 if (res.asserts.asserts[j].value) {
96 std::cout <<
" (\033[;32mSuccess\033[0m)\n";
98 std::cout <<
" (\033[1;31m Fail \033[0m)\n";
99 if (!res.asserts.asserts[j].comment.empty()) {
100 std::cout <<
"----- logs : \n"
101 << res.asserts.asserts[j].comment <<
"\n-----" << std::endl;
108 u32 assert_count = 0;
110 for (
int rank = 0; rank < rank_results.size(); rank++) {
111 auto &res = rank_results[rank];
112 for (
unsigned int j = 0; j < res.asserts.asserts.size(); j++) {
113 if (res.asserts.asserts[j].value) {
120 if (success_cnt == assert_count) {
121 std::cout <<
" -> Result : \033[;32mSuccess\033[0m";
123 std::cout <<
" -> Result : \033[1;31m Fail \033[0m";
126 std::string s_assert = shambase::format(
" [{}/{}] ", success_cnt, assert_count);
127 printf(
"%-15s", s_assert.c_str());
128 std::cout <<
" (" << timer.
get_time_str() <<
")" << std::endl;
131 if (success_cnt != assert_count) {
132 logger::raw_ln(shambase::format(
"##[error]Test {} failed", rank_results[0].name));
136 std::cout << std::endl;
146 bool is_test_failed(details::TestResult &res) {
147 for (
unsigned int j = 0; j < res.asserts.asserts.size(); j++) {
149 if (!res.asserts.asserts[j].value) {
163 std::string gen_fail_log(details::TestResult &res) {
164 std::string out =
"";
166 std::string sep =
"\n-------------------------------------\n";
168 out +=
" - Test : \033[;34m" + res.name
169 +
"\033[0m world_rank = " + std::to_string(res.world_rank);
170 out +=
"\n Assertion list :\n";
172 for (
unsigned int j = 0; j < res.asserts.asserts.size(); j++) {
177 if (res.asserts.asserts[j].value) {
178 out +=
" (\033[;32mSuccess\033[0m)\n";
180 out +=
" (\033[1;31m Fail \033[0m)\n";
183 if ((!res.asserts.asserts[j].value) && !res.asserts.asserts[j].comment.empty()) {
184 out +=
" -> failed assert logs : " + sep + res.asserts.asserts[j].comment + sep;
198 void _print_summary(std::vector<details::TestResult> &results) {
203 logger::print_faint_row();
204 logger::print_faint_row();
205 logger::print_faint_row();
207 shambase::term_colors::bold() +
"Test Report :" + shambase::term_colors::reset());
210 u32 test_count = results.size();
213 std::string log =
"";
214 for (details::TestResult &res : results) {
215 if (!is_test_failed(res)) {
219 log += gen_fail_log(res);
223 std::cout <<
"Test suite status : ";
224 if (fail_count == 0) {
225 std::cout <<
" (\033[;32mSuccess\033[0m)";
226 printf(
" [%d/%d] \n", succ_count, test_count);
228 std::cout <<
" (\033[1;31m Fail \033[0m)";
229 printf(
" [%d/%d] \n", succ_count, test_count);
230 std::cout <<
"\nFailed tests : \n\n" << log;
233 logger::print_faint_row();
234 logger::print_faint_row();
235 logger::print_faint_row();
239 std::vector<details::TestResult> gather_tests(
240 std::vector<details::TestResult> rank_result,
usize &gather_bytecount) {
246 std::basic_stringstream<byte> outrank;
250 std::basic_string<byte> gathered;
257 gather_bytecount = gathered.size();
259 std::basic_stringstream<byte> reader(gathered);
261 std::vector<details::TestResult> out;
274 void print_test_list() {
284 if (test.type == t) {
285 if (test.node_count == -1) {
286 printf(
"- [any] %-15s\n", test.name.c_str());
288 printf(
"- [%03d] %-15s\n", test.node_count, test.name.c_str());
294 printf(
"--- Benchmark ---\n");
296 print_list(Benchmark);
298 printf(
"--- LongBenchmark ---\n");
300 print_list(LongBenchmark);
302 printf(
"--- ValidationTest ---\n");
304 print_list(ValidationTest);
306 printf(
"--- LongValidationTest ---\n");
308 print_list(LongValidationTest);
310 printf(
"--- Unittest ---\n");
312 print_list(Unittest);
316 void write_json_report(std::vector<details::TestResult> &results, std::string outfile) {
321 std::stringstream rank_test_res_out;
323 rank_test_res_out << res.serialize_json() <<
",";
326 std::string out_res_string = rank_test_res_out.str();
330 if (out_res_string.back() ==
',') {
331 out_res_string = out_res_string.substr(0, out_res_string.size() - 1);
338 s_out += R
"( "commit_hash" : ")" + git_commit_hash + "\",\n";
341#if defined(SYCL_COMP_INTEL_LLVM)
342 s_out += R
"( "compiler" : "DPCPP",)"
344#elif defined(SYCL_COMP_HIPSYCL)
345 s_out += R
"( "compiler" : "HipSYCL",)"
348 s_out += R
"( "compiler" : "Unknown",)"
352 s_out += R
"( "comp_args" : ")" + compile_arg + "\",\n";
354 s_out += R
"( "results" : )"
365 void write_tex_report(std::vector<details::TestResult> &results,
bool mark_fail) {
370 logger::raw(
"write report Tex : ");
375 logger::raw_ln(
"Done (tests/report.tex)");
378 std::vector<u32> select_print_tests(
TestConfig cfg) {
387 bool any_node_cnt = (t.node_count == -1);
390 bool can_run_type =
false;
392 auto test_type = t.type;
393 can_run_type |= (run_unit_test && (Unittest == test_type));
394 can_run_type |= (run_validation_test && (ValidationTest == test_type));
395 can_run_type |= (run_longvalidation_test && (LongValidationTest == test_type));
396 can_run_type |= (run_benchmark_test && (Benchmark == test_type));
397 can_run_type |= (run_longbenchmark_test && (LongBenchmark == test_type));
399 return can_run_type && (any_node_cnt || world_size_ok);
405 std::string output =
"";
410 output += (
" - [\033[;32many\033[0m] ");
412 output += shambase::format(
" - [\033[;32m{:03}\033[0m] ", t.
node_count);
414 output +=
"\033[;32m" + t.
name +
"\033[0m\n";
418 output += (
" - [\033[;31many\033[0m] ");
420 output += shambase::format(
" - [\033[;31m{:03}\033[0m] ", t.
node_count);
422 output +=
"\033[;31m" + t.
name +
"\033[0m\n";
425 printf(
"%s", output.c_str());
430 std::vector<u32> selected_tests;
432 auto run_only_check = [&](std::string test_name) ->
bool {
442 if (static_init_vec_tests[i].type == t) {
444 bool run_test = can_run(static_init_vec_tests[i])
445 && run_only_check(static_init_vec_tests[i].name);
447 ON_RANK_0(print_test(static_init_vec_tests[i], run_test));
450 selected_tests.push_back(i);
456 ON_RANK_0(printf(
"\n------------ Tests list --------------\n"));
457 if (run_benchmark_test) {
458 ON_RANK_0(printf(
"--- Benchmark ---\n"));
459 test_loop(Benchmark);
462 if (run_benchmark_test) {
463 ON_RANK_0(printf(
"--- LongBenchmark ---\n"));
464 test_loop(LongBenchmark);
467 if (run_validation_test) {
468 ON_RANK_0(printf(
"--- ValidationTest ---\n"));
469 test_loop(ValidationTest);
472 if (run_longvalidation_test) {
473 ON_RANK_0(printf(
"--- LongValidationTest ---\n"));
474 test_loop(LongValidationTest);
481 ON_RANK_0(printf(
"--------------------------------------\n\n"));
483 return selected_tests;
491 mpi::barrier(MPI_COMM_WORLD);
492 std::vector<u32> selected_tests = select_print_tests(cfg);
493 mpi::barrier(MPI_COMM_WORLD);
495 u32 test_loc_cnt = 0;
497 bool has_error =
false;
499 logger::info_ln(
"Test",
"start python interpreter");
500 py::initialize_interpreter();
502 ON_RANK_0(shamcomm::logs::print_faint_row());
505 ON_RANK_0(shamcomm::logs::print_faint_row());
512 std::filesystem::create_directories("tests/figures");
516 ON_RANK_0(logger::raw_ln(
"Running tests : "));
517 ON_RANK_0(shamcomm::logs::print_faint_row());
519 std::vector<TestResult> results;
520 for (
u32 i : selected_tests) {
524 _start_test_print(test, test_loc_cnt, selected_tests.size());
528 mpi::barrier(MPI_COMM_WORLD);
533 mpi::barrier(MPI_COMM_WORLD);
535 usize gather_bytecount = 0;
536 std::vector<TestResult> gathered = gather_tests({res}, gather_bytecount);
538 logger::raw_ln(
"Test result gathered :", gather_bytecount,
"bytes");
539 _end_test_print(gathered, timer);
542 results.push_back(std::move(res));
547 logger::info_ln(
"Test",
"close python interpreter");
548 py::finalize_interpreter();
550 usize gather_bytecount = 0;
551 results = gather_tests(std::move(results), gather_bytecount);
554 logger::print_faint_row();
555 logger::raw_ln(
"Test result gathered :", gather_bytecount,
"bytes");
559 has_error = has_error || is_test_failed(res);
562 _print_summary(results);
568 write_tex_report(results, has_error);
577 mpi::barrier(MPI_COMM_WORLD);
580 logger::raw_ln(
"Tests done exiting ... exitcode =", errcode);
582 mpi::barrier(MPI_COMM_WORLD);
593 std::array rank_list{1, 2, 3, 4};
595 auto get_pref_type = [](
TestType t) -> std::string {
597 case Benchmark :
return "Benchmark";
598 case LongBenchmark :
return "LongBenchmark";
599 case ValidationTest :
return "ValidationTest";
600 case LongValidationTest:
return "LongValidationTest";
601 case Unittest :
return "Unittest";
605 auto get_arg = [](
TestType t) -> std::string {
607 case Benchmark :
return "--benchmark";
608 case LongBenchmark :
return "--long-test --benchmark";
609 case ValidationTest :
return "--validation";
610 case LongValidationTest:
return "--long-test --validation";
611 case Unittest :
return "--unittest";
615 auto get_test_name = [&](
Test t,
int ranks) -> std::string {
616 std::string name = get_pref_type(t.
type) +
"/" + t.
name
626 std::ofstream filestream;
627 filestream.open(std::string(outfile));
629 std::vector<std::string> cmake_test_list;
631 auto add_test = [&](
Test t,
int ranks) {
632 std::string tname = get_test_name(t, ranks);
633 cmake_test_list.push_back(tname);
635 std::string ret =
"add_test(\"";
639 ret +=
" mpirun -n " + std::to_string(ranks) +
" ../shamrock_test --sycl-cfg 0:0";
641 ret +=
" ../shamrock_test --sycl-cfg 0:0";
643 ret +=
" --run-only \"" + std::string(t.
name) +
"\"";
644 ret +=
" " + get_arg(t.
type);
650 if (t.
type == Benchmark || t.
type == LongBenchmark)
653 for (
int ncount : rank_list) {
665 if (REF_FILES_PATH) {
666 filestream <<
"set_tests_properties(\n";
667 for (
auto tname : cmake_test_list) {
668 filestream <<
" \"" << tname <<
"\"\n";
670 filestream <<
" PROPERTIES\n";
671 filestream <<
" ENVIRONMENT \"REF_FILES_PATH=" + *REF_FILES_PATH <<
"\"\n";
This header does the MPI include and wrap MPI calls.
Header file describing a Node Instance.
void close()
close the NodeInstance Aka : Finalize both MPI & SYCL
header describing return type of a test, and the type of the test
TestType
Describe the type of the performed test.
std::uint32_t u32
32 bit unsigned integer
std::size_t usize
size_t alias
std::int32_t i32
32 bit integer
Class Timer measures the time elapsed since the timer was started.
std::string get_time_str() const
Converts the stored nanosecond time to a string representation.
void end()
Stops the timer and stores the elapsed time in nanoseconds.
void start()
Starts the timer.
Scoped exception generator callback.
This header file contains utility functions related to exception handling in the code.
MPI string gather / allgather helpers (declarations; implementations in shamalgs/src/collective/gathe...
void gather_basic_str(const std::basic_string< byte > &send_vec, std::basic_string< byte > &recv_vec)
same as gather_str but with std::basic_string
Namespace for internal details of the logs module.
void stream_read_vector(std::basic_stringstream< byte > &stream, std::vector< T > &vec)
read a vector from the bytestream Note : this appends read objects to the vector without resetting it
void write_string_to_file(std::string filename, std::string s)
dump a string to a file
void throw_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Throw an exception and append the source location to it.
std::string increase_indent(std::string in, std::string delim="\n ")
Increase indentation of a string.
void stream_write_vector(std::basic_stringstream< byte > &stream, std::vector< T > &vec)
write the vector into the bytestream
std::optional< std::string > getenv_str(const char *env_var)
Get the content of the environment variable if it exist.
bool is_ci_github_actions()
Check if the environment variable GITHUB_ACTIONS is set.
i32 world_rank()
Gives the rank of the current process in the MPI communicator.
i32 world_size()
Gives the size of the MPI communicator.
implementation details of the test library
std::vector< Test > static_init_vec_tests
Static init vector containing the list of all the tests in the code see : programming guide : Static ...
std::string make_test_report_tex(std::vector< TestResult > &results, bool mark_fail)
Make the tex report.
namespace containing stuff related to the test library
void gen_test_list(std::string_view outfile)
output test list to a file
int run_all_tests(int argc, char *argv[], TestConfig cfg)
run all the tests
Pybind11 include and definitions.
main include file for testing
This file contains the definition for the stacktrace related functionality.
void modify_py_sys_path(bool do_print)
Modify Python sys.path to point to one detected during cmake invocation.
void set_sys_argv(int argc, char *argv[])
set the value of sys.argv
Configuration of the test runner.
std::optional< std::string > run_only
Run only regex to select tests.
bool run_long_tests
run also long tests
bool run_benchmark
run benchmarks
bool run_unittest
run unittests
bool full_output
Should display all logs including all asserts.
std::optional< std::string > json_output
Should output a json report.
bool run_validation
run validation tests
Informations about a test.
i32 node_count
Node count of the test.
std::string name
Name of the test.
TestType type
Type of test.
header file to manage sycl
Functions related to the MPI communicator.
#define ON_RANK_0(x)
Macro to execute code only on rank 0.