[clang] [llvm] [TimeProfiler][Clang] Add zstd-compressed time-trace output support (PR #228627)
Chandler Carruth via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 2 17:50:06 PDT 2026
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 <chandlerc at gmail.com>
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();
More information about the cfe-commits
mailing list