From 4df069ee30a4c5137e815343c8b10d13d677a354 Mon Sep 17 00:00:00 2001 From: Alan Zhao Date: Thu, 8 May 2025 17:11:48 -0700 Subject: [PATCH 1/5] [Timers] Add a flag to set a minimum timer value for printing The new LLVM flag `-min-print-time` is the number of seconds a timer must have in order for its value to be printed in either JSON or human readable formatting. This may be used, for example, with Clang's `-ftime-report` to reduce its output size by not printing insignificant values. The default value of this flag is 0 which retains the current behavior of printing all timer values. --- llvm/lib/Support/Timer.cpp | 38 +++++++++++++++++------- llvm/unittests/Support/TimerTest.cpp | 44 ++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/llvm/lib/Support/Timer.cpp b/llvm/lib/Support/Timer.cpp index 22811d7b4af0a..9cc22fbb8bc38 100644 --- a/llvm/lib/Support/Timer.cpp +++ b/llvm/lib/Support/Timer.cpp @@ -53,6 +53,7 @@ class Name2PairMap; static std::string &libSupportInfoOutputFilename(); static bool trackSpace(); static bool sortTimers(); +cl::opt &minPrintTime(); [[maybe_unused]] static SignpostEmitter &signposts(); static sys::SmartMutex &timerLock(); @@ -380,8 +381,12 @@ void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { // Loop through all of the timing data, printing it out. for (const PrintRecord &Record : llvm::reverse(TimersToPrint)) { - Record.Time.print(Total, OS); - OS << Record.Description << '\n'; + if (const TimeRecord &TR = Record.Time; TR.getUserTime() >= minPrintTime() || + TR.getSystemTime() >= minPrintTime() || + TR.getWallTime() >= minPrintTime()) { + Record.Time.print(Total, OS); + OS << Record.Description << '\n'; + } } Total.print(Total, OS); @@ -452,22 +457,31 @@ const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) { prepareToPrintList(false); for (const PrintRecord &R : TimersToPrint) { - OS << delim; - delim = ",\n"; - const TimeRecord &T = R.Time; - printJSONValue(OS, R, ".wall", T.getWallTime()); - OS << delim; - printJSONValue(OS, R, ".user", T.getUserTime()); - OS << delim; - printJSONValue(OS, R, ".sys", T.getSystemTime()); + if (double Value = T.getWallTime(); Value >= minPrintTime()) { + OS << delim; + printJSONValue(OS, R, ".wall", Value); + delim = ",\n"; + } + if (double Value = T.getWallTime(); Value >= minPrintTime()) { + OS << delim; + printJSONValue(OS, R, ".user", T.getUserTime()); + delim = ",\n"; + } + if (double Value = T.getWallTime(); Value >= minPrintTime()) { + OS << delim; + printJSONValue(OS, R, ".sys", T.getSystemTime()); + delim = ",\n"; + } if (T.getMemUsed()) { OS << delim; printJSONValue(OS, R, ".mem", T.getMemUsed()); + delim = ",\n"; } if (T.getInstructionsExecuted()) { OS << delim; printJSONValue(OS, R, ".instr", T.getInstructionsExecuted()); + delim = ",\n"; } } TimersToPrint.clear(); @@ -515,6 +529,9 @@ class llvm::TimerGlobals { cl::desc("In the report, sort the timers in each group in wall clock" " time order"), cl::init(true), cl::Hidden}; + cl::opt MinPrintTime{ + "min-print-time", + cl::desc("Minimum time in seconds for a timer to be printed"), cl::init(0)}; sys::SmartMutex TimerLock; TimerGroup DefaultTimerGroup{"misc", "Miscellaneous Ungrouped Timers", @@ -541,6 +558,7 @@ static std::string &libSupportInfoOutputFilename() { } static bool trackSpace() { return ManagedTimerGlobals->TrackSpace; } static bool sortTimers() { return ManagedTimerGlobals->SortTimers; } +cl::opt &minPrintTime() { return ManagedTimerGlobals->MinPrintTime; } static SignpostEmitter &signposts() { return ManagedTimerGlobals->Signposts; } static sys::SmartMutex &timerLock() { return ManagedTimerGlobals->TimerLock; diff --git a/llvm/unittests/Support/TimerTest.cpp b/llvm/unittests/Support/TimerTest.cpp index 612fd7231da70..0eb81f07bed5a 100644 --- a/llvm/unittests/Support/TimerTest.cpp +++ b/llvm/unittests/Support/TimerTest.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Timer.h" +#include "llvm/Support/CommandLine.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" #if _WIN32 @@ -17,18 +19,20 @@ using namespace llvm; +cl::opt &minPrintTime(); + namespace { // FIXME: Put this somewhere in Support, it's also used in LockFileManager. -void SleepMS() { +void SleepMS(int ms = 1) { #if _WIN32 - Sleep(1); + Sleep(ms); #else struct timespec Interval; - Interval.tv_sec = 0; - Interval.tv_nsec = 1000000; + Interval.tv_sec = ms / 1000; + Interval.tv_nsec = 1000000 * (ms % 1000); #if defined(__MVS__) - long Microseconds = (Interval.tv_nsec + 999) / 1000; + long Microseconds = (Interval.tv_nsec + Interval.tv_sec * 1000 + 999) / 1000; usleep(Microseconds); #else nanosleep(&Interval, nullptr); @@ -82,4 +86,34 @@ TEST(Timer, TimerGroupTimerDestructed) { EXPECT_FALSE(testing::internal::GetCapturedStderr().empty()); } +TEST(Timer, MinTimerFlag) { + testing::internal::CaptureStderr(); + + Timer T1("T1", "T1"); + Timer T2("T2", "T2"); + + minPrintTime().setValue(2); + + T1.startTimer(); + T2.startTimer(); + + SleepMS(1000); + T1.stopTimer(); + + SleepMS(2000); + T2.stopTimer(); + + TimerGroup::printAll(llvm::errs()); + std::string stderr = testing::internal::GetCapturedStderr(); + EXPECT_THAT(stderr, testing::HasSubstr("T2")); + EXPECT_THAT(stderr, testing::Not(testing::HasSubstr("T1"))); + + testing::internal::CaptureStderr(); + + TimerGroup::printAllJSONValues(llvm::errs(), ""); + stderr = testing::internal::GetCapturedStderr(); + EXPECT_THAT(stderr, testing::HasSubstr("T2.wall")); + EXPECT_THAT(stderr, testing::Not(testing::HasSubstr("T1.wall"))); +} + } // namespace From 52331be96062d5b7491e2a5dee3c9f1d4457d499 Mon Sep 17 00:00:00 2001 From: Alan Zhao Date: Fri, 9 May 2025 12:38:34 -0700 Subject: [PATCH 2/5] formatting --- llvm/lib/Support/Timer.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Support/Timer.cpp b/llvm/lib/Support/Timer.cpp index 9cc22fbb8bc38..c5eca6924ef13 100644 --- a/llvm/lib/Support/Timer.cpp +++ b/llvm/lib/Support/Timer.cpp @@ -381,9 +381,10 @@ void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { // Loop through all of the timing data, printing it out. for (const PrintRecord &Record : llvm::reverse(TimersToPrint)) { - if (const TimeRecord &TR = Record.Time; TR.getUserTime() >= minPrintTime() || - TR.getSystemTime() >= minPrintTime() || - TR.getWallTime() >= minPrintTime()) { + if (const TimeRecord &TR = Record.Time; + TR.getUserTime() >= minPrintTime() || + TR.getSystemTime() >= minPrintTime() || + TR.getWallTime() >= minPrintTime()) { Record.Time.print(Total, OS); OS << Record.Description << '\n'; } @@ -531,7 +532,8 @@ class llvm::TimerGlobals { cl::init(true), cl::Hidden}; cl::opt MinPrintTime{ "min-print-time", - cl::desc("Minimum time in seconds for a timer to be printed"), cl::init(0)}; + cl::desc("Minimum time in seconds for a timer to be printed"), + cl::init(0)}; sys::SmartMutex TimerLock; TimerGroup DefaultTimerGroup{"misc", "Miscellaneous Ungrouped Timers", From 32fd6ea338feab79dbbb924ab7e8968fd25b5796 Mon Sep 17 00:00:00 2001 From: Alan Zhao Date: Mon, 12 May 2025 13:36:04 -0700 Subject: [PATCH 3/5] reduce test to 1s --- llvm/unittests/Support/TimerTest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/unittests/Support/TimerTest.cpp b/llvm/unittests/Support/TimerTest.cpp index 0eb81f07bed5a..862c3a5a85a26 100644 --- a/llvm/unittests/Support/TimerTest.cpp +++ b/llvm/unittests/Support/TimerTest.cpp @@ -92,15 +92,15 @@ TEST(Timer, MinTimerFlag) { Timer T1("T1", "T1"); Timer T2("T2", "T2"); - minPrintTime().setValue(2); + minPrintTime().setValue(1); T1.startTimer(); T2.startTimer(); - SleepMS(1000); + SleepMS(500); T1.stopTimer(); - SleepMS(2000); + SleepMS(600); T2.stopTimer(); TimerGroup::printAll(llvm::errs()); From 5e8be07968ea0ca57b5885cc96df039efa2c90d7 Mon Sep 17 00:00:00 2001 From: Alan Zhao Date: Mon, 12 May 2025 13:38:25 -0700 Subject: [PATCH 4/5] rename flag --- llvm/lib/Support/Timer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Support/Timer.cpp b/llvm/lib/Support/Timer.cpp index c5eca6924ef13..8a3d3e7d53bc3 100644 --- a/llvm/lib/Support/Timer.cpp +++ b/llvm/lib/Support/Timer.cpp @@ -531,7 +531,7 @@ class llvm::TimerGlobals { " time order"), cl::init(true), cl::Hidden}; cl::opt MinPrintTime{ - "min-print-time", + "timer-min-print-time", cl::desc("Minimum time in seconds for a timer to be printed"), cl::init(0)}; From 9e9e63eb82e29a52b1d584439031d8875714d595 Mon Sep 17 00:00:00 2001 From: Alan Zhao Date: Mon, 12 May 2025 14:10:27 -0700 Subject: [PATCH 5/5] lambdaify things --- llvm/lib/Support/Timer.cpp | 44 ++++++++++++++------------------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/llvm/lib/Support/Timer.cpp b/llvm/lib/Support/Timer.cpp index 8a3d3e7d53bc3..22033545ffa23 100644 --- a/llvm/lib/Support/Timer.cpp +++ b/llvm/lib/Support/Timer.cpp @@ -382,9 +382,9 @@ void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { // Loop through all of the timing data, printing it out. for (const PrintRecord &Record : llvm::reverse(TimersToPrint)) { if (const TimeRecord &TR = Record.Time; - TR.getUserTime() >= minPrintTime() || - TR.getSystemTime() >= minPrintTime() || - TR.getWallTime() >= minPrintTime()) { + TR.getUserTime() > minPrintTime() || + TR.getSystemTime() > minPrintTime() || + TR.getWallTime() > minPrintTime()) { Record.Time.print(Total, OS); OS << Record.Description << '\n'; } @@ -459,31 +459,19 @@ const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) { prepareToPrintList(false); for (const PrintRecord &R : TimersToPrint) { const TimeRecord &T = R.Time; - if (double Value = T.getWallTime(); Value >= minPrintTime()) { - OS << delim; - printJSONValue(OS, R, ".wall", Value); - delim = ",\n"; - } - if (double Value = T.getWallTime(); Value >= minPrintTime()) { - OS << delim; - printJSONValue(OS, R, ".user", T.getUserTime()); - delim = ",\n"; - } - if (double Value = T.getWallTime(); Value >= minPrintTime()) { - OS << delim; - printJSONValue(OS, R, ".sys", T.getSystemTime()); - delim = ",\n"; - } - if (T.getMemUsed()) { - OS << delim; - printJSONValue(OS, R, ".mem", T.getMemUsed()); - delim = ",\n"; - } - if (T.getInstructionsExecuted()) { - OS << delim; - printJSONValue(OS, R, ".instr", T.getInstructionsExecuted()); - delim = ",\n"; - } + auto MaybePrintJSON = [&](double Value, const char *suffix, + double Threshold) { + if (Value > Threshold) { + OS << delim; + printJSONValue(OS, R, suffix, Value); + delim = ",\n"; + } + }; + MaybePrintJSON(T.getWallTime(), ".wall", minPrintTime()); + MaybePrintJSON(T.getUserTime(), ".user", minPrintTime()); + MaybePrintJSON(T.getSystemTime(), ".sys", minPrintTime()); + MaybePrintJSON(T.getMemUsed(), ".mem", 0); + MaybePrintJSON(T.getInstructionsExecuted(), ".instr", 0); } TimersToPrint.clear(); return delim;