https://github.com/chandlerc created https://github.com/llvm/llvm-project/pull/228627
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 >From ec262e8571bec9cea1e5d2aeeaf2ba4c7c55066c Mon Sep 17 00:00:00 2001 From: Chandler Carruth <[email protected]> Date: Fri, 2 Oct 2026 18:06:45 +0000 Subject: [PATCH] [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 | 13 +++- llvm/lib/Support/TimeProfiler.cpp | 74 +++++++++++++++++-- llvm/unittests/Support/TimeProfilerTest.cpp | 28 +++++++ 12 files changed, 186 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..417918cb1d5ae 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,18 @@ 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(); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
