-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Fix #11750 (refactor ctu-info to generate fewer artifacts on disk) #6778
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -129,6 +129,10 @@ namespace { | |
| return !mCriticalErrors.empty(); | ||
| } | ||
|
|
||
| const std::string& getCtuInfo() const { | ||
| return mCtuInfo; | ||
| } | ||
|
|
||
| private: | ||
| /** | ||
| * Information about progress is directed here. This should be | ||
|
|
@@ -170,9 +174,14 @@ namespace { | |
| std::set<std::string> mActiveCheckers; | ||
|
|
||
| /** | ||
| * True if there are critical errors | ||
| * List of critical errors | ||
| */ | ||
| std::string mCriticalErrors; | ||
|
|
||
| /** | ||
| * CTU information | ||
| */ | ||
| std::string mCtuInfo; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this safe in terms of memory usage? I have not really understood what this is doing yet (maybe add some explanation to the PR) but appears to accumulate the the data in the memory and this could be megabytes in size or even much, much more.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should check it but my hypothesis is that the ctu info will not be huge.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. about memory usage, here is one small test case: cppcheck/test/cli/whole-program
in this test case ~160 bytes source code generates ~450 bytes ctu-info I don't think that memory usage will be a large issue. If we pretend that scanning a large project with 160MB source code would require 450MB memory for ctu info.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. But that has to be constructed as a string and is required to be continuous memory. And we also need to profile that. That sounds like it might slow down things quite a bit. Maybe we might need both modes? |
||
| }; | ||
| } | ||
|
|
||
|
|
@@ -292,7 +301,7 @@ int CppCheckExecutor::check_internal(const Settings& settings) const | |
| #endif | ||
| } | ||
|
|
||
| returnValue |= cppcheck.analyseWholeProgram(settings.buildDir, mFiles, mFileSettings); | ||
| returnValue |= cppcheck.analyseWholeProgram(settings.buildDir, mFiles, mFileSettings, stdLogger.getCtuInfo()); | ||
|
|
||
| if (settings.severity.isEnabled(Severity::information) || settings.checkConfiguration) { | ||
| const bool err = reportSuppressions(settings, suppressions, settings.checks.isEnabled(Checks::unusedFunction), mFiles, mFileSettings, stdLogger); | ||
|
|
@@ -430,6 +439,11 @@ void StdLogger::reportErr(const ErrorMessage &msg) | |
| return; | ||
| } | ||
|
|
||
| if (msg.severity == Severity::internal && msg.id == "ctuinfo") { | ||
| mCtuInfo += msg.shortMessage() + "\n"; | ||
| return; | ||
| } | ||
|
|
||
| if (ErrorLogger::isCriticalErrorId(msg.id) && mCriticalErrors.find(msg.id) == std::string::npos) { | ||
| if (!mCriticalErrors.empty()) | ||
| mCriticalErrors += ", "; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -139,7 +139,7 @@ static std::string getDumpFileName(const Settings& settings, const std::string& | |
| return settings.dumpFile; | ||
|
|
||
| std::string extension; | ||
| if (settings.dump) | ||
| if (settings.dump || !settings.buildDir.empty()) | ||
| extension = ".dump"; | ||
| else | ||
| extension = "." + std::to_string(settings.pid) + ".dump"; | ||
|
|
@@ -167,7 +167,7 @@ static void createDumpFile(const Settings& settings, | |
| if (!fdump.is_open()) | ||
| return; | ||
|
|
||
| { | ||
| if (!settings.buildDir.empty()) { | ||
| std::ofstream fout(getCtuInfoFileName(dumpFile)); | ||
| } | ||
|
|
||
|
|
@@ -1418,8 +1418,7 @@ void CppCheck::executeAddons(const std::vector<std::string>& files, const std::s | |
| std::string fileList; | ||
|
|
||
| if (files.size() >= 2 || endsWith(files[0], ".ctu-info")) { | ||
| fileList = Path::getPathFromFilename(files[0]) + FILELIST + std::to_string(mSettings.pid); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removing the unique identifier (pid) from the filename re-introduces the issue this was fixing - parallel executions writing the same file. This is exposed by running the Python tests with
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh no!! :-(
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I am seeing the same bug, but not totally sure. This repo helps reproduce a concurrency problem on my Linux machine
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A quick fix is simply adding back the pid to the filename. Will take a look later - I totally forgot about it.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I have done that with #7082. Feel free to review it.. |
||
| filesDeleter.addFile(fileList); | ||
| fileList = Path::getPathFromFilename(files[0]) + FILELIST; | ||
| std::ofstream fout(fileList); | ||
| for (const std::string& f: files) | ||
| fout << f << std::endl; | ||
|
|
@@ -1428,6 +1427,8 @@ void CppCheck::executeAddons(const std::vector<std::string>& files, const std::s | |
| // ensure all addons have already been resolved - TODO: remove when settings are const after creation | ||
| assert(mSettings.addonInfos.size() == mSettings.addons.size()); | ||
|
|
||
| std::string ctuInfo; | ||
|
|
||
| for (const AddonInfo &addonInfo : mSettings.addonInfos) { | ||
| if (addonInfo.name != "misra" && !addonInfo.ctu && endsWith(files.back(), ".ctu-info")) | ||
| continue; | ||
|
|
@@ -1444,6 +1445,18 @@ void CppCheck::executeAddons(const std::vector<std::string>& files, const std::s | |
|
|
||
| ErrorMessage errmsg; | ||
|
|
||
| if (obj.count("summary") > 0) { | ||
| if (!mSettings.buildDir.empty()) { | ||
| ctuInfo += res.serialize() + "\n"; | ||
| } else { | ||
| errmsg.severity = Severity::internal; | ||
| errmsg.id = "ctuinfo"; | ||
| errmsg.setmsg(res.serialize()); | ||
| reportErr(errmsg); | ||
| } | ||
| continue; | ||
| } | ||
|
|
||
| if (obj.count("file") > 0) { | ||
| std::string fileName = obj["file"].get<std::string>(); | ||
| const int64_t lineNumber = obj["linenr"].get<int64_t>(); | ||
|
|
@@ -1482,13 +1495,30 @@ void CppCheck::executeAddons(const std::vector<std::string>& files, const std::s | |
| reportErr(errmsg); | ||
| } | ||
| } | ||
|
|
||
| if (!mSettings.buildDir.empty() && fileList.empty()) { | ||
| const std::string& ctuInfoFile = getCtuInfoFileName(files[0]); | ||
| std::ofstream fout(ctuInfoFile); | ||
| fout << ctuInfo; | ||
| } | ||
| } | ||
|
|
||
| void CppCheck::executeAddonsWholeProgram(const std::list<FileWithDetails> &files, const std::list<FileSettings>& fileSettings) | ||
| void CppCheck::executeAddonsWholeProgram(const std::list<FileWithDetails> &files, const std::list<FileSettings>& fileSettings, const std::string& ctuInfo) | ||
| { | ||
| if (mSettings.addons.empty()) | ||
| return; | ||
|
|
||
| if (mSettings.buildDir.empty()) { | ||
| const std::string fileName = std::to_string(mSettings.pid) + ".ctu-info"; | ||
| FilesDeleter filesDeleter; | ||
| filesDeleter.addFile(fileName); | ||
| std::ofstream fout(fileName); | ||
| fout << ctuInfo; | ||
| fout.close(); | ||
| executeAddons({fileName}, ""); | ||
| return; | ||
| } | ||
|
|
||
| std::vector<std::string> ctuInfoFiles; | ||
| for (const auto &f: files) { | ||
| const std::string &dumpFileName = getDumpFileName(mSettings, f.path()); | ||
|
|
@@ -1506,11 +1536,6 @@ void CppCheck::executeAddonsWholeProgram(const std::list<FileWithDetails> &files | |
| const ErrorMessage errmsg = ErrorMessage::fromInternalError(e, nullptr, "", "Bailing out from analysis: Whole program analysis failed"); | ||
| reportErr(errmsg); | ||
| } | ||
|
|
||
| if (mSettings.buildDir.empty()) { | ||
| for (const std::string &f: ctuInfoFiles) | ||
| std::remove(f.c_str()); | ||
| } | ||
| } | ||
|
|
||
| Settings &CppCheck::settings() | ||
|
|
@@ -1806,13 +1831,9 @@ bool CppCheck::analyseWholeProgram() | |
| return errors && (mExitCode > 0); | ||
| } | ||
|
|
||
| unsigned int CppCheck::analyseWholeProgram(const std::string &buildDir, const std::list<FileWithDetails> &files, const std::list<FileSettings>& fileSettings) | ||
| unsigned int CppCheck::analyseWholeProgram(const std::string &buildDir, const std::list<FileWithDetails> &files, const std::list<FileSettings>& fileSettings, const std::string& ctuInfo) | ||
| { | ||
| executeAddonsWholeProgram(files, fileSettings); | ||
| if (buildDir.empty()) { | ||
| removeCtuInfoFiles(files, fileSettings); | ||
| return mExitCode; | ||
| } | ||
| executeAddonsWholeProgram(files, fileSettings, ctuInfo); | ||
| if (mSettings.checks.isEnabled(Checks::unusedFunction)) | ||
| CheckUnusedFunctions::analyseWholeProgram(mSettings, *this, buildDir); | ||
| std::list<Check::FileInfo*> fileInfoList; | ||
|
|
@@ -1876,22 +1897,6 @@ unsigned int CppCheck::analyseWholeProgram(const std::string &buildDir, const st | |
| return mExitCode; | ||
| } | ||
|
|
||
| void CppCheck::removeCtuInfoFiles(const std::list<FileWithDetails> &files, const std::list<FileSettings>& fileSettings) | ||
| { | ||
| if (mSettings.buildDir.empty()) { | ||
| for (const auto& f: files) { | ||
| const std::string &dumpFileName = getDumpFileName(mSettings, f.path()); | ||
| const std::string &ctuInfoFileName = getCtuInfoFileName(dumpFileName); | ||
| std::remove(ctuInfoFileName.c_str()); | ||
| } | ||
| for (const auto& fs: fileSettings) { | ||
| const std::string &dumpFileName = getDumpFileName(mSettings, fs.filename()); | ||
| const std::string &ctuInfoFileName = getCtuInfoFileName(dumpFileName); | ||
| std::remove(ctuInfoFileName.c_str()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // cppcheck-suppress unusedFunction - only used in tests | ||
| void CppCheck::resetTimerResults() | ||
| { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels a bit strange that this lives in the just remotely related logger. I wonder if all the logic should live in its own object and cleanup should be RAII-based and such.
That would be similar to what I tried in #6634 which comes up short in making it a local object because it needs to intercept the logged error at some point (which also applies to the code here). So adding some kind of hook into the error logging which std, XML and CTU (and even SARIF) could use would make a lot of sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if I understand these comments fully.
I do feel the ctu info belongs in cli and gui rather than lib. it's aggregated info from all threads. For me it's reasonable that CppcheckExecutor owns the data (directly or indirectly) however I can agree that the functionality does not technically belong in StdLogger actually.
We also have the mActiveCheckers and mCriticalErrors. Those do not really fit very well in the StdLogger neither.
I do not see a very elegant way to insert hooks. We could add one more ErrorLogger that owns the StdLogger?
Do you have better ideas..?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I still suggest to put the condition in StdLogger that ensures the output is formatted with sarif/text/xml so it will take a ErrorMessage input and output the proper string..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, again something in this file turns into a grab-bag after things got sorted out at some point.
This is not something we need to solve in this PR. I will see if I am put together a PR with the proposed hook based on the previously linked cleanup.