diff options
Diffstat (limited to 'Source/CTest')
-rw-r--r-- | Source/CTest/cmCTestBuildAndTestHandler.cxx | 22 | ||||
-rw-r--r-- | Source/CTest/cmCTestCoverageHandler.cxx | 25 | ||||
-rw-r--r-- | Source/CTest/cmCTestCurl.h | 2 | ||||
-rw-r--r-- | Source/CTest/cmCTestHandlerCommand.cxx | 16 | ||||
-rw-r--r-- | Source/CTest/cmCTestMultiProcessHandler.cxx | 47 | ||||
-rw-r--r-- | Source/CTest/cmCTestMultiProcessHandler.h | 2 | ||||
-rw-r--r-- | Source/CTest/cmCTestRunTest.cxx | 54 | ||||
-rw-r--r-- | Source/CTest/cmCTestRunTest.h | 5 | ||||
-rw-r--r-- | Source/CTest/cmCTestScriptHandler.cxx | 2 | ||||
-rw-r--r-- | Source/CTest/cmCTestSubmitHandler.cxx | 19 | ||||
-rw-r--r-- | Source/CTest/cmCTestTestHandler.cxx | 11 | ||||
-rw-r--r-- | Source/CTest/cmCTestTestHandler.h | 2 | ||||
-rw-r--r-- | Source/CTest/cmProcess.cxx | 18 | ||||
-rw-r--r-- | Source/CTest/cmProcess.h | 2 |
14 files changed, 205 insertions, 22 deletions
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index 2e1ea4c..b2c68e7 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -11,6 +11,7 @@ #include "cmsys/Process.h" #include <chrono> +#include <cstring> #include <ratio> #include <stdlib.h> @@ -196,6 +197,16 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) cmSystemTools::MakeDirectory(this->BinaryDir); } cmWorkingDirectory workdir(this->BinaryDir); + if (workdir.Failed()) { + auto msg = "Failed to change working directory to " + this->BinaryDir + + " : " + std::strerror(workdir.GetLastResult()) + "\n"; + if (outstring) { + *outstring = msg; + } else { + cmCTestLog(this->CTest, ERROR_MESSAGE, msg); + } + return 1; + } if (this->BuildNoCMake) { // Make the generator available for the Build call below. @@ -307,7 +318,16 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) // run the test from the this->BuildRunDir if set if (!this->BuildRunDir.empty()) { out << "Run test in directory: " << this->BuildRunDir << "\n"; - cmSystemTools::ChangeDirectory(this->BuildRunDir); + if (!workdir.SetDirectory(this->BuildRunDir)) { + out << "Failed to change working directory : " + << std::strerror(workdir.GetLastResult()) << "\n"; + if (outstring) { + *outstring = out.str(); + } else { + cmCTestLog(this->CTest, ERROR_MESSAGE, out.str()); + } + return 1; + } } out << "Running test command: \"" << fullPath << "\""; for (std::string const& testCommandArg : this->TestCommandArgs) { diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 9c66e73..bafbe9a 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -23,6 +23,7 @@ #include "cmsys/RegularExpression.hxx" #include <algorithm> #include <chrono> +#include <cstring> #include <iomanip> #include <iterator> #include <sstream> @@ -927,7 +928,8 @@ int cmCTestCoverageHandler::HandleGCovCoverage( std::string gcovCommand = this->CTest->GetCTestConfiguration("CoverageCommand"); if (gcovCommand.empty()) { - cmCTestLog(this->CTest, WARNING, "Could not find gcov." << std::endl); + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "Could not find gcov." << std::endl, this->Quiet); return 0; } std::string gcovExtraFlags = @@ -975,7 +977,12 @@ int cmCTestCoverageHandler::HandleGCovCoverage( std::string testingDir = this->CTest->GetBinaryDir() + "/Testing"; std::string tempDir = testingDir + "/CoverageInfo"; - cmSystemTools::MakeDirectory(tempDir); + if (!cmSystemTools::MakeDirectory(tempDir)) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Unable to make directory: " << tempDir << std::endl); + cont->Error++; + return 0; + } cmWorkingDirectory workdir(tempDir); int gcovStyle = 0; @@ -1376,6 +1383,14 @@ int cmCTestCoverageHandler::HandleLCovCoverage( this->Quiet); std::string fileDir = cmSystemTools::GetFilenamePath(f); cmWorkingDirectory workdir(fileDir); + if (workdir.Failed()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Unable to change working directory to " + << fileDir << " : " + << std::strerror(workdir.GetLastResult()) << std::endl); + cont->Error++; + continue; + } cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Current coverage dir: " << fileDir << std::endl, @@ -1600,6 +1615,12 @@ bool cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files) gl.RecurseThroughSymlinksOff(); std::string buildDir = this->CTest->GetCTestConfiguration("BuildDirectory"); cmWorkingDirectory workdir(buildDir); + if (workdir.Failed()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Unable to change working directory to " << buildDir + << std::endl); + return false; + } // Run profmerge to merge all *.dyn files into dpi files if (!cmSystemTools::RunSingleCommand("profmerge")) { diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h index 427a392..86d9489 100644 --- a/Source/CTest/cmCTestCurl.h +++ b/Source/CTest/cmCTestCurl.h @@ -16,7 +16,7 @@ class cmCTestCurl public: cmCTestCurl(cmCTest*); ~cmCTestCurl(); - bool UploadFile(std::string const& url, std::string const& file, + bool UploadFile(std::string const& local_file, std::string const& url, std::string const& fields, std::string& response); bool HttpRequest(std::string const& url, std::string const& fields, std::string& response); diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index 5a7baf5..1fff2fa 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -9,6 +9,7 @@ #include "cmWorkingDirectory.h" #include "cmake.h" +#include <cstring> #include <sstream> #include <stdlib.h> @@ -218,6 +219,21 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, } cmWorkingDirectory workdir( this->CTest->GetCTestConfiguration("BuildDirectory")); + if (workdir.Failed()) { + this->SetError("failed to change directory to " + + this->CTest->GetCTestConfiguration("BuildDirectory") + + " : " + std::strerror(workdir.GetLastResult())); + if (capureCMakeError) { + this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR], + "-1"); + cmCTestLog(this->CTest, ERROR_MESSAGE, this->GetName() + << " " << this->GetError() << "\n"); + // return success because failure is recorded in CAPTURE_CMAKE_ERROR + return true; + } + return false; + } + int res = handler->ProcessHandler(); if (this->Values[ct_RETURN_VALUE] && *this->Values[ct_RETURN_VALUE]) { std::ostringstream str; diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 50c2d86..14b5caa 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestMultiProcessHandler.h" +#include "cmAffinity.h" #include "cmCTest.h" #include "cmCTestRunTest.h" #include "cmCTestScriptHandler.h" @@ -19,6 +20,7 @@ #include <algorithm> #include <chrono> +#include <cstring> #include <iomanip> #include <list> #include <math.h> @@ -53,6 +55,8 @@ cmCTestMultiProcessHandler::cmCTestMultiProcessHandler() this->TestLoad = 0; this->Completed = 0; this->RunningCount = 0; + this->ProcessorsAvailable = cmAffinity::GetProcessorsAvailable(); + this->HaveAffinity = this->ProcessorsAvailable.size(); this->StopTimePassed = false; this->HasCycles = false; this->SerialTestRunning = false; @@ -127,6 +131,21 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test) return false; } + if (this->HaveAffinity && this->Properties[test]->WantAffinity) { + size_t needProcessors = this->GetProcessorsUsed(test); + if (needProcessors > this->ProcessorsAvailable.size()) { + return false; + } + std::vector<size_t> affinity; + affinity.reserve(needProcessors); + for (size_t i = 0; i < needProcessors; ++i) { + auto p = this->ProcessorsAvailable.begin(); + affinity.push_back(*p); + this->ProcessorsAvailable.erase(p); + } + this->Properties[test]->Affinity = std::move(affinity); + } + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "test " << test << "\n", this->Quiet); this->TestRunningMap[test] = true; // mark the test as running @@ -151,13 +170,19 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test) } } - cmWorkingDirectory workdir(this->Properties[test]->Directory); - - // Lock the resources we'll be using + // Always lock the resources we'll be using, even if we fail to set the + // working directory because FinishTestProcess() will try to unlock them this->LockResources(test); - if (testRun->StartTest(this->Total)) { - return true; + cmWorkingDirectory workdir(this->Properties[test]->Directory); + if (workdir.Failed()) { + testRun->StartFailure("Failed to change working directory to " + + this->Properties[test]->Directory + " : " + + std::strerror(workdir.GetLastResult())); + } else { + if (testRun->StartTest(this->Total)) { + return true; + } } this->FinishTestProcess(testRun, false); @@ -200,6 +225,11 @@ inline size_t cmCTestMultiProcessHandler::GetProcessorsUsed(int test) if (processors > this->ParallelLevel) { processors = this->ParallelLevel; } + // Cap tests that want affinity to the maximum affinity available. + if (this->HaveAffinity && processors > this->HaveAffinity && + this->Properties[test]->WantAffinity) { + processors = this->HaveAffinity; + } return processors; } @@ -398,6 +428,11 @@ void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner, this->UnlockResources(test); this->RunningCount -= GetProcessorsUsed(test); + for (auto p : properties->Affinity) { + this->ProcessorsAvailable.insert(p); + } + properties->Affinity.clear(); + delete runner; if (started) { this->StartNextTests(); @@ -666,6 +701,8 @@ void cmCTestMultiProcessHandler::PrintTestList() count++; cmCTestTestHandler::cmCTestTestProperties& p = *it.second; + // Don't worry if this fails, we are only showing the test list, not + // running the tests cmWorkingDirectory workdir(p.Directory); cmCTestRunTest testRun(*this); diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index 7837ff9..19e1a35 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -119,6 +119,8 @@ protected: // Number of tests that are complete size_t Completed; size_t RunningCount; + std::set<size_t> ProcessorsAvailable; + size_t HaveAffinity; bool StopTimePassed; // list of test properties (indices concurrent to the test map) PropertiesMap Properties; diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 30ad38c..8d8ebaa 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -14,6 +14,7 @@ #include "cmsys/RegularExpression.hxx" #include <chrono> #include <cmAlgorithms.h> +#include <cstring> #include <iomanip> #include <ratio> #include <sstream> @@ -248,11 +249,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) *this->TestHandler->LogFile << "Test time = " << buf << std::endl; } - // Set the working directory to the tests directory to process Dart files. - { - cmWorkingDirectory workdir(this->TestProperties->Directory); - this->DartProcessing(); - } + this->DartProcessing(); // if this is doing MemCheck then all the output needs to be put into // Output since that is what is parsed by cmCTestMemCheckHandler @@ -338,6 +335,13 @@ bool cmCTestRunTest::StartAgain() this->RunAgain = false; // reset // change to tests directory cmWorkingDirectory workdir(this->TestProperties->Directory); + if (workdir.Failed()) { + this->StartFailure("Failed to change working directory to " + + this->TestProperties->Directory + " : " + + std::strerror(workdir.GetLastResult())); + return true; + } + this->StartTest(this->TotalNumberOfTests); return true; } @@ -386,6 +390,37 @@ void cmCTestRunTest::MemCheckPostProcess() handler->PostProcessTest(this->TestResult, this->Index); } +void cmCTestRunTest::StartFailure(std::string const& output) +{ + // Still need to log the Start message so the test summary records our + // attempt to start this test + cmCTestLog(this->CTest, HANDLER_OUTPUT, + std::setw(2 * getNumWidth(this->TotalNumberOfTests) + 8) + << "Start " + << std::setw(getNumWidth(this->TestHandler->GetMaxIndex())) + << this->TestProperties->Index << ": " + << this->TestProperties->Name << std::endl); + + this->ProcessOutput.clear(); + if (!output.empty()) { + *this->TestHandler->LogFile << output << std::endl; + cmCTestLog(this->CTest, ERROR_MESSAGE, output << std::endl); + } + + this->TestResult.Properties = this->TestProperties; + this->TestResult.ExecutionTime = cmDuration::zero(); + this->TestResult.CompressOutput = false; + this->TestResult.ReturnValue = -1; + this->TestResult.CompletionStatus = "Failed to start"; + this->TestResult.Status = cmCTestTestHandler::NOT_RUN; + this->TestResult.TestCount = this->TestProperties->Index; + this->TestResult.Name = this->TestProperties->Name; + this->TestResult.Path = this->TestProperties->Directory; + this->TestResult.Output = output; + this->TestResult.FullCommandLine.clear(); + this->TestProcess = cm::make_unique<cmProcess>(*this); +} + // Starts the execution of a test. Returns once it has started bool cmCTestRunTest::StartTest(size_t total) { @@ -515,7 +550,8 @@ bool cmCTestRunTest::StartTest(size_t total) } return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout, - &this->TestProperties->Environment); + &this->TestProperties->Environment, + &this->TestProperties->Affinity); } void cmCTestRunTest::ComputeArguments() @@ -591,7 +627,8 @@ void cmCTestRunTest::DartProcessing() } bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout, - std::vector<std::string>* environment) + std::vector<std::string>* environment, + std::vector<size_t>* affinity) { this->TestProcess = cm::make_unique<cmProcess>(*this); this->TestProcess->SetId(this->Index); @@ -637,7 +674,8 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout, cmSystemTools::AppendEnv(*environment); } - return this->TestProcess->StartProcess(this->MultiTestHandler.Loop); + return this->TestProcess->StartProcess(this->MultiTestHandler.Loop, + affinity); } void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total) diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index 4d57357..3b1d674 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -74,6 +74,8 @@ public: bool StartAgain(); + void StartFailure(std::string const& output); + cmCTest* GetCTest() const { return this->CTest; } void FinalizeTest(); @@ -83,7 +85,8 @@ private: void DartProcessing(); void ExeNotFound(std::string exe); bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout, - std::vector<std::string>* environment); + std::vector<std::string>* environment, + std::vector<size_t>* affinity); void WriteLogOutputTop(size_t completed, size_t total); // Run post processing of the process output for MemCheck void MemCheckPostProcess(); diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index e0bffd4..5fff730 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -527,7 +527,7 @@ int cmCTestScriptHandler::RunConfigurationScript( return result; } - // only run the curent script if we should + // only run the current script if we should if (this->Makefile && this->Makefile->IsOn("CTEST_RUN_CURRENT_SCRIPT") && this->ShouldRunCurrentScript) { return this->RunCurrentScript(); diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 08d05c8..3bab81e 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -7,6 +7,7 @@ #include "cm_jsoncpp_value.h" #include "cmsys/Process.h" #include <chrono> +#include <cstring> #include <sstream> #include <stdio.h> #include <stdlib.h> @@ -1532,6 +1533,15 @@ int cmCTestSubmitHandler::ProcessHandler() // change to the build directory so that we can uses a relative path // on windows since scp doesn't support "c:" a drive in the path cmWorkingDirectory workdir(buildDirectory); + if (workdir.Failed()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + " Failed to change directory to " + << buildDirectory << " : " + << std::strerror(workdir.GetLastResult()) << std::endl); + ofs << " Failed to change directory to " << buildDirectory << " : " + << std::strerror(workdir.GetLastResult()) << std::endl; + return -1; + } if (!this->SubmitUsingSCP(this->CTest->GetCTestConfiguration("ScpCommand"), "Testing/" + this->CTest->GetCurrentTag(), files, @@ -1551,6 +1561,15 @@ int cmCTestSubmitHandler::ProcessHandler() // change to the build directory so that we can uses a relative path // on windows since scp doesn't support "c:" a drive in the path cmWorkingDirectory workdir(buildDirectory); + if (workdir.Failed()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + " Failed to change directory to " + << buildDirectory << " : " + << std::strerror(workdir.GetLastResult()) << std::endl); + ofs << " Failed to change directory to " << buildDirectory << " : " + << std::strerror(workdir.GetLastResult()) << std::endl; + return -1; + } cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Change directory: " << buildDirectory << std::endl, this->Quiet); diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 84d8926..cbaf984 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -6,6 +6,7 @@ #include <cmsys/Base64.h> #include <cmsys/Directory.hxx> #include <cmsys/RegularExpression.hxx> +#include <cstring> #include <functional> #include <iomanip> #include <iterator> @@ -14,7 +15,6 @@ #include <sstream> #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <time.h> #include "cmAlgorithms.h" @@ -85,6 +85,11 @@ bool cmCTestSubdirCommand::InitialPass(std::vector<std::string> const& args, bool readit = false; { cmWorkingDirectory workdir(fname); + if (workdir.Failed()) { + this->SetError("Failed to change directory to " + fname + " : " + + std::strerror(workdir.GetLastResult())); + return false; + } const char* testFilename; if (cmSystemTools::FileExists("CTestTestfile.cmake")) { // does the CTestTestfile.cmake exist ? @@ -2165,6 +2170,9 @@ bool cmCTestTestHandler::SetTestsProperties( rt.Processors = 1; } } + if (key == "PROCESSOR_AFFINITY") { + rt.WantAffinity = cmSystemTools::IsOn(val.c_str()); + } if (key == "SKIP_RETURN_CODE") { rt.SkipReturnCode = atoi(val.c_str()); if (rt.SkipReturnCode < 0 || rt.SkipReturnCode > 255) { @@ -2336,6 +2344,7 @@ bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args) test.ExplicitTimeout = false; test.Cost = 0; test.Processors = 1; + test.WantAffinity = false; test.SkipReturnCode = -1; test.PreviousRuns = 0; if (this->UseIncludeRegExpFlag && diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index f4978b6..d2694a1 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -130,6 +130,8 @@ public: int Index; // Requested number of process slots int Processors; + bool WantAffinity; + std::vector<size_t> Affinity; // return code of test which will mark test as "not run" int SkipReturnCode; std::vector<std::string> Environment; diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 09ed0a9..5c9b169 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -83,7 +83,7 @@ void cmProcess::SetCommandArguments(std::vector<std::string> const& args) this->Arguments = args; } -bool cmProcess::StartProcess(uv_loop_t& loop) +bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity) { this->ProcessState = cmProcess::State::Error; if (this->Command.empty()) { @@ -138,6 +138,22 @@ bool cmProcess::StartProcess(uv_loop_t& loop) options.stdio_count = 3; // in, out and err options.exit_cb = &cmProcess::OnExitCB; options.stdio = stdio; +#if !defined(CMAKE_USE_SYSTEM_LIBUV) + std::vector<char> cpumask; + if (affinity && !affinity->empty()) { + cpumask.resize(static_cast<size_t>(uv_cpumask_size()), 0); + for (auto p : *affinity) { + cpumask[p] = 1; + } + options.cpumask = cpumask.data(); + options.cpumask_size = cpumask.size(); + } else { + options.cpumask = nullptr; + options.cpumask_size = 0; + } +#else + static_cast<void>(affinity); +#endif status = uv_read_start(pipe_reader, &cmProcess::OnAllocateCB, &cmProcess::OnReadCB); diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h index 20e24b9..b2d87fa 100644 --- a/Source/CTest/cmProcess.h +++ b/Source/CTest/cmProcess.h @@ -36,7 +36,7 @@ public: void ChangeTimeout(cmDuration t); void ResetStartTime(); // Return true if the process starts - bool StartProcess(uv_loop_t& loop); + bool StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity); enum class State { |