Commit 6f9aaad1 authored by Rolf Eike Beer's avatar Rolf Eike Beer
Browse files

CTest: create one output file per memcheck (#14303)

The output file used for memory checker runs must be unique for every test run
in parallel, so simply make them unique for every test run. Simply use the test
index to avoid collisions.
parent 7c9f0c66
......@@ -89,7 +89,7 @@ void cmCTestBatchTestHandler::WriteTestCommand(int test, std::fstream& fout)
command = cmSystemTools::ConvertToOutputPath(command.c_str());
//Prepends memcheck args to our command string if this is a memcheck
this->TestHandler->GenerateTestCommand(processArgs);
this->TestHandler->GenerateTestCommand(processArgs, test);
processArgs.push_back(command);
for(std::vector<std::string>::iterator arg = processArgs.begin();
......
......@@ -200,6 +200,7 @@ void cmCTestMemCheckHandler::Initialize()
this->CustomMaximumPassedTestOutputSize = 0;
this->CustomMaximumFailedTestOutputSize = 0;
this->MemoryTester = "";
this->MemoryTesterDynamicOptions.clear();
this->MemoryTesterOptions.clear();
this->MemoryTesterStyle = UNKNOWN;
this->MemoryTesterOutputFile = "";
......@@ -242,12 +243,28 @@ int cmCTestMemCheckHandler::PostProcessHandler()
//----------------------------------------------------------------------
void cmCTestMemCheckHandler::GenerateTestCommand(
std::vector<std::string>& args)
std::vector<std::string>& args, int test)
{
std::vector<cmStdString>::size_type pp;
std::string memcheckcommand = "";
memcheckcommand
cmStdString index;
cmOStringStream stream;
std::string memcheckcommand
= cmSystemTools::ConvertToOutputPath(this->MemoryTester.c_str());
stream << test;
index = stream.str();
for ( pp = 0; pp < this->MemoryTesterDynamicOptions.size(); pp ++ )
{
cmStdString arg = this->MemoryTesterDynamicOptions[pp];
cmStdString::size_type pos = arg.find("??");
if (pos != cmStdString::npos)
{
arg.replace(pos, 2, index);
}
args.push_back(arg);
memcheckcommand += " \"";
memcheckcommand += arg;
memcheckcommand += "\"";
}
for ( pp = 0; pp < this->MemoryTesterOptions.size(); pp ++ )
{
args.push_back(this->MemoryTesterOptions[pp]);
......@@ -478,7 +495,8 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
= cmSystemTools::ParseArguments(memoryTesterOptions.c_str());
this->MemoryTesterOutputFile
= this->CTest->GetBinaryDir() + "/Testing/Temporary/MemoryChecker.log";
= this->CTest->GetBinaryDir()
+ "/Testing/Temporary/MemoryChecker.??.log";
switch ( this->MemoryTesterStyle )
{
......@@ -510,7 +528,7 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
}
std::string outputFile = "--log-file="
+ this->MemoryTesterOutputFile;
this->MemoryTesterOptions.push_back(outputFile);
this->MemoryTesterDynamicOptions.push_back(outputFile);
break;
}
case cmCTestMemCheckHandler::PURIFY:
......@@ -538,19 +556,19 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
outputFile = "-log-file=";
#endif
outputFile += this->MemoryTesterOutputFile;
this->MemoryTesterOptions.push_back(outputFile);
this->MemoryTesterDynamicOptions.push_back(outputFile);
break;
}
case cmCTestMemCheckHandler::BOUNDS_CHECKER:
{
this->BoundsCheckerXMLFile = this->MemoryTesterOutputFile;
std::string dpbdFile = this->CTest->GetBinaryDir()
+ "/Testing/Temporary/MemoryChecker.DPbd";
+ "/Testing/Temporary/MemoryChecker.??.DPbd";
this->BoundsCheckerDPBDFile = dpbdFile;
this->MemoryTesterOptions.push_back("/B");
this->MemoryTesterOptions.push_back(dpbdFile);
this->MemoryTesterOptions.push_back("/X");
this->MemoryTesterOptions.push_back(this->MemoryTesterOutputFile);
this->MemoryTesterDynamicOptions.push_back("/B");
this->MemoryTesterDynamicOptions.push_back(dpbdFile);
this->MemoryTesterDynamicOptions.push_back("/X");
this->MemoryTesterDynamicOptions.push_back(this->MemoryTesterOutputFile);
this->MemoryTesterOptions.push_back("/M");
break;
}
......@@ -898,25 +916,23 @@ bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput(
// This method puts the bounds checker output file into the output
// for the test
void
cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(cmCTestTestResult& res)
cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(cmCTestTestResult& res,
int test)
{
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"PostProcessBoundsCheckerTest for : "
<< res.Name.c_str() << std::endl);
if ( !cmSystemTools::FileExists(this->MemoryTesterOutputFile.c_str()) )
cmStdString ofile = testOutputFileName(test);
if ( ofile.empty() )
{
std::string log = "Cannot find memory tester output file: "
+ this->MemoryTesterOutputFile;
cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl);
return;
}
// put a scope around this to close ifs so the file can be removed
{
std::ifstream ifs(this->MemoryTesterOutputFile.c_str());
std::ifstream ifs(ofile.c_str());
if ( !ifs )
{
std::string log = "Cannot read memory tester output file: "
+ this->MemoryTesterOutputFile;
std::string log = "Cannot read memory tester output file: " + ofile;
cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl);
return;
}
......@@ -939,38 +955,39 @@ cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(cmCTestTestResult& res)
}
void
cmCTestMemCheckHandler::PostProcessPurifyTest(cmCTestTestResult& res)
cmCTestMemCheckHandler::PostProcessPurifyTest(cmCTestTestResult& res,
int test)
{
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"PostProcessPurifyTest for : "
<< res.Name.c_str() << std::endl);
appendMemTesterOutput(res);
appendMemTesterOutput(res, test);
}
void
cmCTestMemCheckHandler::PostProcessValgrindTest(cmCTestTestResult& res)
cmCTestMemCheckHandler::PostProcessValgrindTest(cmCTestTestResult& res,
int test)
{
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"PostProcessValgrindTest for : "
<< res.Name.c_str() << std::endl);
appendMemTesterOutput(res);
appendMemTesterOutput(res, test);
}
void
cmCTestMemCheckHandler::appendMemTesterOutput(cmCTestTestResult& res)
cmCTestMemCheckHandler::appendMemTesterOutput(cmCTestTestResult& res,
int test)
{
if ( !cmSystemTools::FileExists(this->MemoryTesterOutputFile.c_str()) )
cmStdString ofile = testOutputFileName(test);
if ( ofile.empty() )
{
std::string log = "Cannot find memory tester output file: "
+ this->MemoryTesterOutputFile;
cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl);
return;
}
std::ifstream ifs(this->MemoryTesterOutputFile.c_str());
std::ifstream ifs(ofile.c_str());
if ( !ifs )
{
std::string log = "Cannot read memory tester output file: "
+ this->MemoryTesterOutputFile;
std::string log = "Cannot read memory tester output file: " + ofile;
cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl);
return;
}
......@@ -981,3 +998,25 @@ cmCTestMemCheckHandler::appendMemTesterOutput(cmCTestTestResult& res)
res.Output += "\n";
}
}
cmStdString
cmCTestMemCheckHandler::testOutputFileName(int test)
{
cmStdString index;
cmOStringStream stream;
stream << test;
index = stream.str();
cmStdString ofile = this->MemoryTesterOutputFile;
cmStdString::size_type pos = ofile.find("??");
ofile.replace(pos, 2, index);
if ( !cmSystemTools::FileExists(ofile.c_str()) )
{
std::string log = "Cannot find memory tester output file: "
+ ofile;
cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl);
ofile = "";
}
return ofile;
}
......@@ -37,7 +37,7 @@ public:
protected:
virtual int PreProcessHandler();
virtual int PostProcessHandler();
virtual void GenerateTestCommand(std::vector<std::string>& args);
virtual void GenerateTestCommand(std::vector<std::string>& args, int test);
private:
......@@ -89,6 +89,7 @@ private:
std::string BoundsCheckerDPBDFile;
std::string BoundsCheckerXMLFile;
std::string MemoryTester;
std::vector<cmStdString> MemoryTesterDynamicOptions;
std::vector<cmStdString> MemoryTesterOptions;
int MemoryTesterStyle;
std::string MemoryTesterOutputFile;
......@@ -117,12 +118,16 @@ private:
bool ProcessMemCheckBoundsCheckerOutput(const std::string& str,
std::string& log, int* results);
void PostProcessPurifyTest(cmCTestTestResult& res);
void PostProcessBoundsCheckerTest(cmCTestTestResult& res);
void PostProcessValgrindTest(cmCTestTestResult& res);
void PostProcessPurifyTest(cmCTestTestResult& res, int test);
void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test);
void PostProcessValgrindTest(cmCTestTestResult& res, int test);
///! append MemoryTesterOutputFile to the test log
void appendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res);
void appendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res,
int test);
///! generate the output filename for the given test index
cmStdString testOutputFileName(int test);
};
#endif
......
......@@ -389,13 +389,13 @@ void cmCTestRunTest::MemCheckPostProcess()
switch ( handler->MemoryTesterStyle )
{
case cmCTestMemCheckHandler::VALGRIND:
handler->PostProcessValgrindTest(this->TestResult);
handler->PostProcessValgrindTest(this->TestResult, this->Index);
break;
case cmCTestMemCheckHandler::PURIFY:
handler->PostProcessPurifyTest(this->TestResult);
handler->PostProcessPurifyTest(this->TestResult, this->Index);
break;
case cmCTestMemCheckHandler::BOUNDS_CHECKER:
handler->PostProcessBoundsCheckerTest(this->TestResult);
handler->PostProcessBoundsCheckerTest(this->TestResult, this->Index);
break;
default:
break;
......@@ -524,7 +524,7 @@ void cmCTestRunTest::ComputeArguments()
= cmSystemTools::ConvertToOutputPath(this->ActualCommand.c_str());
//Prepends memcheck args to our command string
this->TestHandler->GenerateTestCommand(this->Arguments);
this->TestHandler->GenerateTestCommand(this->Arguments, this->Index);
for(std::vector<std::string>::iterator i = this->Arguments.begin();
i != this->Arguments.end(); ++i)
{
......
......@@ -1107,7 +1107,7 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
}
//----------------------------------------------------------------------
void cmCTestTestHandler::GenerateTestCommand(std::vector<std::string>&)
void cmCTestTestHandler::GenerateTestCommand(std::vector<std::string>&, int)
{
}
......
......@@ -153,7 +153,7 @@ protected:
// compute a final test list
virtual int PreProcessHandler();
virtual int PostProcessHandler();
virtual void GenerateTestCommand(std::vector<std::string>& args);
virtual void GenerateTestCommand(std::vector<std::string>& args, int test);
int ExecuteCommands(std::vector<cmStdString>& vec);
void WriteTestResultHeader(std::ostream& os, cmCTestTestResult* result);
......
......@@ -66,6 +66,7 @@ function(gen_mc_test NAME CHECKER)
-D PSEUDO_PURIFY=$<TARGET_FILE:pseudo_purify>
-D PSEUDO_VALGRIND=$<TARGET_FILE:pseudo_valgrind>
-D ERROR_COMMAND=$<TARGET_FILE:memcheck_fail>
${ARGN}
)
endfunction(gen_mc_test)
......@@ -74,10 +75,11 @@ function(gen_mcnl_test NAME CHECKER)
-D PSEUDO_BC=$<TARGET_FILE:pseudonl_BC>
-D PSEUDO_PURIFY=$<TARGET_FILE:pseudonl_purify>
-D PSEUDO_VALGRIND=$<TARGET_FILE:pseudonl_valgrind>
${ARGN}
)
set_tests_properties(CTestTestMemcheck${NAME}
PROPERTIES
PASS_REGULAR_EXPRESSION "\nCannot find memory tester output file: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/${NAME}/Testing/Temporary/MemoryChecker.log\n(.*\n)?Error in read script: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/${NAME}/test.cmake\n")
PASS_REGULAR_EXPRESSION "\nCannot find memory tester output file: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/${NAME}/Testing/Temporary/MemoryChecker.1.log\n(.*\n)?Error in read script: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/${NAME}/test.cmake\n")
endfunction(gen_mcnl_test)
unset(CTEST_EXTRA_CONFIG)
......@@ -109,14 +111,17 @@ set(CTEST_EXTRA_CONFIG "set(CTEST_CUSTOM_MEMCHECK_IGNORE RunCMakeAgain)\n")
set(CMAKELISTS_EXTRA_CODE "add_test(NAME RunCMakeAgain COMMAND \"\${CMAKE_COMMAND}\" --version)")
gen_mc_test(DummyValgrindIgnoreMemcheck "\${PSEUDO_VALGRIND}")
unset(CTEST_EXTRA_CONFIG)
gen_mc_test(DummyValgrindTwoTargets "\${PSEUDO_VALGRIND}" "-VV")
set(CTEST_EXTRA_CONFIG "set(CTEST_MEMORYCHECK_SUPPRESSIONS_FILE \"\${CMAKE_CURRENT_BINARY_DIR}/does-not-exist\")")
unset(CMAKELISTS_EXTRA_CODE)
gen_mc_test(DummyValgrindInvalidSupFile "\${PSEUDO_VALGRIND}")
# CTest will add the logfile option as last option. Tell the dummy memcheck
# to ignore that argument. This will cause the logfile to be missing, which
# will be the prove for us that the custom option is indeed used.
set(CTEST_EXTRA_CONFIG "set(CTEST_MEMORYCHECK_COMMAND_OPTIONS \"--\")")
# CTest will add the logfile option before any custom options. Set the logfile
# again, this time to an empty string. This will cause the logfile to be
# missing, which will be the prove for us that the custom option is indeed used.
set(CTEST_EXTRA_CONFIG "set(CTEST_MEMORYCHECK_COMMAND_OPTIONS \"--log-file=\")")
gen_mc_test(DummyValgrindCustomOptions "\${PSEUDO_VALGRIND}")
unset(CTEST_EXTRA_CONFIG)
......@@ -161,4 +166,8 @@ set_tests_properties(CTestTestMemcheckDummyValgrindInvalidSupFile PROPERTIES
PASS_REGULAR_EXPRESSION "\nCannot find memory checker suppression file: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/does-not-exist\n")
set_tests_properties(CTestTestMemcheckDummyValgrindCustomOptions PROPERTIES
PASS_REGULAR_EXPRESSION "\nCannot find memory tester output file: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindCustomOptions/Testing/Temporary/MemoryChecker.log\n(.*\n)?Error in read script: ${CMAKE_CURRENT_BINARY_DIR}/DummyValgrindCustomOptions/test.cmake\n")
PASS_REGULAR_EXPRESSION "\nCannot find memory tester output file: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindCustomOptions/Testing/Temporary/MemoryChecker.1.log\n(.*\n)?Error in read script: ${CMAKE_CURRENT_BINARY_DIR}/DummyValgrindCustomOptions/test.cmake\n")
set_tests_properties(CTestTestMemcheckDummyValgrindTwoTargets PROPERTIES
PASS_REGULAR_EXPRESSION
"\nMemory check project ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets\n.*\n *Start 1: RunCMake\n(.*\n)?Memory check command: .* \"--log-file=${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets/Testing/Temporary/MemoryChecker.1.log\" \"-q\".*\n *Start 2: RunCMakeAgain\n(.*\n)?Memory check command: .* \"--log-file=${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets/Testing/Temporary/MemoryChecker.2.log\" \"-q\".*\n")
......@@ -28,12 +28,6 @@ main(int argc, char **argv)
std::string logfile;
for (int i = 1; i < argc; i++) {
std::string arg = argv[i];
// stop processing options, this allows to force
// the logfile to be ignored
if (arg == "--")
{
break;
}
if (arg.find(logarg) == 0)
{
if (nextarg)
......@@ -46,7 +40,7 @@ main(int argc, char **argv)
{
logfile = arg.substr(logarg.length());
}
break;
// keep searching, it may be overridden later to provoke an error
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment