Skip to content

Commit 49b87b0

Browse files
committed
[Driver] -ftime-trace: derive trace file names from -o and -dumpdir
Inspired by D133662. Close #57285 When -ftime-trace is specified and the driver performs both compilation and linking phases, the trace files are currently placed in the temporary directory (/tmp by default on *NIX). A more sensible behavior would be to derive the trace file names from the -o option, similar to how GCC derives auxiliary and dump file names. Use -dumpdir (D149193) to implement the -gsplit-dwarf like behavior. The following script demonstrates the time trace filenames. ``` #!/bin/sh -e PATH=/tmp/Rel/bin:$PATH # adapt according to your build directory mkdir -p d e f echo 'int main() {}' > d/a.c echo > d/b.c a() { rm $1 || exit 1; } clang -ftime-trace d/a.c d/b.c # previously /tmp/[ab]-*.json a a-a.json; a a-b.json clang -ftime-trace d/a.c d/b.c -o e/x # previously /tmp/[ab]-*.json a e/x-a.json; a e/x-b.json clang -ftime-trace d/a.c d/b.c -o e/x -dumpdir f/ a f/a.json; a f/b.json clang -ftime-trace=f d/a.c d/b.c -o e/x a f/a-*.json; a f/b-*.json clang -c -ftime-trace d/a.c d/b.c a a.json b.json clang -c -ftime-trace=f d/a.c d/b.c a f/a.json f/b.json clang -c -ftime-trace d/a.c -o e/xa.o a e/xa.json clang -c -ftime-trace d/a.c -o e/xa.o -dumpdir f/g a f/ga.json ``` The driver checks `-ftime-trace` and `-ftime-trace=`, infers the trace file name, and passes `-ftime-trace=` to cc1. The `-ftime-trace` cc1 option is removed. With offloading, previously `-ftime-trace` is passed to all offloading actions, causing the same trace file to be overwritten by host and offloading actions. This patch doesn't attempt to support offloading (D133662), but makes a sensible change (`OffloadingPrefix.empty()`) to ensure we don't overwrite the trace file. Minor behavior differences: the trace file is now a result file, which will be removed upon an error. -ftime-trace-granularity=0, like -ftime-trace, can now cause a -Wunused-command-line-argument warning. Reviewed By: Maetveis Differential Revision: https://reviews.llvm.org/D150282
1 parent b700a90 commit 49b87b0

File tree

7 files changed

+92
-32
lines changed

7 files changed

+92
-32
lines changed

