diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 4ef47e7314..b886002efe 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -51,6 +52,48 @@ constexpr unsigned long kParallelLevelMinimum = 2u; // Under a job server, parallelism is effectively limited // only by available job server tokens. constexpr unsigned long kParallelLevelUnbounded = 0x10000u; + +struct CostEntry +{ + cm::string_view name; + int prevRuns; + float cost; +}; + +cm::optional splitCostLine(cm::string_view line) +{ + std::string part; + cm::string_view::size_type pos1 = line.size(); + cm::string_view::size_type pos2 = line.find_last_of(' ', pos1); + auto findNext = [line, &part, &pos1, &pos2]() -> bool { + if (pos2 != cm::string_view::npos) { + cm::string_view sub = line.substr(pos2 + 1, pos1 - pos2 - 1); + part.assign(sub.begin(), sub.end()); + pos1 = pos2; + if (pos1 > 0) { + pos2 = line.find_last_of(' ', pos1 - 1); + } + return true; + } + return false; + }; + + // parse the cost + if (!findNext()) { + return cm::nullopt; + } + float cost = static_cast(atof(part.c_str())); + + // parse the previous runs + if (!findNext()) { + return cm::nullopt; + } + int prev = atoi(part.c_str()); + + // from start to the last found space is the name + return CostEntry{ line.substr(0, pos1), prev, cost }; +} + } namespace cmsys { @@ -794,24 +837,21 @@ void cmCTestMultiProcessHandler::UpdateCostData() if (line == "---") { break; } - std::vector parts = cmSystemTools::SplitString(line, ' '); // Format: - if (parts.size() < 3) { + cm::optional entry = splitCostLine(line); + if (!entry) { break; } - std::string name = parts[0]; - int prev = atoi(parts[1].c_str()); - float cost = static_cast(atof(parts[2].c_str())); - - int index = this->SearchByName(name); + int index = this->SearchByName(entry->name); if (index == -1) { // This test is not in memory. We just rewrite the entry - fout << name << " " << prev << " " << cost << "\n"; + fout << entry->name << " " << entry->prevRuns << " " << entry->cost + << "\n"; } else { // Update with our new average cost - fout << name << " " << this->Properties[index]->PreviousRuns << " " - << this->Properties[index]->Cost << "\n"; + fout << entry->name << " " << this->Properties[index]->PreviousRuns + << " " << this->Properties[index]->Cost << "\n"; temp.erase(index); } } @@ -847,28 +887,25 @@ void cmCTestMultiProcessHandler::ReadCostData() break; } - std::vector parts = cmSystemTools::SplitString(line, ' '); + // Format: + cm::optional entry = splitCostLine(line); // Probably an older version of the file, will be fixed next run - if (parts.size() < 3) { + if (!entry) { fin.close(); return; } - std::string name = parts[0]; - int prev = atoi(parts[1].c_str()); - float cost = static_cast(atof(parts[2].c_str())); - - int index = this->SearchByName(name); + int index = this->SearchByName(entry->name); if (index == -1) { continue; } - this->Properties[index]->PreviousRuns = prev; + this->Properties[index]->PreviousRuns = entry->prevRuns; // When not running in parallel mode, don't use cost data if (this->GetParallelLevel() > 1 && this->Properties[index] && this->Properties[index]->Cost == 0) { - this->Properties[index]->Cost = cost; + this->Properties[index]->Cost = entry->cost; } } // Next part of the file is the failed tests @@ -881,7 +918,7 @@ void cmCTestMultiProcessHandler::ReadCostData() } } -int cmCTestMultiProcessHandler::SearchByName(std::string const& name) +int cmCTestMultiProcessHandler::SearchByName(cm::string_view name) { int index = -1; diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index fd6c17f2fa..811be613c3 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -13,6 +13,7 @@ #include #include +#include #include "cmCTest.h" #include "cmCTestResourceAllocator.h" @@ -110,7 +111,7 @@ protected: void UpdateCostData(); void ReadCostData(); // Return index of a test based on its name - int SearchByName(std::string const& name); + int SearchByName(cm::string_view name); void CreateTestCostList(); diff --git a/Tests/CTestTestScheduler/CMakeLists.txt b/Tests/CTestTestScheduler/CMakeLists.txt index 6f8cb4dbc0..daf6ce2b23 100644 --- a/Tests/CTestTestScheduler/CMakeLists.txt +++ b/Tests/CTestTestScheduler/CMakeLists.txt @@ -1,9 +1,9 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.19) project (CTestTestScheduler) include (CTest) add_executable (Sleep sleep.c) foreach (time RANGE 1 4) - add_test (TestSleep${time} Sleep ${time}) + add_test ("TestSleep ${time}" Sleep ${time}) endforeach ()