https://github.com/chandlerc updated https://github.com/llvm/llvm-project/pull/228627
>From 2765dc14d832440ecb0ede141a64d3a1460ec088 Mon Sep 17 00:00:00 2001 From: Chandler Carruth <[email protected]> Date: Fri, 2 Oct 2026 18:06:45 +0000 Subject: [PATCH 1/3] [TimeProfiler][Clang] Add zstd-compressed time-trace output support Time trace JSON files can become very large (tens of megabytes) when profiling with fine granularity (-ftime-trace-granularity=0) or verbose output (-ftime-trace-verbose), while compressing by ~20x with zstd. Add support for writing zstd-compressed time-trace output directly using LLVM's existing llvm::compression facilities: - Extend llvm::timeTraceProfilerInitialize and llvm::timeTraceProfilerWrite to support DebugCompressionType and infer zstd compression from .zst/.zstd file extensions via llvm::inferTimeTraceCompressionFromPath. - Add -ftime-trace-compress and -ftime-trace-compress=<none|zstd> driver and CC1 options to explicitly control compression regardless of output filename. - Update default output filename inference when -ftime-trace is used without an explicit filename so compressed traces use a .json.zst extension. Assisted-by: Antigravity with Gemini --- .../clang/Basic/DiagnosticDriverKinds.td | 2 + .../include/clang/Frontend/FrontendOptions.h | 5 ++ clang/include/clang/Options/Options.td | 11 +++ clang/lib/Driver/Driver.cpp | 18 ++++- clang/lib/Driver/ToolChains/Clang.cpp | 26 +++++++ clang/lib/Frontend/CompilerInvocation.cpp | 5 ++ clang/test/Driver/compress-zstd.c | 4 + clang/test/Driver/ftime-trace.cpp | 11 ++- clang/tools/driver/cc1_main.cpp | 7 +- llvm/include/llvm/Support/TimeProfiler.h | 12 ++- llvm/lib/Support/TimeProfiler.cpp | 74 +++++++++++++++++-- llvm/unittests/Support/TimeProfilerTest.cpp | 28 +++++++ 12 files changed, 185 insertions(+), 18 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index df6ff0c2cf399..369fbef8d0c85 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -564,6 +564,8 @@ def warn_incompatible_sysroot : Warning<"using sysroot for '%0' but targeting '% InGroup<DiagGroup<"incompatible-sysroot">>; def warn_debug_compression_unavailable : Warning<"cannot compress debug sections (%0 not enabled)">, InGroup<DiagGroup<"debug-compression-unavailable">>; +def err_drv_time_trace_compression_unavailable + : Error<"cannot compress time trace (%0 not enabled)">; def warn_drv_disabling_vptr_no_rtti_default : Warning< "implicitly disabling vptr sanitizer because rtti wasn't enabled">, InGroup<AutoDisableVptrSanitizer>; diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index b85cf4c007862..701c8d75fe61f 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -16,6 +16,7 @@ #include "clang/Serialization/ModuleFileExtension.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/MemoryBuffer.h" #include <cassert> #include <map> @@ -543,6 +544,10 @@ class FrontendOptions { LLVM_PREFERRED_TYPE(bool) unsigned TimeTraceVerbose : 1; + /// Compression format for -ftime-trace output. + llvm::DebugCompressionType TimeTraceCompress = + llvm::DebugCompressionType::None; + /// Path which stores the output files for -ftime-trace std::string TimeTracePath; diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 60ae84cb0af5c..1d867223b9b68 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -4822,6 +4822,17 @@ def ftime_trace_verbose : Joined<["-"], "ftime-trace-verbose">, Group<f_Group>, HelpText<"Make time trace capture verbose event details (e.g. source filenames). This can increase the size of the output by 2-3 times">, Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>, MarshallingInfoFlag<FrontendOpts<"TimeTraceVerbose">>; +def ftime_trace_compress_EQ : Joined<["-"], "ftime-trace-compress=">, Group<f_Group>, + HelpText<"Compress -ftime-trace output with the specified algorithm">, + Values<"none,zstd">, + NormalizedValuesScope<"llvm::DebugCompressionType">, + NormalizedValues<["None", "Zstd"]>, + Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>, + MarshallingInfoEnum<FrontendOpts<"TimeTraceCompress">, "None">; +def ftime_trace_compress : Flag<["-"], "ftime-trace-compress">, Group<f_Group>, + Alias<ftime_trace_compress_EQ>, AliasArgs<["zstd"]>, + HelpText<"Alias for -ftime-trace-compress=zstd">, + Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>; def ftime_trace_EQ : Joined<["-"], "ftime-trace=">, Group<f_Group>, HelpText<"Similar to -ftime-trace. Specify the JSON file or a directory which will contain the JSON file">, Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>, diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 7649941a68b1c..79ad73d45825c 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -5173,6 +5173,16 @@ static void handleTimeTrace(Compilation &C, const ArgList &Args, /*CreatePrefixForHost=*/true); } + StringRef DefaultExt = ".json"; + StringRef DefaultExtNoDot = "json"; + if (const Arg *CompressArg = + Args.getLastArgNoClaim(options::OPT_ftime_trace_compress_EQ)) { + if (StringRef(CompressArg->getValue()) == "zstd") { + DefaultExt = ".json.zst"; + DefaultExtNoDot = "json.zst"; + } + } + SmallString<128> Path; if (A->getOption().matches(options::OPT_ftime_trace_EQ)) { Path = A->getValue(); @@ -5181,7 +5191,7 @@ static void handleTimeTrace(Compilation &C, const ArgList &Args, ? llvm::sys::path::stem(Result.getFilename()) : llvm::sys::path::stem(BaseInput)); Tmp += OffloadingPrefix; - Tmp += ".json"; + Tmp += DefaultExt; llvm::sys::path::append(Path, Tmp); } } else { @@ -5191,7 +5201,7 @@ static void handleTimeTrace(Compilation &C, const ArgList &Args, Path = DumpDir->getValue(); Path += llvm::sys::path::stem(BaseInput); Path += OffloadingPrefix; - Path += ".json"; + Path += DefaultExt; } else if (!OffloadingPrefix.empty()) { // For offloading, derive path from -o output directory combined with // the input filename and offload prefix. @@ -5200,10 +5210,10 @@ static void handleTimeTrace(Compilation &C, const ArgList &Args, if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) Path = llvm::sys::path::parent_path(FinalOutput->getValue()); llvm::sys::path::append(Path, TraceName); - Path += ".json"; + Path += DefaultExt; } else { Path = Result.getFilename(); - llvm::sys::path::replace_extension(Path, "json"); + llvm::sys::path::replace_extension(Path, DefaultExtNoDot); } } const char *ResultFile = C.getArgs().MakeArgString(Path); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index f0d04bf4b6a83..eda506494829a 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -46,11 +46,13 @@ #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/Support/YAMLParser.h" #include "llvm/TargetParser/AArch64TargetParser.h" #include "llvm/TargetParser/ARMTargetParserCommon.h" @@ -7344,6 +7346,28 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("-ftime-trace=" + Twine(Name))); Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_verbose); + if (const Arg *CompressArg = + Args.getLastArg(options::OPT_ftime_trace_compress_EQ)) { + StringRef Value = CompressArg->getValue(); + if (Value == "none") { + // Explicit -ftime-trace-compress=none disables compression even if the + // filename has a .zst/.zstd extension. + } else if (Value == "zstd") { + if (llvm::compression::zstd::isAvailable()) + CmdArgs.push_back("-ftime-trace-compress=zstd"); + else + D.Diag(diag::err_drv_time_trace_compression_unavailable) << "zstd"; + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << CompressArg->getSpelling() << Value; + } + } else if (llvm::inferTimeTraceCompressionFromPath(Name) == + llvm::DebugCompressionType::Zstd) { + if (llvm::compression::zstd::isAvailable()) + CmdArgs.push_back("-ftime-trace-compress=zstd"); + else + D.Diag(diag::err_drv_time_trace_compression_unavailable) << "zstd"; + } } if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { @@ -9760,6 +9784,8 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, OPT_ftime_trace_EQ, OPT_ftime_trace_granularity_EQ, OPT_ftime_trace_verbose, + OPT_ftime_trace_compress, + OPT_ftime_trace_compress_EQ, OPT_opt_record_file, OPT_opt_record_format, OPT_opt_record_passes, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b794a99c3d0c0..ed30d93b6026b 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -5239,6 +5239,11 @@ bool CompilerInvocation::CreateFromArgsImpl( llvm::driver::ProfileInstrKind::ProfileNone) Diags.Report(diag::err_drv_profile_instrument_use_path_with_no_kind); + if (Res.getFrontendOpts().TimeTraceCompress == + llvm::DebugCompressionType::Zstd && + !llvm::compression::zstd::isAvailable()) + Diags.Report(diag::err_drv_time_trace_compression_unavailable) << "zstd"; + FixupInvocation(Res, Diags, Args, DashX); return Diags.getNumErrors() == NumErrorsBefore; diff --git a/clang/test/Driver/compress-zstd.c b/clang/test/Driver/compress-zstd.c index 84b26354589e9..a8e07631eede4 100644 --- a/clang/test/Driver/compress-zstd.c +++ b/clang/test/Driver/compress-zstd.c @@ -5,3 +5,7 @@ // CHECK: {{"-cc1(as)?".* "--compress-debug-sections=zstd"}} // CHECK: "--compress-debug-sections=zstd" + +// RUN: %clang -### -c -ftime-trace -ftime-trace-compress %s -o a.o 2>&1 | FileCheck %s --check-prefix=TIME-TRACE-ZSTD +// RUN: %clang -### -c -ftime-trace=a.json.zst %s -o a.o 2>&1 | FileCheck %s --check-prefix=TIME-TRACE-ZSTD +// TIME-TRACE-ZSTD: "-cc1"{{.*}} "-ftime-trace=a.json.zst" "-ftime-trace-compress=zstd" diff --git a/clang/test/Driver/ftime-trace.cpp b/clang/test/Driver/ftime-trace.cpp index 60c5885704b58..77c46ae43bb53 100644 --- a/clang/test/Driver/ftime-trace.cpp +++ b/clang/test/Driver/ftime-trace.cpp @@ -55,14 +55,23 @@ // LINK3: -cc1{{.*}} "-ftime-trace=e{{/|\\\\}}a-{{[^.]*}}.json" "-ftime-trace-granularity=0" "-ftime-trace-verbose" // LINK3: -cc1{{.*}} "-ftime-trace=e{{/|\\\\}}b-{{[^.]*}}.json" "-ftime-trace-granularity=0" "-ftime-trace-verbose" -// RUN: %clang -### -ftime-trace -ftime-trace=e -ftime-trace-granularity=1 -ftime-trace-verbose -xassembler d/a.cpp 2>&1 | \ +// RUN: %clang -### -ftime-trace -ftime-trace=e -ftime-trace-granularity=1 -ftime-trace-verbose -ftime-trace-compress -ftime-trace-compress=none -xassembler d/a.cpp 2>&1 | \ // RUN: FileCheck %s --check-prefix=UNUSED // UNUSED: warning: argument unused during compilation: '-ftime-trace' // UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace=e' // UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace-granularity=1' // UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace-verbose' +// UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace-compress' +// UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace-compress=none' // UNUSED-NOT: warning: +// RUN: %clang -### -c -ftime-trace=foo.json.zst -ftime-trace-compress=none -fintegrated-as d/a.cpp -o e/a.o 2>&1 | FileCheck %s --check-prefix=COMPRESS-NONE +// COMPRESS-NONE: -cc1{{.*}} "-ftime-trace=foo.json.zst" +// COMPRESS-NONE-NOT: "-ftime-trace-compress + +// RUN: not %clang -### -c -ftime-trace -ftime-trace-compress=invalid d/a.cpp -o e/a.o 2>&1 | FileCheck %s --check-prefix=COMPRESS-INVALID +// COMPRESS-INVALID: error: unsupported argument 'invalid' to option '-ftime-trace-compress=' + template <typename T> struct Struct { T Num; diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index 89b0a340e6672..1c3fef0630ea4 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -253,7 +253,8 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { if (!Clang->getFrontendOpts().TimeTracePath.empty()) { llvm::timeTraceProfilerInitialize( Clang->getFrontendOpts().TimeTraceGranularity, Argv0, - Clang->getFrontendOpts().TimeTraceVerbose); + Clang->getFrontendOpts().TimeTraceVerbose, + Clang->getFrontendOpts().TimeTraceCompress); } // --print-supported-cpus takes priority over the actual compilation. if (Clang->getFrontendOpts().PrintSupportedCPUs) @@ -312,8 +313,10 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { } if (llvm::timeTraceProfilerEnabled()) { + bool Binary = Clang->getFrontendOpts().TimeTraceCompress != + llvm::DebugCompressionType::None; if (auto profilerOutput = Clang->createOutputFile( - Clang->getFrontendOpts().TimeTracePath, /*Binary=*/false, + Clang->getFrontendOpts().TimeTracePath, Binary, /*RemoveFileOnSignal=*/false, /*useTemporary=*/false)) { llvm::timeTraceProfilerWrite(*profilerOutput); diff --git a/llvm/include/llvm/Support/TimeProfiler.h b/llvm/include/llvm/Support/TimeProfiler.h index 2eb2c09d1becd..014379de62f0d 100644 --- a/llvm/include/llvm/Support/TimeProfiler.h +++ b/llvm/include/llvm/Support/TimeProfiler.h @@ -78,6 +78,7 @@ #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Error.h" namespace llvm { @@ -113,12 +114,17 @@ LLVM_ABI bool isTimeTraceVerbose(); struct TimeTraceProfilerEntry; +/// Infer the time trace compression format from \p Path based on its file +/// extension (.zst/.zstd -> Zstd, otherwise None). +LLVM_ABI DebugCompressionType inferTimeTraceCompressionFromPath(StringRef Path); + /// Initialize the time trace profiler. /// This sets up the global \p TimeTraceProfilerInstance /// variable to be the profiler instance. -LLVM_ABI void timeTraceProfilerInitialize(unsigned TimeTraceGranularity, - StringRef ProcName, - bool TimeTraceVerbose = false); +LLVM_ABI void timeTraceProfilerInitialize( + unsigned TimeTraceGranularity, StringRef ProcName, + bool TimeTraceVerbose = false, + DebugCompressionType TimeTraceCompress = DebugCompressionType::None); /// Cleanup the time trace profiler, if it was initialized. LLVM_ABI void timeTraceProfilerCleanup(); diff --git a/llvm/lib/Support/TimeProfiler.cpp b/llvm/lib/Support/TimeProfiler.cpp index 002529f20d661..c2816e98cd30a 100644 --- a/llvm/lib/Support/TimeProfiler.cpp +++ b/llvm/lib/Support/TimeProfiler.cpp @@ -127,12 +127,15 @@ struct InProgressEntry { }; struct llvm::TimeTraceProfiler { - TimeTraceProfiler(unsigned TimeTraceGranularity = 0, StringRef ProcName = "", - bool TimeTraceVerbose = false) + TimeTraceProfiler( + unsigned TimeTraceGranularity = 0, StringRef ProcName = "", + bool TimeTraceVerbose = false, + DebugCompressionType TimeTraceCompress = DebugCompressionType::None) : BeginningOfTime(system_clock::now()), StartTime(ClockType::now()), ProcName(ProcName), Pid(sys::Process::getProcessId()), Tid(llvm::get_threadid()), TimeTraceGranularity(TimeTraceGranularity), - TimeTraceVerbose(TimeTraceVerbose) { + TimeTraceVerbose(TimeTraceVerbose), + TimeTraceCompress(TimeTraceCompress) { llvm::get_thread_name(ThreadName); } @@ -212,7 +215,7 @@ struct llvm::TimeTraceProfiler { // Write events from this TimeTraceProfilerInstance and // ThreadTimeTraceProfilerInstances. - void write(raw_pwrite_stream &OS) { + void write(raw_ostream &OS) { // Acquire Mutex as reading ThreadTimeTraceProfilerInstances. auto &Instances = getTimeTraceProfilerInstances(); std::lock_guard<std::mutex> Lock(Instances.Lock); @@ -383,6 +386,9 @@ struct llvm::TimeTraceProfiler { // Make time trace capture verbose event details (e.g. source filenames). This // can increase the size of the output by 2-3 times. const bool TimeTraceVerbose; + + // Optional compression format for output. + DebugCompressionType TimeTraceCompress; }; bool llvm::isTimeTraceVerbose() { @@ -390,14 +396,22 @@ bool llvm::isTimeTraceVerbose() { getTimeTraceProfilerInstance()->TimeTraceVerbose; } +DebugCompressionType llvm::inferTimeTraceCompressionFromPath(StringRef Path) { + StringRef Ext = llvm::sys::path::extension(Path); + if (Ext.equals_insensitive(".zst") || Ext.equals_insensitive(".zstd")) + return DebugCompressionType::Zstd; + return DebugCompressionType::None; +} + void llvm::timeTraceProfilerInitialize(unsigned TimeTraceGranularity, StringRef ProcName, - bool TimeTraceVerbose) { + bool TimeTraceVerbose, + DebugCompressionType TimeTraceCompress) { assert(TimeTraceProfilerInstance == nullptr && "Profiler should not be initialized"); TimeTraceProfilerInstance = new TimeTraceProfiler( TimeTraceGranularity, llvm::sys::path::filename(ProcName), - TimeTraceVerbose); + TimeTraceVerbose, TimeTraceCompress); } // Removes all TimeTraceProfilerInstances. @@ -425,7 +439,30 @@ void llvm::timeTraceProfilerFinishThread() { void llvm::timeTraceProfilerWrite(raw_pwrite_stream &OS) { assert(TimeTraceProfilerInstance != nullptr && "Profiler object can't be null"); - TimeTraceProfilerInstance->write(OS); + DebugCompressionType CompressType = + TimeTraceProfilerInstance->TimeTraceCompress; + if (CompressType == DebugCompressionType::None) { + TimeTraceProfilerInstance->write(OS); + return; + } + + compression::Format F = compression::formatFor(CompressType); + if (const char *Reason = compression::getReasonIfUnsupported(F)) + report_fatal_error(Reason); + + SmallVector<char, 0> Uncompressed; + { + raw_svector_ostream UncompressedOS(Uncompressed); + TimeTraceProfilerInstance->write(UncompressedOS); + } + SmallVector<uint8_t, 0> Compressed; + compression::compress( + compression::Params(F), + ArrayRef(reinterpret_cast<const uint8_t *>(Uncompressed.data()), + Uncompressed.size()), + Compressed); + OS.write(reinterpret_cast<const char *>(Compressed.data()), + Compressed.size()); } Error llvm::timeTraceProfilerWrite(StringRef PreferredFileName, @@ -437,14 +474,35 @@ Error llvm::timeTraceProfilerWrite(StringRef PreferredFileName, if (Path.empty()) { Path = FallbackFileName == "-" ? "out" : FallbackFileName.str(); Path += TimeTraceFileExtension; + if (TimeTraceProfilerInstance->TimeTraceCompress == + DebugCompressionType::Zstd) + Path += ".zst"; + } + + DebugCompressionType CompressType = + TimeTraceProfilerInstance->TimeTraceCompress; + if (CompressType == DebugCompressionType::None) + CompressType = inferTimeTraceCompressionFromPath(Path); + + if (CompressType != DebugCompressionType::None) { + if (const char *Reason = compression::getReasonIfUnsupported( + compression::formatFor(CompressType))) + return createStringError(inconvertibleErrorCode(), Reason); } std::error_code EC; - raw_fd_ostream OS(Path, EC, sys::fs::OF_TextWithCRLF); + sys::fs::OpenFlags Flags = CompressType == DebugCompressionType::None + ? sys::fs::OF_TextWithCRLF + : sys::fs::OF_None; + raw_fd_ostream OS(Path, EC, Flags); if (EC) return createStringError(EC, "Could not open " + Path); + DebugCompressionType SavedCompress = + TimeTraceProfilerInstance->TimeTraceCompress; + TimeTraceProfilerInstance->TimeTraceCompress = CompressType; timeTraceProfilerWrite(OS); + TimeTraceProfilerInstance->TimeTraceCompress = SavedCompress; return Error::success(); } diff --git a/llvm/unittests/Support/TimeProfilerTest.cpp b/llvm/unittests/Support/TimeProfilerTest.cpp index aa1185bae2961..38d25b35991aa 100644 --- a/llvm/unittests/Support/TimeProfilerTest.cpp +++ b/llvm/unittests/Support/TimeProfilerTest.cpp @@ -43,6 +43,34 @@ TEST(TimeProfiler, Scope_Smoke) { ASSERT_TRUE(json.find(R"("detail":"detail")") != std::string::npos); } +TEST(TimeProfiler, Compression) { + EXPECT_EQ(inferTimeTraceCompressionFromPath("foo.json"), + DebugCompressionType::None); + EXPECT_EQ(inferTimeTraceCompressionFromPath("foo.json.zst"), + DebugCompressionType::Zstd); + EXPECT_EQ(inferTimeTraceCompressionFromPath("foo.ZSTD"), + DebugCompressionType::Zstd); + + if (!compression::zstd::isAvailable()) + return; + + timeTraceProfilerInitialize(/*TimeTraceGranularity=*/0, "test", + /*TimeTraceVerbose=*/false, + DebugCompressionType::Zstd); + { + TimeTraceScope Scope("compressed_event", "compressed_detail"); + } + + SmallVector<char, 0> CompressedChars; + raw_svector_ostream OS(CompressedChars); + timeTraceProfilerWrite(OS); + timeTraceProfilerCleanup(); + + ASSERT_FALSE(CompressedChars.empty()); + // Compressed output must not start with '{'. + EXPECT_NE(CompressedChars.front(), '{'); +} + TEST(TimeProfiler, Begin_End_Smoke) { setupProfiler(); >From 52e61698f81748e1009883b8bf59b689edfba190 Mon Sep 17 00:00:00 2001 From: Chandler Carruth <[email protected]> Date: Mon, 5 Oct 2026 08:07:28 +0000 Subject: [PATCH 2/3] [TimeProfiler][Clang] Address review comments on #228627 - Simplify Path and CompressType initialization in timeTraceProfilerWrite so inferTimeTraceCompressionFromPath is only consulted when an explicit PreferredFileName is provided. - Clarify the comment on -ftime-trace-compress=none in the Clang driver and add a driver test case for overriding an earlier -ftime-trace-compress flag. Assisted-by: Antigravity with Gemini --- clang/lib/Driver/ToolChains/Clang.cpp | 5 +++-- clang/test/Driver/ftime-trace.cpp | 4 ++++ llvm/lib/Support/TimeProfiler.cpp | 12 +++++------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index eda506494829a..a49bf1256e54c 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7350,8 +7350,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.getLastArg(options::OPT_ftime_trace_compress_EQ)) { StringRef Value = CompressArg->getValue(); if (Value == "none") { - // Explicit -ftime-trace-compress=none disables compression even if the - // filename has a .zst/.zstd extension. + // Explicit -ftime-trace-compress=none disables compression (for + // example, overriding an earlier -ftime-trace-compress flag or a + // .zst/.zstd filename extension); -cc1 defaults to uncompressed output. } else if (Value == "zstd") { if (llvm::compression::zstd::isAvailable()) CmdArgs.push_back("-ftime-trace-compress=zstd"); diff --git a/clang/test/Driver/ftime-trace.cpp b/clang/test/Driver/ftime-trace.cpp index 77c46ae43bb53..4a3a644165444 100644 --- a/clang/test/Driver/ftime-trace.cpp +++ b/clang/test/Driver/ftime-trace.cpp @@ -65,6 +65,10 @@ // UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace-compress=none' // UNUSED-NOT: warning: +// RUN: %clang -### -c -ftime-trace -ftime-trace-compress -ftime-trace-compress=none -fintegrated-as d/a.cpp -o e/a.o 2>&1 | FileCheck %s --check-prefix=COMPRESS-OVERRIDE-NONE +// COMPRESS-OVERRIDE-NONE: -cc1{{.*}} "-ftime-trace=e/a.json" +// COMPRESS-OVERRIDE-NONE-NOT: "-ftime-trace-compress + // RUN: %clang -### -c -ftime-trace=foo.json.zst -ftime-trace-compress=none -fintegrated-as d/a.cpp -o e/a.o 2>&1 | FileCheck %s --check-prefix=COMPRESS-NONE // COMPRESS-NONE: -cc1{{.*}} "-ftime-trace=foo.json.zst" // COMPRESS-NONE-NOT: "-ftime-trace-compress diff --git a/llvm/lib/Support/TimeProfiler.cpp b/llvm/lib/Support/TimeProfiler.cpp index c2816e98cd30a..5edcc6212c594 100644 --- a/llvm/lib/Support/TimeProfiler.cpp +++ b/llvm/lib/Support/TimeProfiler.cpp @@ -470,19 +470,17 @@ Error llvm::timeTraceProfilerWrite(StringRef PreferredFileName, assert(TimeTraceProfilerInstance != nullptr && "Profiler object can't be null"); + DebugCompressionType CompressType = + TimeTraceProfilerInstance->TimeTraceCompress; std::string Path = PreferredFileName.str(); if (Path.empty()) { Path = FallbackFileName == "-" ? "out" : FallbackFileName.str(); Path += TimeTraceFileExtension; - if (TimeTraceProfilerInstance->TimeTraceCompress == - DebugCompressionType::Zstd) + if (CompressType == DebugCompressionType::Zstd) Path += ".zst"; - } - - DebugCompressionType CompressType = - TimeTraceProfilerInstance->TimeTraceCompress; - if (CompressType == DebugCompressionType::None) + } else if (CompressType == DebugCompressionType::None) { CompressType = inferTimeTraceCompressionFromPath(Path); + } if (CompressType != DebugCompressionType::None) { if (const char *Reason = compression::getReasonIfUnsupported( >From ecfda00fe1db581dcc0a18bad5958df8b386d400 Mon Sep 17 00:00:00 2001 From: Chandler Carruth <[email protected]> Date: Tue, 6 Oct 2026 02:41:08 +0000 Subject: [PATCH 3/3] [TimeProfiler][Clang] Use tri-state TimeTraceCompression and remove bare flag - Introduce llvm::TimeTraceCompression ({Infer, None, Zstd}) in TimeProfiler.h so TimeTraceCompression::Infer infers compression from the output path while TimeTraceCompression::None explicitly disables compression even for .zst/.zstd filenames. - Remove the bare -ftime-trace-compress alias in favor of explicit -ftime-trace-compress=<none|zstd|infer>. Assisted-by: Antigravity with Gemini --- .../include/clang/Frontend/FrontendOptions.h | 8 ++-- clang/include/clang/Options/Options.td | 12 ++---- clang/lib/Driver/ToolChains/Clang.cpp | 30 ++++++------- clang/lib/Frontend/CompilerInvocation.cpp | 9 +++- clang/test/Driver/compress-zstd.c | 3 +- clang/test/Driver/ftime-trace.cpp | 9 ++-- clang/tools/driver/cc1_main.cpp | 16 +++++-- llvm/include/llvm/Support/TimeProfiler.h | 12 ++++-- llvm/lib/Support/TimeProfiler.cpp | 41 +++++++++--------- llvm/unittests/Support/TimeProfilerTest.cpp | 42 +++++++++++++++++-- 10 files changed, 117 insertions(+), 65 deletions(-) diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index 701c8d75fe61f..5624934cd8659 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -16,8 +16,8 @@ #include "clang/Serialization/ModuleFileExtension.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/Compression.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/TimeProfiler.h" #include <cassert> #include <map> #include <memory> @@ -544,9 +544,9 @@ class FrontendOptions { LLVM_PREFERRED_TYPE(bool) unsigned TimeTraceVerbose : 1; - /// Compression format for -ftime-trace output. - llvm::DebugCompressionType TimeTraceCompress = - llvm::DebugCompressionType::None; + /// Compression mode for -ftime-trace output. + llvm::TimeTraceCompression TimeTraceCompress = + llvm::TimeTraceCompression::Infer; /// Path which stores the output files for -ftime-trace std::string TimeTracePath; diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 1d867223b9b68..c73a811a1a4ec 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -4824,15 +4824,11 @@ def ftime_trace_verbose : Joined<["-"], "ftime-trace-verbose">, Group<f_Group>, MarshallingInfoFlag<FrontendOpts<"TimeTraceVerbose">>; def ftime_trace_compress_EQ : Joined<["-"], "ftime-trace-compress=">, Group<f_Group>, HelpText<"Compress -ftime-trace output with the specified algorithm">, - Values<"none,zstd">, - NormalizedValuesScope<"llvm::DebugCompressionType">, - NormalizedValues<["None", "Zstd"]>, + Values<"none,zstd,infer">, + NormalizedValuesScope<"llvm::TimeTraceCompression">, + NormalizedValues<["None", "Zstd", "Infer"]>, Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>, - MarshallingInfoEnum<FrontendOpts<"TimeTraceCompress">, "None">; -def ftime_trace_compress : Flag<["-"], "ftime-trace-compress">, Group<f_Group>, - Alias<ftime_trace_compress_EQ>, AliasArgs<["zstd"]>, - HelpText<"Alias for -ftime-trace-compress=zstd">, - Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>; + MarshallingInfoEnum<FrontendOpts<"TimeTraceCompress">, "Infer">; def ftime_trace_EQ : Joined<["-"], "ftime-trace=">, Group<f_Group>, HelpText<"Similar to -ftime-trace. Specify the JSON file or a directory which will contain the JSON file">, Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index a49bf1256e54c..1858c3b35f274 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7346,28 +7346,31 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("-ftime-trace=" + Twine(Name))); Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_verbose); + llvm::TimeTraceCompression Compress = llvm::TimeTraceCompression::Infer; if (const Arg *CompressArg = Args.getLastArg(options::OPT_ftime_trace_compress_EQ)) { StringRef Value = CompressArg->getValue(); - if (Value == "none") { - // Explicit -ftime-trace-compress=none disables compression (for - // example, overriding an earlier -ftime-trace-compress flag or a - // .zst/.zstd filename extension); -cc1 defaults to uncompressed output. - } else if (Value == "zstd") { - if (llvm::compression::zstd::isAvailable()) - CmdArgs.push_back("-ftime-trace-compress=zstd"); - else - D.Diag(diag::err_drv_time_trace_compression_unavailable) << "zstd"; - } else { + if (Value == "none") + Compress = llvm::TimeTraceCompression::None; + else if (Value == "zstd") + Compress = llvm::TimeTraceCompression::Zstd; + else if (Value == "infer") + Compress = llvm::TimeTraceCompression::Infer; + else D.Diag(diag::err_drv_unsupported_option_argument) << CompressArg->getSpelling() << Value; - } - } else if (llvm::inferTimeTraceCompressionFromPath(Name) == - llvm::DebugCompressionType::Zstd) { + } + if (Compress == llvm::TimeTraceCompression::Infer) + Compress = llvm::inferTimeTraceCompressionFromPath(Name); + if (Compress == llvm::TimeTraceCompression::Zstd) { if (llvm::compression::zstd::isAvailable()) CmdArgs.push_back("-ftime-trace-compress=zstd"); else D.Diag(diag::err_drv_time_trace_compression_unavailable) << "zstd"; + } else if (Compress == llvm::TimeTraceCompression::None && + llvm::inferTimeTraceCompressionFromPath(Name) != + llvm::TimeTraceCompression::None) { + CmdArgs.push_back("-ftime-trace-compress=none"); } } @@ -9785,7 +9788,6 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, OPT_ftime_trace_EQ, OPT_ftime_trace_granularity_EQ, OPT_ftime_trace_verbose, - OPT_ftime_trace_compress, OPT_ftime_trace_compress_EQ, OPT_opt_record_file, OPT_opt_record_format, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index ed30d93b6026b..2d8eaea5782a7 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -5239,8 +5239,13 @@ bool CompilerInvocation::CreateFromArgsImpl( llvm::driver::ProfileInstrKind::ProfileNone) Diags.Report(diag::err_drv_profile_instrument_use_path_with_no_kind); - if (Res.getFrontendOpts().TimeTraceCompress == - llvm::DebugCompressionType::Zstd && + llvm::TimeTraceCompression TimeTraceCompress = + Res.getFrontendOpts().TimeTraceCompress; + if (TimeTraceCompress == llvm::TimeTraceCompression::Infer && + !Res.getFrontendOpts().TimeTracePath.empty()) + TimeTraceCompress = llvm::inferTimeTraceCompressionFromPath( + Res.getFrontendOpts().TimeTracePath); + if (TimeTraceCompress == llvm::TimeTraceCompression::Zstd && !llvm::compression::zstd::isAvailable()) Diags.Report(diag::err_drv_time_trace_compression_unavailable) << "zstd"; diff --git a/clang/test/Driver/compress-zstd.c b/clang/test/Driver/compress-zstd.c index a8e07631eede4..22f9ca53e3be8 100644 --- a/clang/test/Driver/compress-zstd.c +++ b/clang/test/Driver/compress-zstd.c @@ -6,6 +6,7 @@ // CHECK: {{"-cc1(as)?".* "--compress-debug-sections=zstd"}} // CHECK: "--compress-debug-sections=zstd" -// RUN: %clang -### -c -ftime-trace -ftime-trace-compress %s -o a.o 2>&1 | FileCheck %s --check-prefix=TIME-TRACE-ZSTD +// RUN: %clang -### -c -ftime-trace -ftime-trace-compress=zstd %s -o a.o 2>&1 | FileCheck %s --check-prefix=TIME-TRACE-ZSTD // RUN: %clang -### -c -ftime-trace=a.json.zst %s -o a.o 2>&1 | FileCheck %s --check-prefix=TIME-TRACE-ZSTD +// RUN: %clang -### -c -ftime-trace=a.json.zst -ftime-trace-compress=none -ftime-trace-compress=infer %s -o a.o 2>&1 | FileCheck %s --check-prefix=TIME-TRACE-ZSTD // TIME-TRACE-ZSTD: "-cc1"{{.*}} "-ftime-trace=a.json.zst" "-ftime-trace-compress=zstd" diff --git a/clang/test/Driver/ftime-trace.cpp b/clang/test/Driver/ftime-trace.cpp index 4a3a644165444..032cbab5e4025 100644 --- a/clang/test/Driver/ftime-trace.cpp +++ b/clang/test/Driver/ftime-trace.cpp @@ -55,23 +55,22 @@ // LINK3: -cc1{{.*}} "-ftime-trace=e{{/|\\\\}}a-{{[^.]*}}.json" "-ftime-trace-granularity=0" "-ftime-trace-verbose" // LINK3: -cc1{{.*}} "-ftime-trace=e{{/|\\\\}}b-{{[^.]*}}.json" "-ftime-trace-granularity=0" "-ftime-trace-verbose" -// RUN: %clang -### -ftime-trace -ftime-trace=e -ftime-trace-granularity=1 -ftime-trace-verbose -ftime-trace-compress -ftime-trace-compress=none -xassembler d/a.cpp 2>&1 | \ +// RUN: %clang -### -ftime-trace -ftime-trace=e -ftime-trace-granularity=1 -ftime-trace-verbose -ftime-trace-compress=none -xassembler d/a.cpp 2>&1 | \ // RUN: FileCheck %s --check-prefix=UNUSED // UNUSED: warning: argument unused during compilation: '-ftime-trace' // UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace=e' // UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace-granularity=1' // UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace-verbose' -// UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace-compress' // UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace-compress=none' // UNUSED-NOT: warning: -// RUN: %clang -### -c -ftime-trace -ftime-trace-compress -ftime-trace-compress=none -fintegrated-as d/a.cpp -o e/a.o 2>&1 | FileCheck %s --check-prefix=COMPRESS-OVERRIDE-NONE +// RUN: %clang -### -c -ftime-trace -ftime-trace-compress=zstd -ftime-trace-compress=none -fintegrated-as d/a.cpp -o e/a.o 2>&1 | FileCheck %s --check-prefix=COMPRESS-OVERRIDE-NONE +// RUN: %clang -### -c -ftime-trace -ftime-trace-compress=zstd -ftime-trace-compress=infer -fintegrated-as d/a.cpp -o e/a.o 2>&1 | FileCheck %s --check-prefix=COMPRESS-OVERRIDE-NONE // COMPRESS-OVERRIDE-NONE: -cc1{{.*}} "-ftime-trace=e/a.json" // COMPRESS-OVERRIDE-NONE-NOT: "-ftime-trace-compress // RUN: %clang -### -c -ftime-trace=foo.json.zst -ftime-trace-compress=none -fintegrated-as d/a.cpp -o e/a.o 2>&1 | FileCheck %s --check-prefix=COMPRESS-NONE -// COMPRESS-NONE: -cc1{{.*}} "-ftime-trace=foo.json.zst" -// COMPRESS-NONE-NOT: "-ftime-trace-compress +// COMPRESS-NONE: -cc1{{.*}} "-ftime-trace=foo.json.zst" "-ftime-trace-compress=none" // RUN: not %clang -### -c -ftime-trace -ftime-trace-compress=invalid d/a.cpp -o e/a.o 2>&1 | FileCheck %s --check-prefix=COMPRESS-INVALID // COMPRESS-INVALID: error: unsupported argument 'invalid' to option '-ftime-trace-compress=' diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index 1c3fef0630ea4..5ed0c372717e1 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -251,10 +251,14 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { std::move(PCHOps)); if (!Clang->getFrontendOpts().TimeTracePath.empty()) { + llvm::TimeTraceCompression Compress = + Clang->getFrontendOpts().TimeTraceCompress; + if (Compress == llvm::TimeTraceCompression::Infer) + Compress = llvm::inferTimeTraceCompressionFromPath( + Clang->getFrontendOpts().TimeTracePath); llvm::timeTraceProfilerInitialize( Clang->getFrontendOpts().TimeTraceGranularity, Argv0, - Clang->getFrontendOpts().TimeTraceVerbose, - Clang->getFrontendOpts().TimeTraceCompress); + Clang->getFrontendOpts().TimeTraceVerbose, Compress); } // --print-supported-cpus takes priority over the actual compilation. if (Clang->getFrontendOpts().PrintSupportedCPUs) @@ -313,8 +317,12 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { } if (llvm::timeTraceProfilerEnabled()) { - bool Binary = Clang->getFrontendOpts().TimeTraceCompress != - llvm::DebugCompressionType::None; + llvm::TimeTraceCompression Compress = + Clang->getFrontendOpts().TimeTraceCompress; + if (Compress == llvm::TimeTraceCompression::Infer) + Compress = llvm::inferTimeTraceCompressionFromPath( + Clang->getFrontendOpts().TimeTracePath); + bool Binary = Compress == llvm::TimeTraceCompression::Zstd; if (auto profilerOutput = Clang->createOutputFile( Clang->getFrontendOpts().TimeTracePath, Binary, /*RemoveFileOnSignal=*/false, diff --git a/llvm/include/llvm/Support/TimeProfiler.h b/llvm/include/llvm/Support/TimeProfiler.h index 014379de62f0d..66b543a63e86b 100644 --- a/llvm/include/llvm/Support/TimeProfiler.h +++ b/llvm/include/llvm/Support/TimeProfiler.h @@ -78,7 +78,6 @@ #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/Compression.h" #include "llvm/Support/Error.h" namespace llvm { @@ -98,6 +97,13 @@ enum class TimeTraceEventType { AsyncEvent }; +/// Compression mode for time trace output. +enum class TimeTraceCompression { + Infer, + None, + Zstd, +}; + struct TimeTraceMetadata { std::string Detail; // Source file and line number information for the event. @@ -116,7 +122,7 @@ struct TimeTraceProfilerEntry; /// Infer the time trace compression format from \p Path based on its file /// extension (.zst/.zstd -> Zstd, otherwise None). -LLVM_ABI DebugCompressionType inferTimeTraceCompressionFromPath(StringRef Path); +LLVM_ABI TimeTraceCompression inferTimeTraceCompressionFromPath(StringRef Path); /// Initialize the time trace profiler. /// This sets up the global \p TimeTraceProfilerInstance @@ -124,7 +130,7 @@ LLVM_ABI DebugCompressionType inferTimeTraceCompressionFromPath(StringRef Path); LLVM_ABI void timeTraceProfilerInitialize( unsigned TimeTraceGranularity, StringRef ProcName, bool TimeTraceVerbose = false, - DebugCompressionType TimeTraceCompress = DebugCompressionType::None); + TimeTraceCompression TimeTraceCompress = TimeTraceCompression::Infer); /// Cleanup the time trace profiler, if it was initialized. LLVM_ABI void timeTraceProfilerCleanup(); diff --git a/llvm/lib/Support/TimeProfiler.cpp b/llvm/lib/Support/TimeProfiler.cpp index 5edcc6212c594..05df72e30ad1a 100644 --- a/llvm/lib/Support/TimeProfiler.cpp +++ b/llvm/lib/Support/TimeProfiler.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/JSON.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" @@ -130,7 +131,7 @@ struct llvm::TimeTraceProfiler { TimeTraceProfiler( unsigned TimeTraceGranularity = 0, StringRef ProcName = "", bool TimeTraceVerbose = false, - DebugCompressionType TimeTraceCompress = DebugCompressionType::None) + TimeTraceCompression TimeTraceCompress = TimeTraceCompression::Infer) : BeginningOfTime(system_clock::now()), StartTime(ClockType::now()), ProcName(ProcName), Pid(sys::Process::getProcessId()), Tid(llvm::get_threadid()), TimeTraceGranularity(TimeTraceGranularity), @@ -387,8 +388,8 @@ struct llvm::TimeTraceProfiler { // can increase the size of the output by 2-3 times. const bool TimeTraceVerbose; - // Optional compression format for output. - DebugCompressionType TimeTraceCompress; + // Compression mode for output. + TimeTraceCompression TimeTraceCompress; }; bool llvm::isTimeTraceVerbose() { @@ -396,17 +397,17 @@ bool llvm::isTimeTraceVerbose() { getTimeTraceProfilerInstance()->TimeTraceVerbose; } -DebugCompressionType llvm::inferTimeTraceCompressionFromPath(StringRef Path) { +TimeTraceCompression llvm::inferTimeTraceCompressionFromPath(StringRef Path) { StringRef Ext = llvm::sys::path::extension(Path); if (Ext.equals_insensitive(".zst") || Ext.equals_insensitive(".zstd")) - return DebugCompressionType::Zstd; - return DebugCompressionType::None; + return TimeTraceCompression::Zstd; + return TimeTraceCompression::None; } void llvm::timeTraceProfilerInitialize(unsigned TimeTraceGranularity, StringRef ProcName, bool TimeTraceVerbose, - DebugCompressionType TimeTraceCompress) { + TimeTraceCompression TimeTraceCompress) { assert(TimeTraceProfilerInstance == nullptr && "Profiler should not be initialized"); TimeTraceProfilerInstance = new TimeTraceProfiler( @@ -439,14 +440,14 @@ void llvm::timeTraceProfilerFinishThread() { void llvm::timeTraceProfilerWrite(raw_pwrite_stream &OS) { assert(TimeTraceProfilerInstance != nullptr && "Profiler object can't be null"); - DebugCompressionType CompressType = + TimeTraceCompression CompressType = TimeTraceProfilerInstance->TimeTraceCompress; - if (CompressType == DebugCompressionType::None) { + if (CompressType != TimeTraceCompression::Zstd) { TimeTraceProfilerInstance->write(OS); return; } - compression::Format F = compression::formatFor(CompressType); + compression::Format F = compression::Format::Zstd; if (const char *Reason = compression::getReasonIfUnsupported(F)) report_fatal_error(Reason); @@ -470,33 +471,33 @@ Error llvm::timeTraceProfilerWrite(StringRef PreferredFileName, assert(TimeTraceProfilerInstance != nullptr && "Profiler object can't be null"); - DebugCompressionType CompressType = + TimeTraceCompression CompressType = TimeTraceProfilerInstance->TimeTraceCompress; std::string Path = PreferredFileName.str(); if (Path.empty()) { Path = FallbackFileName == "-" ? "out" : FallbackFileName.str(); Path += TimeTraceFileExtension; - if (CompressType == DebugCompressionType::Zstd) + if (CompressType == TimeTraceCompression::Zstd) Path += ".zst"; - } else if (CompressType == DebugCompressionType::None) { + } else if (CompressType == TimeTraceCompression::Infer) { CompressType = inferTimeTraceCompressionFromPath(Path); } - if (CompressType != DebugCompressionType::None) { - if (const char *Reason = compression::getReasonIfUnsupported( - compression::formatFor(CompressType))) + if (CompressType == TimeTraceCompression::Zstd) { + if (const char *Reason = + compression::getReasonIfUnsupported(compression::Format::Zstd)) return createStringError(inconvertibleErrorCode(), Reason); } std::error_code EC; - sys::fs::OpenFlags Flags = CompressType == DebugCompressionType::None - ? sys::fs::OF_TextWithCRLF - : sys::fs::OF_None; + sys::fs::OpenFlags Flags = CompressType == TimeTraceCompression::Zstd + ? sys::fs::OF_None + : sys::fs::OF_TextWithCRLF; raw_fd_ostream OS(Path, EC, Flags); if (EC) return createStringError(EC, "Could not open " + Path); - DebugCompressionType SavedCompress = + TimeTraceCompression SavedCompress = TimeTraceProfilerInstance->TimeTraceCompress; TimeTraceProfilerInstance->TimeTraceCompress = CompressType; timeTraceProfilerWrite(OS); diff --git a/llvm/unittests/Support/TimeProfilerTest.cpp b/llvm/unittests/Support/TimeProfilerTest.cpp index 38d25b35991aa..d10b4bce2c5fc 100644 --- a/llvm/unittests/Support/TimeProfilerTest.cpp +++ b/llvm/unittests/Support/TimeProfilerTest.cpp @@ -15,6 +15,10 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/TimeProfiler.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" #include "gtest/gtest.h" using namespace llvm; @@ -45,18 +49,18 @@ TEST(TimeProfiler, Scope_Smoke) { TEST(TimeProfiler, Compression) { EXPECT_EQ(inferTimeTraceCompressionFromPath("foo.json"), - DebugCompressionType::None); + TimeTraceCompression::None); EXPECT_EQ(inferTimeTraceCompressionFromPath("foo.json.zst"), - DebugCompressionType::Zstd); + TimeTraceCompression::Zstd); EXPECT_EQ(inferTimeTraceCompressionFromPath("foo.ZSTD"), - DebugCompressionType::Zstd); + TimeTraceCompression::Zstd); if (!compression::zstd::isAvailable()) return; timeTraceProfilerInitialize(/*TimeTraceGranularity=*/0, "test", /*TimeTraceVerbose=*/false, - DebugCompressionType::Zstd); + TimeTraceCompression::Zstd); { TimeTraceScope Scope("compressed_event", "compressed_detail"); } @@ -69,6 +73,36 @@ TEST(TimeProfiler, Compression) { ASSERT_FALSE(CompressedChars.empty()); // Compressed output must not start with '{'. EXPECT_NE(CompressedChars.front(), '{'); + + SmallString<128> TempPath; + sys::fs::createUniquePath("time-trace-%%%%%%%.json.zst", TempPath, true); + llvm::scope_exit CleanupFile([&]() { sys::fs::remove(TempPath); }); + + // Default (TimeTraceCompression::Infer) infers Zstd from the .zst extension. + timeTraceProfilerInitialize(/*TimeTraceGranularity=*/0, "test"); + { + TimeTraceScope Scope("inferred_event", "inferred_detail"); + } + ASSERT_FALSE(errorToBool(timeTraceProfilerWrite(TempPath, "fallback"))); + timeTraceProfilerCleanup(); + auto BufOrErr = MemoryBuffer::getFile(TempPath); + ASSERT_TRUE(static_cast<bool>(BufOrErr)); + ASSERT_FALSE((*BufOrErr)->getBuffer().empty()); + EXPECT_NE((*BufOrErr)->getBuffer().front(), '{'); + + // Explicit TimeTraceCompression::None overrides the .zst extension. + timeTraceProfilerInitialize(/*TimeTraceGranularity=*/0, "test", + /*TimeTraceVerbose=*/false, + TimeTraceCompression::None); + { + TimeTraceScope Scope("uncompressed_event", "uncompressed_detail"); + } + ASSERT_FALSE(errorToBool(timeTraceProfilerWrite(TempPath, "fallback"))); + timeTraceProfilerCleanup(); + BufOrErr = MemoryBuffer::getFile(TempPath); + ASSERT_TRUE(static_cast<bool>(BufOrErr)); + ASSERT_FALSE((*BufOrErr)->getBuffer().empty()); + EXPECT_EQ((*BufOrErr)->getBuffer().front(), '{'); } TEST(TimeProfiler, Begin_End_Smoke) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