clang/include/clang/Driver/Compilation.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ class Compilation {
112112
/// only be removed if we crash.
113113
ArgStringMap FailureResultFiles;
114114

115+
/// -ftime-trace result files.
116+
ArgStringMap TimeTraceFiles;
117+
115118
/// Optional redirection for stdin, stdout, stderr.
116119
std::vector<std::optional<StringRef>> Redirects;
117120

@@ -269,6 +272,14 @@ class Compilation {
269272
return Name;
270273
}
271274

275+
const char *getTimeTraceFile(const JobAction *JA) const {
276+
return TimeTraceFiles.lookup(JA);
277+
}
278+
void addTimeTraceFile(const char *Name, const JobAction *JA) {
279+
assert(!TimeTraceFiles.contains(JA));
280+
TimeTraceFiles[JA] = Name;
281+
}
282+
272283
/// CleanupFile - Delete a given file.
273284
///
274285
/// \param IssueErrors - Report failures as errors.

clang/include/clang/Driver/Options.td

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3004,8 +3004,7 @@ def ftime_trace : Flag<["-"], "ftime-trace">, Group<f_Group>,
30043004
Turn on time profiler. Generates JSON file based on output filename. Results
30053005
can be analyzed with chrome://tracing or `Speedscope App
30063006
<https://www.speedscope.app>`_ for flamegraph visualization.}]>,
3007-
Flags<[CC1Option, CoreOption]>,
3008-
MarshallingInfoFlag<FrontendOpts<"TimeTrace">>;
3007+
Flags<[CoreOption]>;
30093008
def ftime_trace_granularity_EQ : Joined<["-"], "ftime-trace-granularity=">, Group<f_Group>,
30103009
HelpText<"Minimum time granularity (in microseconds) traced by time profiler">,
30113010
Flags<[CC1Option, CoreOption]>,

clang/include/clang/Frontend/FrontendOptions.h

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -283,9 +283,6 @@ class FrontendOptions {
283283
/// print the supported cpus for the current target
284284
unsigned PrintSupportedCPUs : 1;
285285

286-
/// Output time trace profile.
287-
unsigned TimeTrace : 1;
288-
289286
/// Show the -version text.
290287
unsigned ShowVersion : 1;
291288

@@ -513,16 +510,16 @@ class FrontendOptions {
513510
public:
514511
FrontendOptions()
515512
: DisableFree(false), RelocatablePCH(false), ShowHelp(false),
516-
ShowStats(false), AppendStats(false), TimeTrace(false),
517-
ShowVersion(false), FixWhatYouCan(false), FixOnlyWarnings(false),
518-
FixAndRecompile(false), FixToTemporaries(false),
519-
ARCMTMigrateEmitARCErrors(false), SkipFunctionBodies(false),
520-
UseGlobalModuleIndex(true), GenerateGlobalModuleIndex(true),
521-
ASTDumpDecls(false), ASTDumpLookups(false),
522-
BuildingImplicitModule(false), BuildingImplicitModuleUsesLock(true),
523-
ModulesEmbedAllFiles(false), IncludeTimestamps(true),
524-
UseTemporary(true), AllowPCMWithCompilerErrors(false),
525-
ModulesShareFileManager(true), TimeTraceGranularity(500) {}
513+
ShowStats(false), AppendStats(false), ShowVersion(false),
514+
FixWhatYouCan(false), FixOnlyWarnings(false), FixAndRecompile(false),
515+
FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false),
516+
SkipFunctionBodies(false), UseGlobalModuleIndex(true),
517+
GenerateGlobalModuleIndex(true), ASTDumpDecls(false),
518+
ASTDumpLookups(false), BuildingImplicitModule(false),
519+
BuildingImplicitModuleUsesLock(true), ModulesEmbedAllFiles(false),
520+
IncludeTimestamps(true), UseTemporary(true),
521+
AllowPCMWithCompilerErrors(false), ModulesShareFileManager(true),
522+
TimeTraceGranularity(500) {}
526523

527524
/// getInputKindForExtension - Return the appropriate input kind for a file
528525
/// extension. For example, "c" would return Language::C.

clang/lib/Driver/Driver.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5234,6 +5234,37 @@ InputInfoList Driver::BuildJobsForAction(
52345234
return Result;
52355235
}
52365236

5237+
static void handleTimeTrace(Compilation &C, const ArgList &Args,
5238+
const JobAction *JA, const char *BaseInput,
5239+
const InputInfo &Result) {
5240+
Arg *A =
5241+
Args.getLastArg(options::OPT_ftime_trace, options::OPT_ftime_trace_EQ);
5242+
if (!A)
5243+
return;
5244+
SmallString<128> Path;
5245+
if (A->getOption().matches(options::OPT_ftime_trace_EQ)) {
5246+
Path = A->getValue();
5247+
if (llvm::sys::fs::is_directory(Path)) {
5248+
SmallString<128> Tmp(Result.getFilename());
5249+
llvm::sys::path::replace_extension(Tmp, "json");
5250+
llvm::sys::path::append(Path, llvm::sys::path::filename(Tmp));
5251+
}
5252+
} else {
5253+
if (Arg *DumpDir = Args.getLastArgNoClaim(options::OPT_dumpdir)) {
5254+
// The trace file is ${dumpdir}${basename}.json. Note that dumpdir may not
5255+
// end with a path separator.
5256+
Path = DumpDir->getValue();
5257+
Path += llvm::sys::path::filename(BaseInput);
5258+
} else {
5259+
Path = Result.getFilename();
5260+
}
5261+
llvm::sys::path::replace_extension(Path, "json");
5262+
}
5263+
const char *ResultFile = C.getArgs().MakeArgString(Path);
5264+
C.addTimeTraceFile(ResultFile, JA);
5265+
C.addResultFile(ResultFile, JA);
5266+
}
5267+
52375268
InputInfoList Driver::BuildJobsForActionNoCache(
52385269
Compilation &C, const Action *A, const ToolChain *TC, StringRef BoundArch,
52395270
bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput,
@@ -5483,6 +5514,8 @@ InputInfoList Driver::BuildJobsForActionNoCache(
54835514
AtTopLevel, MultipleArchs,
54845515
OffloadingPrefix),
54855516
BaseInput);
5517+
if (T->canEmitIR() && OffloadingPrefix.empty())
5518+
handleTimeTrace(C, Args, JA, BaseInput, Result);
54865519
}
54875520

54885521
if (CCCPrintBindings && !CCGenDiagnostics) {

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6344,13 +6344,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
63446344
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
63456345
Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
63466346
Args.AddLastArg(CmdArgs, options::OPT_ftime_report_EQ);
6347-
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace);
6348-
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ);
6349-
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_EQ);
63506347
Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
63516348
Args.AddLastArg(CmdArgs, options::OPT_malign_double);
63526349
Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file);
63536350

