diff --git a/Makefile b/Makefile index 02735d36ee8..b82b924e1d9 100644 --- a/Makefile +++ b/Makefile @@ -695,7 +695,7 @@ $(libcppdir)/vfvalue.o: lib/vfvalue.cpp lib/config.h lib/errortypes.h lib/mathli frontend/frontend.o: frontend/frontend.cpp frontend/frontend.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_FE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ frontend/frontend.cpp -cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h lib/xml.h +cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h lib/xml.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cmdlineparser.cpp cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/sehwrapper.h cli/signalhandler.h cli/singleexecutor.h cli/threadexecutor.h externals/picojson/picojson.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/checkersreport.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/sarifreport.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h @@ -776,7 +776,7 @@ test/testclangimport.o: test/testclangimport.cpp lib/addoninfo.h lib/check.h lib test/testclass.o: test/testclass.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testclass.cpp -test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h +test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcmdlineparser.cpp test/testcolor.o: test/testcolor.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h @@ -917,7 +917,7 @@ test/testsymboldatabase.o: test/testsymboldatabase.cpp lib/addoninfo.h lib/check test/testthreadexecutor.o: test/testthreadexecutor.cpp cli/executor.h cli/threadexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testthreadexecutor.cpp -test/testtimer.o: test/testtimer.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/timer.h lib/utils.h test/fixture.h +test/testtimer.o: test/testtimer.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/timer.h lib/utils.h test/fixture.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtimer.cpp test/testtoken.o: test/testtoken.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 552af42ab71..2069c89579c 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -36,7 +36,6 @@ #include "settings.h" #include "standards.h" #include "suppressions.h" -#include "timer.h" #include "utils.h" #include "frontend.h" @@ -1430,17 +1429,17 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a else if (std::strncmp(argv[i], "--showtime=", 11) == 0) { const std::string showtimeMode = argv[i] + 11; if (showtimeMode == "file") - mSettings.showtime = ShowTime::FILE; + mSettings.showtime = Settings::ShowTime::FILE; else if (showtimeMode == "file-total") - mSettings.showtime = ShowTime::FILE_TOTAL; + mSettings.showtime = Settings::ShowTime::FILE_TOTAL; else if (showtimeMode == "summary") - mSettings.showtime = ShowTime::SUMMARY; + mSettings.showtime = Settings::ShowTime::SUMMARY; else if (showtimeMode == "top5_file") - mSettings.showtime = ShowTime::TOP5_FILE; + mSettings.showtime = Settings::ShowTime::TOP5_FILE; else if (showtimeMode == "top5_summary") - mSettings.showtime = ShowTime::TOP5_SUMMARY; + mSettings.showtime = Settings::ShowTime::TOP5_SUMMARY; else if (showtimeMode == "none") - mSettings.showtime = ShowTime::NONE; + mSettings.showtime = Settings::ShowTime::NONE; else if (showtimeMode.empty()) { mLogger.printError("no mode provided for --showtime"); return Result::Fail; diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 680f7387c70..5fb4d89855d 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -268,8 +269,8 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) } std::unique_ptr overallTimer; - if (settings.showtime == ShowTime::SUMMARY || settings.showtime == ShowTime::TOP5_SUMMARY) - overallTimer.reset(new OneShotTimer("Overall time", settings.showtime)); + if (settings.showtime == Settings::ShowTime::SUMMARY || settings.showtime == Settings::ShowTime::TOP5_SUMMARY) + overallTimer.reset(new OneShotTimer("Overall time")); settings.loadSummaries(); @@ -420,7 +421,9 @@ bool CppCheckExecutor::reportUnmatchedSuppressions(const Settings &settings, con int CppCheckExecutor::check_internal(const Settings& settings, Suppressions& supprs) const { StdLogger stdLogger(settings); - TimerResults timerResults; + std::unique_ptr timerResults; + if (settings.showtime != Settings::ShowTime::NONE) + timerResults.reset(new TimerResults); if (settings.reportProgress >= 0) stdLogger.resetLatestProgressOutputTime(); @@ -441,31 +444,35 @@ int CppCheckExecutor::check_internal(const Settings& settings, Suppressions& sup if (!settings.checkersReportFilename.empty()) std::remove(settings.checkersReportFilename.c_str()); - CppCheck cppcheck(settings, supprs, stdLogger, &timerResults, true, executeCommand); + CppCheck cppcheck(settings, supprs, stdLogger, timerResults.get(), true, executeCommand); unsigned int returnValue = 0; if (settings.useSingleJob()) { // Single process - SingleExecutor executor(cppcheck, mFiles, mFileSettings, settings, supprs, stdLogger, &timerResults); + SingleExecutor executor(cppcheck, mFiles, mFileSettings, settings, supprs, stdLogger, timerResults.get()); returnValue = executor.check(); } else { #if defined(HAS_THREADING_MODEL_THREAD) if (settings.executor == Settings::ExecutorType::Thread) { - ThreadExecutor executor(mFiles, mFileSettings, settings, supprs, stdLogger, &timerResults, CppCheckExecutor::executeCommand); + ThreadExecutor executor(mFiles, mFileSettings, settings, supprs, stdLogger, timerResults.get(), CppCheckExecutor::executeCommand); returnValue = executor.check(); } #endif #if defined(HAS_THREADING_MODEL_FORK) if (settings.executor == Settings::ExecutorType::Process) { - ProcessExecutor executor(mFiles, mFileSettings, settings, supprs, stdLogger, &timerResults, CppCheckExecutor::executeCommand); + ProcessExecutor executor(mFiles, mFileSettings, settings, supprs, stdLogger, timerResults.get(), CppCheckExecutor::executeCommand); returnValue = executor.check(); } #endif } // TODO: show time *after* the whole program analysis - if (settings.showtime == ShowTime::SUMMARY || settings.showtime == ShowTime::TOP5_SUMMARY) - timerResults.showResults(settings.showtime); + if (timerResults) { + if (settings.showtime == Settings::ShowTime::SUMMARY) + timerResults->showResults(); + else if (settings.showtime == Settings::ShowTime::TOP5_SUMMARY) + timerResults->showResults(5); + } // TODO: is this run again instead of using previously cached results? returnValue |= cppcheck.analyseWholeProgram(settings.buildDir, mFiles, mFileSettings, stdLogger.getCtuInfo()); diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index db2b2e5091a..a1b9d558acd 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -924,8 +924,8 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str return mLogger->exitcode(); std::unique_ptr checkTimeTimer; - if (mSettings.showtime == ShowTime::FILE || mSettings.showtime == ShowTime::FILE_TOTAL || mSettings.showtime == ShowTime::TOP5_FILE) - checkTimeTimer.reset(new OneShotTimer("Check time: " + file.spath(), mSettings.showtime)); + if (mSettings.showtime == Settings::ShowTime::FILE || mSettings.showtime == Settings::ShowTime::FILE_TOTAL || mSettings.showtime == Settings::ShowTime::TOP5_FILE) + checkTimeTimer.reset(new OneShotTimer("Check time: " + file.spath())); if (!mSettings.quiet) { std::string fixedpath = Path::toNativeSeparators(file.spath()); @@ -1045,7 +1045,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str // Get configurations.. std::set configurations; if (maxConfigs > 1) { - Timer::run("Preprocessor::getConfigs", mSettings.showtime, mTimerResults, [&]() { + Timer::run("Preprocessor::getConfigs", mTimerResults, [&]() { configurations = preprocessor.getConfigs(); }); } else { @@ -1130,7 +1130,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str if (mSettings.preprocessOnly) { std::string codeWithoutCfg; - Timer::run("Preprocessor::getcode", mSettings.showtime, mTimerResults, [&]() { + Timer::run("Preprocessor::getcode", mTimerResults, [&]() { codeWithoutCfg = preprocessor.getcode(currentConfig, files, true); }); @@ -1154,7 +1154,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str { bool skipCfg = false; // Create tokens, skip rest of iteration if failed - Timer::run("Tokenizer::createTokens", mSettings.showtime, mTimerResults, [&]() { + Timer::run("Tokenizer::createTokens", mTimerResults, [&]() { simplecpp::OutputList outputList_cfg; simplecpp::TokenList tokensP = preprocessor.preprocess(currentConfig, files, outputList_cfg); const simplecpp::Output* o = preprocessor.handleErrors(outputList_cfg); @@ -1180,7 +1180,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str Tokenizer tokenizer(std::move(tokenlist), mErrorLogger); try { - if (mSettings.showtime != ShowTime::NONE) + if (mSettings.showtime != Settings::ShowTime::NONE) tokenizer.setTimerResults(mTimerResults); tokenizer.setDirectives(directives); // TODO: how to avoid repeated copies? @@ -1294,8 +1294,12 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str // TODO: clear earlier? mLogger->clear(); - if (mTimerResults && (mSettings.showtime == ShowTime::FILE || mSettings.showtime == ShowTime::TOP5_FILE)) - mTimerResults->showResults(mSettings.showtime); + if (mTimerResults) { + if (mSettings.showtime == Settings::ShowTime::FILE) + mTimerResults->showResults(); + else if (mSettings.showtime == Settings::ShowTime::TOP5_FILE) + mTimerResults->showResults(5); + } return mLogger->exitcode(); } @@ -1354,7 +1358,7 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer, AnalyzerInformation return; } - Timer::run(check->name() + "::runChecks", mSettings.showtime, mTimerResults, [&]() { + Timer::run(check->name() + "::runChecks", mTimerResults, [&]() { check->runChecks(tokenizer, &mErrorLogger); }); } @@ -1489,7 +1493,7 @@ void CppCheck::executeAddons(const std::string& dumpFile, const FileWithDetails& { if (!dumpFile.empty()) { std::vector f{dumpFile}; - Timer::run("CppCheck::executeAddons", mSettings.showtime, mTimerResults, [&]() { + Timer::run("CppCheck::executeAddons", mTimerResults, [&]() { executeAddons(f, file.spath()); }); } diff --git a/lib/settings.h b/lib/settings.h index 85da57c4458..b7b23675aae 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -53,7 +53,6 @@ class Regex; #endif struct Suppressions; -enum class ShowTime : std::uint8_t; namespace ValueFlow { class Value; } @@ -442,6 +441,15 @@ class CPPCHECKLIB WARN_UNUSED Settings { SimpleEnableGroup certainty; SimpleEnableGroup checks; + enum class ShowTime : std::uint8_t { + NONE, + FILE, + FILE_TOTAL, + SUMMARY, + TOP5_SUMMARY, + TOP5_FILE + }; + /** @brief show timing information (--showtime=file|summary|top5) */ ShowTime showtime{}; diff --git a/lib/timer.cpp b/lib/timer.cpp index f4025fb3427..275acc06078 100644 --- a/lib/timer.cpp +++ b/lib/timer.cpp @@ -19,52 +19,57 @@ #include "timer.h" #include -#include -#include #include +#include #include #include namespace { - using dataElementType = std::pair; - bool more_second_sec(const dataElementType& lhs, const dataElementType& rhs) - { - return lhs.second.getSeconds() > rhs.second.getSeconds(); - } - // TODO: remove and print through (synchronized) ErrorLogger instead std::mutex stdCoutLock; } // TODO: this does not include any file context when SHOWTIME_FILE thus rendering it useless - should we include the logging with the progress logging? // that could also get rid of the broader locking -void TimerResults::showResults(ShowTime mode, bool metrics) const +void TimerResults::showResults(size_t max_results, bool metrics) const { - if (mode == ShowTime::NONE) - return; - std::vector data; + using dataElementType = std::pair>; + std::vector data; { std::lock_guard l(mResultsSync); data.reserve(mResults.size()); data.insert(data.begin(), mResults.cbegin(), mResults.cend()); } - std::sort(data.begin(), data.end(), more_second_sec); + + const auto asSeconds = [](std::chrono::milliseconds ms) -> std::chrono::duration { + return std::chrono::duration_cast>(ms); + }; + + const auto getSeconds = [&asSeconds](const std::vector& results) -> std::chrono::duration { + return std::accumulate(results.cbegin(), results.cend(), std::chrono::duration{}, [&asSeconds](std::chrono::duration secs, std::chrono::milliseconds duration) { + return secs + asSeconds(duration); + }); + }; + + std::sort(data.begin(), data.end(), [&getSeconds](const dataElementType& lhs, const dataElementType& rhs) -> bool { + return getSeconds(lhs.second) > getSeconds(rhs.second); + }); // lock the whole logging operation to avoid multiple threads printing their results at the same time std::lock_guard l(stdCoutLock); size_t ordinal = 1; // maybe it would be nice to have an ordinal in output later! for (auto iter=data.cbegin(); iter!=data.cend(); ++iter) { - if ((mode != ShowTime::TOP5_FILE && mode != ShowTime::TOP5_SUMMARY) || (ordinal<=5)) { - const double sec = iter->second.getSeconds().count(); + if (ordinal <= max_results) { + const double sec = getSeconds(iter->second).count(); std::cout << iter->first << ": " << sec << "s"; if (metrics) { - const double secAverage = sec / static_cast(iter->second.mResults.size()); - const double secMin = asSeconds(*std::min_element(iter->second.mResults.cbegin(), iter->second.mResults.cend())).count(); - const double secMax = asSeconds(*std::max_element(iter->second.mResults.cbegin(), iter->second.mResults.cend())).count(); - std::cout << " (avg. " << secAverage << "s / min " << secMin << "s / max " << secMax << "s - " << iter->second.mResults.size() << " result(s))"; + const double secAverage = sec / static_cast(iter->second.size()); + const double secMin = asSeconds(*std::min_element(iter->second.cbegin(), iter->second.cend())).count(); + const double secMax = asSeconds(*std::max_element(iter->second.cbegin(), iter->second.cend())).count(); + std::cout << " (avg. " << secAverage << "s / min " << secMin << "s / max " << secMax << "s - " << iter->second.size() << " result(s))"; } std::cout << std::endl; } @@ -76,7 +81,7 @@ void TimerResults::addResults(const std::string& name, std::chrono::milliseconds { std::lock_guard l(mResultsSync); - mResults[name].mResults.push_back(duration); + mResults[name].push_back(duration); } void TimerResults::reset() @@ -85,12 +90,14 @@ void TimerResults::reset() mResults.clear(); } -Timer::Timer(std::string str, ShowTime showtimeMode, TimerResultsIntf* timerResults) +Timer::Timer(std::string str, TimerResultsIntf* timerResults) : mName(std::move(str)) - , mMode(showtimeMode) - , mStart(Clock::now()) , mResults(timerResults) -{} +{ + if (!mResults) + return; + mStart = Clock::now(); +} Timer::~Timer() { @@ -99,18 +106,13 @@ Timer::~Timer() void Timer::stop() { - if (mMode == ShowTime::NONE) + if (mStart == TimePoint{}) return; - if (mStart != TimePoint{}) { - if (!mResults) { - assert(false); - } - else { - auto diff = std::chrono::duration_cast(Clock::now() - mStart); - mResults->addResults(mName, diff); - } - } - mMode = ShowTime::NONE; // prevent multiple stops + + const auto diff = std::chrono::duration_cast(Clock::now() - mStart); + mResults->addResults(mName, diff); + + mStart = TimePoint{}; // prevent multiple stops } static std::string durationToString(std::chrono::milliseconds duration) @@ -138,11 +140,8 @@ static std::string durationToString(std::chrono::milliseconds duration) return (ellapsedTime + secondsStr + "s"); } -OneShotTimer::OneShotTimer(std::string name, ShowTime showtime) +OneShotTimer::OneShotTimer(std::string name) { - if (showtime == ShowTime::NONE) - return; - class MyResults : public TimerResultsIntf { private: @@ -156,5 +155,5 @@ OneShotTimer::OneShotTimer(std::string name, ShowTime showtime) }; mResults.reset(new MyResults); - mTimer.reset(new Timer(std::move(name), showtime, mResults.get())); + mTimer.reset(new Timer(std::move(name), mResults.get())); } diff --git a/lib/timer.h b/lib/timer.h index 5611bc5304b..58ec8de08cc 100644 --- a/lib/timer.h +++ b/lib/timer.h @@ -23,56 +23,33 @@ #include "config.h" #include -#include +#include +#include #include #include #include -#include #include #include #include -enum class ShowTime : std::uint8_t { - NONE, - FILE, - FILE_TOTAL, - SUMMARY, - TOP5_SUMMARY, - TOP5_FILE -}; - class CPPCHECKLIB TimerResultsIntf { public: virtual ~TimerResultsIntf() = default; virtual void addResults(const std::string& name, std::chrono::milliseconds duration) = 0; - - static std::chrono::duration asSeconds(std::chrono::milliseconds ms) { - return std::chrono::duration_cast>(ms); - } -}; - -struct TimerResultsData { - std::vector mResults; - - std::chrono::duration getSeconds() const { - return std::accumulate(mResults.cbegin(), mResults.cend(), std::chrono::duration{}, [](std::chrono::duration secs, std::chrono::milliseconds duration) { - return secs + TimerResultsIntf::asSeconds(duration); - }); - } }; class CPPCHECKLIB WARN_UNUSED TimerResults : public TimerResultsIntf { public: TimerResults() = default; - void showResults(ShowTime mode, bool metrics = true) const; + void showResults(size_t max_results = std::numeric_limits::max(), bool metrics = true) const; void addResults(const std::string& name, std::chrono::milliseconds duration) override; void reset(); -private: - std::map mResults; +protected: + std::map> mResults; mutable std::mutex mResultsSync; }; @@ -81,7 +58,7 @@ class CPPCHECKLIB Timer { using Clock = std::chrono::high_resolution_clock; using TimePoint = std::chrono::time_point; - Timer(std::string str, ShowTime showtimeMode, TimerResultsIntf* timerResults = nullptr); + explicit Timer(std::string str, TimerResultsIntf* timerResults = nullptr); ~Timer(); Timer(const Timer&) = delete; @@ -90,14 +67,13 @@ class CPPCHECKLIB Timer { void stop(); template - static void run(std::string str, ShowTime showtimeMode, TimerResultsIntf* timerResults, const TFunc& f) { - Timer t(std::move(str), showtimeMode, timerResults); + static void run(std::string str, TimerResultsIntf* timerResults, const TFunc& f) { + Timer t(std::move(str), timerResults); f(); } private: const std::string mName; - ShowTime mMode{}; TimePoint mStart; TimerResultsIntf* mResults{}; }; @@ -105,7 +81,7 @@ class CPPCHECKLIB Timer { class CPPCHECKLIB OneShotTimer { public: - OneShotTimer(std::string name, ShowTime showtime); + explicit OneShotTimer(std::string name); private: std::unique_ptr mResults; std::unique_ptr mTimer; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 4cce2a71434..bda68e34fb0 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3508,7 +3508,7 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration, int fileIndex) mConfiguration = configuration; if (mTimerResults) { - Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1", mSettings.showtime, mTimerResults); + Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1", mTimerResults); if (!simplifyTokenList1(list.getFiles().front().c_str())) return false; } else { @@ -3516,18 +3516,16 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration, int fileIndex) return false; } - const ShowTime showTime = mTimerResults ? mSettings.showtime : ShowTime::NONE; - - Timer::run("Tokenizer::simplifyTokens1::createAst", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::createAst", mTimerResults, [&]() { list.createAst(); list.validateAst(mSettings.debugnormal); }); - Timer::run("Tokenizer::simplifyTokens1::createSymbolDatabase", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::createSymbolDatabase", mTimerResults, [&]() { createSymbolDatabase(); }); - Timer::run("Tokenizer::simplifyTokens1::setValueType", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::setValueType", mTimerResults, [&]() { mSymbolDatabase->setValueTypeInTokenList(false); mSymbolDatabase->setValueTypeInTokenList(true); }); @@ -3542,7 +3540,7 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration, int fileIndex) const bool doValueFlow = !disableValueflowEnv || (std::strcmp(disableValueflowEnv, "1") != 0); if (doValueFlow) { - Timer::run("Tokenizer::simplifyTokens1::ValueFlow", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::ValueFlow", mTimerResults, [&]() { ValueFlow::setValues(list, *mSymbolDatabase, mErrorLogger, mSettings, mTimerResults); }); @@ -5753,10 +5751,8 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) validate(); - const ShowTime showTime = mTimerResults ? mSettings.showtime : ShowTime::NONE; - // Bail out if code is garbage - Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::findGarbageCode", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::findGarbageCode", mTimerResults, [&]() { findGarbageCode(); }); @@ -5893,7 +5889,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) simplifyTypedefLHS(); // typedef.. - Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTypedef", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTypedef", mTimerResults, [&]() { simplifyTypedef(); }); @@ -5987,7 +5983,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) simplifyTypeIntrinsics(); // Handle templates.. - Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTemplates", showTime, mTimerResults, [&]() { + Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTemplates", mTimerResults, [&]() { simplifyTemplates(); }); @@ -6014,7 +6010,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) validate(); // #6772 "segmentation fault (invalid code) in Tokenizer::setVarId" - Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::setVarId", showTime, mTimerResults, [&](){ + Timer::run("Tokenizer::simplifyTokens1::simplifyTokenList1::setVarId", mTimerResults, [&](){ setVarId(); }); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 6db9ba6d1e3..f31fa1273e9 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -7266,7 +7266,7 @@ struct ValueFlowPassRunner { name += ' '; name += std::to_string(it); } - Timer t(name, state.settings.showtime, timerResults); + Timer t(name, timerResults); pass->run(state); } else { pass->run(state); diff --git a/test/fixture.cpp b/test/fixture.cpp index cdc826d083a..de42837a56e 100644 --- a/test/fixture.cpp +++ b/test/fixture.cpp @@ -116,7 +116,7 @@ bool TestFixture::prepareTest(const char testname[]) std::cout << fullTestName << std::endl; } if (timer_results) - mTimer.reset(new Timer(fullTestName, ShowTime::TOP5_SUMMARY, timer_results)); + mTimer.reset(new Timer(fullTestName, timer_results)); return !dry_run; } @@ -423,11 +423,7 @@ std::size_t TestFixture::runTests(const options& args) const auto f = [&](){ fixture = test->create(); }; - // TODO: Timer::run() needs proper handling if no results should be collected - if (args.timer_results()) - Timer::run(test->classname + " - create", ShowTime::TOP5_SUMMARY, args.timer_results(), f); - else - f(); + Timer::run(test->classname + " - create", args.timer_results(), f); fixture->processOptions(args); fixture->run(tests); } diff --git a/test/options.cpp b/test/options.cpp index 9db2bce8563..54527b26ecd 100644 --- a/test/options.cpp +++ b/test/options.cpp @@ -58,9 +58,8 @@ options::options(int argc, const char* const argv[]) options::~options() { - // TODO: allow more than 5 results to be shown if (mTimerResults) - mTimerResults->showResults(ShowTime::TOP5_FILE, false); + mTimerResults->showResults(10, false); } bool options::quiet() const diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 06ee30837d6..e5d231d47ed 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -31,7 +31,6 @@ #include "settings.h" #include "standards.h" #include "suppressions.h" -#include "timer.h" #include "utils.h" #include @@ -2193,21 +2192,21 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=summary", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == ShowTime::SUMMARY); + ASSERT_EQUALS_ENUM(Settings::ShowTime::SUMMARY, settings->showtime); } void showtimeFile() { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=file", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == ShowTime::FILE); + ASSERT_EQUALS_ENUM(Settings::ShowTime::FILE, settings->showtime); } void showtimeFileTotal() { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=file-total", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == ShowTime::FILE_TOTAL); + ASSERT_EQUALS_ENUM(Settings::ShowTime::FILE_TOTAL, settings->showtime); } void showtimeTop5() { @@ -2221,21 +2220,21 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=top5_file", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == ShowTime::TOP5_FILE); + ASSERT_EQUALS_ENUM(Settings::ShowTime::TOP5_FILE, settings->showtime); } void showtimeTop5Summary() { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=top5_summary", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == ShowTime::TOP5_SUMMARY); + ASSERT_EQUALS_ENUM(Settings::ShowTime::TOP5_SUMMARY, settings->showtime); } void showtimeNone() { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=none", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == ShowTime::NONE); + ASSERT_EQUALS_ENUM(Settings::ShowTime::NONE, settings->showtime); } void showtimeEmpty() { diff --git a/test/testprocessexecutor.cpp b/test/testprocessexecutor.cpp index 10562088f56..5a379166039 100644 --- a/test/testprocessexecutor.cpp +++ b/test/testprocessexecutor.cpp @@ -64,7 +64,7 @@ class TestProcessExecutorBase : public TestFixture { struct CheckOptions { bool quiet = true; - ShowTime showtime = ShowTime::NONE; + Settings::ShowTime showtime = Settings::ShowTime::NONE; const char* plistOutput = nullptr; std::vector filesList; }; @@ -177,7 +177,7 @@ class TestProcessExecutorBase : public TestFixture { "void f()\n" "{\n" " (void)(*((int*)0));\n" - "}", dinit(CheckOptions, $.showtime = ShowTime::SUMMARY)); + "}", dinit(CheckOptions, $.showtime = Settings::ShowTime::SUMMARY)); // we are not interested in the results - so just consume them ignore_errout(); } @@ -246,7 +246,7 @@ class TestProcessExecutorBase : public TestFixture { check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::TOP5_FILE)); + $.showtime = Settings::ShowTime::TOP5_FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; // for each file: top5 results + check time TODO_ASSERT_EQUALS(static_cast(5 + 1) * 2, 0, cppcheck::count_all_of(output_s, '\n')); @@ -257,7 +257,7 @@ class TestProcessExecutorBase : public TestFixture { check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::FILE)); + $.showtime = Settings::ShowTime::FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; TODO_ASSERT_EQUALS(2, 0, cppcheck::count_all_of(output_s, "Overall time:")); } @@ -267,7 +267,7 @@ class TestProcessExecutorBase : public TestFixture { check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::FILE_TOTAL)); + $.showtime = Settings::ShowTime::FILE_TOTAL)); const std::string output_s = GET_REDIRECT_OUTPUT; TODO_ASSERT(output_s.find("Check time: " + fprefix() + "_1.c: ") != std::string::npos); TODO_ASSERT(output_s.find("Check time: " + fprefix() + "_2.c: ") != std::string::npos); diff --git a/test/testsingleexecutor.cpp b/test/testsingleexecutor.cpp index 8351bb7c331..57343c58525 100644 --- a/test/testsingleexecutor.cpp +++ b/test/testsingleexecutor.cpp @@ -61,7 +61,7 @@ class TestSingleExecutorBase : public TestFixture { struct CheckOptions { bool quiet = true; - ShowTime showtime = ShowTime::NONE; + Settings::ShowTime showtime = Settings::ShowTime::NONE; const char* plistOutput = nullptr; std::vector filesList; }; @@ -165,7 +165,7 @@ class TestSingleExecutorBase : public TestFixture { "void f()\n" "{\n" " (void)(*((int*)0));\n" - "}", dinit(CheckOptions, $.showtime = ShowTime::SUMMARY)); + "}", dinit(CheckOptions, $.showtime = Settings::ShowTime::SUMMARY)); // we are not interested in the results - so just consume them ignore_errout(); } @@ -239,7 +239,7 @@ class TestSingleExecutorBase : public TestFixture { check(2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::TOP5_FILE)); + $.showtime = Settings::ShowTime::TOP5_FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; // for each file: top5 results + check time ASSERT_EQUALS((5 + 1) * 2LL, cppcheck::count_all_of(output_s, '\n')); @@ -250,7 +250,7 @@ class TestSingleExecutorBase : public TestFixture { check(2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::FILE)); + $.showtime = Settings::ShowTime::FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; ASSERT_EQUALS(0, cppcheck::count_all_of(output_s, "Overall time:")); } @@ -260,7 +260,7 @@ class TestSingleExecutorBase : public TestFixture { check(2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::FILE_TOTAL)); + $.showtime = Settings::ShowTime::FILE_TOTAL)); const std::string output_s = GET_REDIRECT_OUTPUT; ASSERT(output_s.find("Check time: " + fprefix() + "_" + zpad3(1) + ".c: ") != std::string::npos); ASSERT(output_s.find("Check time: " + fprefix() + "_" + zpad3(2) + ".c: ") != std::string::npos); diff --git a/test/testthreadexecutor.cpp b/test/testthreadexecutor.cpp index 36c3e69f8e8..8da83aa1b8f 100644 --- a/test/testthreadexecutor.cpp +++ b/test/testthreadexecutor.cpp @@ -64,7 +64,7 @@ class TestThreadExecutorBase : public TestFixture { struct CheckOptions { bool quiet = true; - ShowTime showtime = ShowTime::NONE; + Settings::ShowTime showtime = Settings::ShowTime::NONE; const char* plistOutput = nullptr; std::vector filesList; }; @@ -178,7 +178,7 @@ class TestThreadExecutorBase : public TestFixture { "void f()\n" "{\n" " (void)(*((int*)0));\n" - "}", dinit(CheckOptions, $.showtime = ShowTime::SUMMARY)); + "}", dinit(CheckOptions, $.showtime = Settings::ShowTime::SUMMARY)); // we are not interested in the results - so just consume them ignore_errout(); } @@ -247,7 +247,7 @@ class TestThreadExecutorBase : public TestFixture { check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::TOP5_FILE)); + $.showtime = Settings::ShowTime::TOP5_FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; // for each file: top5 results + check time ASSERT_EQUALS((5 + 1) * 2LL, cppcheck::count_all_of(output_s, '\n')); @@ -258,7 +258,7 @@ class TestThreadExecutorBase : public TestFixture { check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::FILE)); + $.showtime = Settings::ShowTime::FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; ASSERT_EQUALS(0, cppcheck::count_all_of(output_s, "Overall time:")); } @@ -268,7 +268,7 @@ class TestThreadExecutorBase : public TestFixture { check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = ShowTime::FILE_TOTAL)); + $.showtime = Settings::ShowTime::FILE_TOTAL)); const std::string output_s = GET_REDIRECT_OUTPUT; ASSERT(output_s.find("Check time: " + fprefix() + "_1.c: ") != std::string::npos); ASSERT(output_s.find("Check time: " + fprefix() + "_2.c: ") != std::string::npos); diff --git a/test/testtimer.cpp b/test/testtimer.cpp index 3f160c0c2b7..33e49cc8603 100644 --- a/test/testtimer.cpp +++ b/test/testtimer.cpp @@ -17,26 +17,63 @@ */ #include "fixture.h" +#include "redirect.h" #include "timer.h" #include +#include class TestTimer : public TestFixture { public: TestTimer() : TestFixture("TestTimer") {} private: + class TimerResultsTest : public TimerResults + { + public: + std::map> getResults() { + std::lock_guard l(mResultsSync); + return mResults; + } + }; void run() override { TEST_CASE(result); } - void result() const { - TimerResultsData t1; - t1.mResults.emplace_back(1234); - ASSERT(t1.getSeconds().count() > 1.233 && t1.getSeconds().count() < 1.235); + void result() { + REDIRECT; - // TODO : more tests + TimerResultsTest t1; + t1.addResults("call1", std::chrono::milliseconds{1230}); + t1.addResults("call2", std::chrono::milliseconds{1234}); + t1.addResults("call1", std::chrono::milliseconds{1235}); + t1.addResults("call1", std::chrono::milliseconds{1239}); + + const auto results = t1.getResults(); + ASSERT_EQUALS(2, results.size()); + + auto it = results.find("call1"); + ASSERT(it != results.cend()); + ASSERT_EQUALS(3, it->second.size()); + ASSERT_EQUALS(1230, it->second[0].count()); + ASSERT_EQUALS(1235, it->second[1].count()); + ASSERT_EQUALS(1239, it->second[2].count()); + + it = results.find("call2"); + ASSERT(it != results.cend()); + ASSERT_EQUALS(1, it->second.size()); + ASSERT_EQUALS(1234, it->second[0].count()); + + t1.showResults(); + ASSERT_EQUALS("call1: 3.704s (avg. 1.23467s / min 1.23s / max 1.239s - 3 result(s))\n" + "call2: 1.234s (avg. 1.234s / min 1.234s / max 1.234s - 1 result(s))\n", GET_REDIRECT_OUTPUT); + + t1.showResults(1); + ASSERT_EQUALS("call1: 3.704s (avg. 1.23467s / min 1.23s / max 1.239s - 3 result(s))\n", GET_REDIRECT_OUTPUT); + + t1.showResults(1, false); + ASSERT_EQUALS("call1: 3.704s\n", GET_REDIRECT_OUTPUT); } };