diff --git a/cli/processexecutor.cpp b/cli/processexecutor.cpp index 11f920db13c..234b54ec99f 100644 --- a/cli/processexecutor.cpp +++ b/cli/processexecutor.cpp @@ -78,7 +78,7 @@ ProcessExecutor::ProcessExecutor(const std::list &files, const namespace { class PipeWriter : public ErrorLogger { public: - enum PipeSignal : std::uint8_t {REPORT_OUT='1',REPORT_ERROR='2',REPORT_SUPPR_INLINE='3',REPORT_SUPPR='4',CHILD_END='5',REPORT_METRIC='6'}; + enum PipeSignal : std::uint8_t {REPORT_OUT='1',REPORT_ERROR='2',REPORT_SUPPR_INLINE='3',REPORT_SUPPR='4',CHILD_END='5',REPORT_METRIC='6',REPORT_TIMER='7'}; explicit PipeWriter(int pipe) : mWpipe(pipe) {} @@ -104,6 +104,18 @@ namespace { writeToPipe(REPORT_METRIC, metric); } + void writerTimer(const TimerResults* timerResults) const { + if (!timerResults) + return; + + for (const auto& entry : timerResults->results()) + { + for (const auto& d : entry.second) { + writeToPipe(REPORT_TIMER, entry.first + ";" + std::to_string(d.count())); + } + } + } + void writeEnd(const std::string& str) const { writeToPipe(CHILD_END, str); } @@ -188,7 +200,8 @@ bool ProcessExecutor::handleRead(int rpipe, unsigned int &result, const std::str type != PipeWriter::REPORT_SUPPR_INLINE && type != PipeWriter::REPORT_SUPPR && type != PipeWriter::CHILD_END && - type != PipeWriter::REPORT_METRIC) { + type != PipeWriter::REPORT_METRIC && + type != PipeWriter::REPORT_TIMER) { std::cerr << "#### ThreadExecutor::handleRead(" << filename << ") invalid type " << int(type) << std::endl; std::exit(EXIT_FAILURE); } @@ -272,6 +285,20 @@ bool ProcessExecutor::handleRead(int rpipe, unsigned int &result, const std::str res = false; } else if (type == PipeWriter::REPORT_METRIC) { mErrorLogger.reportMetric(buf); + } else if (type == PipeWriter::REPORT_TIMER) { + if (!mTimerResults) { + // TODO: make this non-fatal + std::cerr << "#### ThreadExecutor::handleRead(" << filename << ") received timer results when no timer is enabled" << std::endl; + std::exit(EXIT_FAILURE); + } + const auto parts = splitString(buf, ';'); + if (parts.size() < 2) + { + // TODO: make this non-fatal + std::cerr << "#### ThreadExecutor::handleRead(" << filename << ") adding of timer result failed - insufficient data" << std::endl; + std::exit(EXIT_FAILURE); + } + mTimerResults->addResults(parts[0], std::chrono::milliseconds{strToInt(parts[1])}); } return res; @@ -359,6 +386,8 @@ unsigned int ProcessExecutor::check() pipewriter.writeSuppr(mSuppressions.nomsg); + pipewriter.writerTimer(mTimerResults); + pipewriter.writeEnd(std::to_string(resultOfCheck)); std::exit(EXIT_SUCCESS); } diff --git a/lib/timer.h b/lib/timer.h index 58ec8de08cc..fbf6f5a448a 100644 --- a/lib/timer.h +++ b/lib/timer.h @@ -48,6 +48,10 @@ class CPPCHECKLIB WARN_UNUSED TimerResults : public TimerResultsIntf { void reset(); + const std::map>& results() const { + return mResults; + } + protected: std::map> mResults; mutable std::mutex mResultsSync; diff --git a/test/cli/other_test.py b/test/cli/other_test.py index fa87948b028..4aaddc3572d 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -1032,9 +1032,8 @@ def test_showtime_top5_file_compdb(tmp_path): __test_showtime_top5_file(tmp_path, use_compdb=True) -# TODO: remove extra args when --executor=process works def __test_showtime_top5_summary(tmp_path, use_compdb=False): - __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', use_compdb=use_compdb, extra_args=['-j1']) + __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', use_compdb=use_compdb) def test_showtime_top5_summary(tmp_path): @@ -1045,30 +1044,6 @@ def test_showtime_top5_summary_compdb(tmp_path): __test_showtime_top5_summary(tmp_path, use_compdb=True) -# TODO: remove when --executor=process works -def test_showtime_top5_summary_j_thread(tmp_path): - __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', extra_args=['-j2', '--executor=thread']) - - -# TODO: remove when --executor=process works -def test_showtime_top5_summary_compdb_j_thread(tmp_path): - __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', use_compdb=True, extra_args=['-j2', '--executor=thread']) - - -# TODO: remove override when fixed -@pytest.mark.skipif(sys.platform == 'win32', reason="requires ProcessExecutor") -@pytest.mark.xfail(strict=True) # TODO: need to transfer the timer results to parent process - see #4452 -def test_showtime_top5_summary_j_process(tmp_path): - __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', extra_args=['-j2', '--executor=process']) - - -# TODO: remove override when fixed -@pytest.mark.skipif(sys.platform == 'win32', reason="requires ProcessExecutor") -@pytest.mark.xfail(strict=True) # TODO: need to transfer the timer results to parent process - see #4452 -def test_showtime_top5_summary_compdb_j_process(tmp_path): - __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', use_compdb=True, extra_args=['-j2', '--executor=process']) - - def __test_showtime_file(tmp_path, use_compdb=False, use_addons=False, use_clang_tidy=False): exp_res = 79 # project analysis does not call Preprocessor::getConfig() @@ -1103,13 +1078,12 @@ def test_showtime_file_clang_tidy_compdb(tmp_path): __test_showtime_file(tmp_path, use_clang_tidy=True, use_compdb=True) -# TODO: remove extra args when --executor=process works def __test_showtime_summary(tmp_path, use_compdb=False, use_addons=False, use_clang_tidy=False): exp_res = 79 # project analysis does not call Preprocessor::getConfig() if use_compdb: exp_res -= 1 - __test_showtime(tmp_path, 'summary', exp_res, 'Overall time: ', use_compdb=use_compdb, use_addons=use_addons, use_clang_tidy=use_clang_tidy, extra_args=['-j1']) + __test_showtime(tmp_path, 'summary', exp_res, 'Overall time: ', use_compdb=use_compdb, use_addons=use_addons, use_clang_tidy=use_clang_tidy) def test_showtime_summary(tmp_path): @@ -1138,30 +1112,6 @@ def test_showtime_summary_clang_tidy_compdb(tmp_path): __test_showtime_summary(tmp_path, use_clang_tidy=True, use_compdb=True) -# TODO: remove when --executor=process works -def test_showtime_summary_j_thread(tmp_path): - __test_showtime(tmp_path, 'summary', 79, 'Overall time: ', extra_args=['-j2', '--executor=thread']) - - -# TODO: remove when --executor=process works -def test_showtime_summary_compdb_j_thread(tmp_path): - __test_showtime(tmp_path, 'summary', 78, 'Overall time: ', use_compdb=True, extra_args=['-j2', '--executor=thread']) - - -# TODO: remove override when fixed -@pytest.mark.skipif(sys.platform == 'win32', reason="requires ProcessExecutor") -@pytest.mark.xfail(strict=True) # TODO: need to transfer the timer results to parent process - see #4452 -def test_showtime_summary_j_process(tmp_path): - __test_showtime(tmp_path, 'summary', 79, 'Overall time: ', extra_args=['-j2', '--executor=process']) - - -# TODO: remove override when fixed -@pytest.mark.skipif(sys.platform == 'win32', reason="requires ProcessExecutor") -@pytest.mark.xfail(strict=True) # TODO: need to transfer the timer results to parent process - see #4452 -def test_showtime_summary_compdb_j_process(tmp_path): - __test_showtime(tmp_path, 'summary', 78, 'Overall time: ', use_compdb=True, extra_args=['-j2', '--executor=process']) - - def __test_showtime_file_total(tmp_path, use_compdb=False): __test_showtime(tmp_path, 'file-total', 0, 'Check time: ', use_compdb=use_compdb)