6351+
if (const char *Name = C.getTimeTraceFile(&JA)) {
6352+
CmdArgs.push_back(Args.MakeArgString("-ftime-trace=" + Twine(Name)));
6353+
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ);
6354+
}
6355+
63546356
if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) {
63556357
CmdArgs.push_back("-ftrapv-handler");
63566358
CmdArgs.push_back(A->getValue());

clang/test/Driver/ftime-trace.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,35 @@
3131
// CHECK: "name": "process_name"
3232
// CHECK: "name": "thread_name"
3333

34+
// RUN: mkdir d e f && cp %s d/a.cpp && touch d/b.c
35+
36+
// RUN: %clang -### -c -ftime-trace -ftime-trace-granularity=0 d/a.cpp -o e/a.o 2>&1 | FileCheck %s --check-prefix=COMPILE1
37+
// COMPILE1: -cc1{{.*}} "-ftime-trace=e/a.json" "-ftime-trace-granularity=0"
38+
39+
// RUN: %clang -### -c -ftime-trace -ftime-trace-granularity=0 d/a.cpp d/b.c -dumpdir f/ 2>&1 | FileCheck %s --check-prefix=COMPILE2
40+
// COMPILE2: -cc1{{.*}} "-ftime-trace=f/a.json" "-ftime-trace-granularity=0"
41+
// COMPILE2: -cc1{{.*}} "-ftime-trace=f/b.json" "-ftime-trace-granularity=0"
42+
43+
/// -o specifies the link output. Create ${output}-${basename}.json.
44+
// RUN: %clang -### -ftime-trace -ftime-trace-granularity=0 d/a.cpp d/b.c -o e/x 2>&1 | FileCheck %s --check-prefix=LINK1
45+
// LINK1: -cc1{{.*}} "-ftime-trace=e/x-a.json" "-ftime-trace-granularity=0"
46+
// LINK1: -cc1{{.*}} "-ftime-trace=e/x-b.json" "-ftime-trace-granularity=0"
47+
48+
/// -dumpdir is f/g, not ending with a path separator. We create f/g${basename}.json.
49+
// RUN: %clang -### -ftime-trace -ftime-trace-granularity=0 d/a.cpp d/b.c -o e/x -dumpdir f/g 2>&1 | FileCheck %s --check-prefix=LINK2
50+
// LINK2: -cc1{{.*}} "-ftime-trace=f/ga.json" "-ftime-trace-granularity=0"
51+
// LINK2: -cc1{{.*}} "-ftime-trace=f/gb.json" "-ftime-trace-granularity=0"
52+
53+
// RUN: %clang -### -ftime-trace=e -ftime-trace-granularity=0 d/a.cpp d/b.c -o f/x -dumpdir f/ 2>&1 | FileCheck %s --check-prefix=LINK3
54+
// LINK3: -cc1{{.*}} "-ftime-trace=e/a-{{[^.]*}}.json" "-ftime-trace-granularity=0"
55+
// LINK3: -cc1{{.*}} "-ftime-trace=e/b-{{[^.]*}}.json" "-ftime-trace-granularity=0"
56+
57+
// RUN: %clang -### -ftime-trace -ftime-trace=e -ftime-trace-granularity=1 -xassembler d/a.cpp 2>&1 | \
58+
// RUN: FileCheck %s --check-prefix=UNUSED --implicit-check-not=warning:
59+
// UNUSED: warning: argument unused during compilation: '-ftime-trace'
60+
// UNUSED: warning: argument unused during compilation: '-ftime-trace=e'
61+
// UNUSED: warning: argument unused during compilation: '-ftime-trace-granularity=1'
62+
3463
template <typename T>
3564
struct Struct {
3665
T Num;

clang/tools/driver/cc1_main.cpp

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
213213
bool Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
214214
Argv, Diags, Argv0);
215215

216-
if (Clang->getFrontendOpts().TimeTrace ||
217-
!Clang->getFrontendOpts().TimeTracePath.empty()) {
218-
Clang->getFrontendOpts().TimeTrace = 1;
216+
if (!Clang->getFrontendOpts().TimeTracePath.empty()) {
219217
llvm::timeTraceProfilerInitialize(
220218
Clang->getFrontendOpts().TimeTraceGranularity, Argv0);
221219
}
@@ -257,16 +255,6 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
257255
llvm::TimerGroup::clearAll();
258256

259257
if (llvm::timeTraceProfilerEnabled()) {
260-
SmallString<128> Path(Clang->getFrontendOpts().OutputFile);
261-
llvm::sys::path::replace_extension(Path, "json");
262-
if (!Clang->getFrontendOpts().TimeTracePath.empty()) {
263-
// replace the suffix to '.json' directly
264-
SmallString<128> TracePath(Clang->getFrontendOpts().TimeTracePath);
265-
if (llvm::sys::fs::is_directory(TracePath))
266-
llvm::sys::path::append(TracePath, llvm::sys::path::filename(Path));
267-
Path.assign(TracePath);
268-
}
269-
270258
// It is possible that the compiler instance doesn't own a file manager here
271259
// if we're compiling a module unit. Since the file manager are owned by AST
272260
// when we're compiling a module unit. So the file manager may be invalid
@@ -280,7 +268,8 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
280268
Clang->getInvocation(), Clang->getDiagnostics()));
281269

282270
if (auto profilerOutput = Clang->createOutputFile(
283-
Path.str(), /*Binary=*/false, /*RemoveFileOnSignal=*/false,
271+
Clang->getFrontendOpts().TimeTracePath, /*Binary=*/false,
272+
/*RemoveFileOnSignal=*/false,
284273
/*useTemporary=*/false)) {
285274
llvm::timeTraceProfilerWrite(*profilerOutput);
286275
profilerOutput.reset();

0 commit comments

Comments
 (0)