diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2828,6 +2828,15 @@ HelpText<"Minimum time granularity (in microseconds) traced by time profiler">, Flags<[CC1Option, CoreOption]>, MarshallingInfoInt, "500u">; +def ftime_trace_path : Joined<["-"], "ftime-trace=">, Group, + HelpText<"Turn on time profiler. Generates JSON file based on output filename. " + "Specify the path which stores the tracing output file.">, + DocBrief<[{ + Turn on time profiler. Generates JSON file based on output filename. Results + can be analyzed with chrome://tracing or `Speedscope App + `_ for flamegraph visualization.}]>, + Flags<[CC1Option, CoreOption]>, + MarshallingInfoString>; def fproc_stat_report : Joined<["-"], "fproc-stat-report">, Group, HelpText<"Print subprocess statistics">; def fproc_stat_report_EQ : Joined<["-"], "fproc-stat-report=">, Group, diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -499,6 +499,9 @@ /// Minimum time granularity (in microseconds) traced by time profiler. unsigned TimeTraceGranularity; + /// Path which stores the output files for -ftime-trace + std::string TimeTracePath; + public: FrontendOptions() : DisableFree(false), RelocatablePCH(false), ShowHelp(false), diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6183,6 +6183,7 @@ Args.AddLastArg(CmdArgs, options::OPT_ftime_report_EQ); Args.AddLastArg(CmdArgs, options::OPT_ftime_trace); Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); + Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_path); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); Args.AddLastArg(CmdArgs, options::OPT_malign_double); Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file); diff --git a/clang/test/Driver/check-time-trace.cpp b/clang/test/Driver/check-time-trace.cpp --- a/clang/test/Driver/check-time-trace.cpp +++ b/clang/test/Driver/check-time-trace.cpp @@ -2,6 +2,20 @@ // RUN: cat %T/check-time-trace.json \ // RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \ // RUN: | FileCheck %s +// RUN: %clangxx -S -ftime-trace=%T/new-name.json -ftime-trace-granularity=0 -o %T/check-time-trace %s +// RUN: cat %T/new-name.json \ +// RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \ +// RUN: | FileCheck %s +// RUN: mkdir %T/output1 +// RUN: %clangxx -S -ftime-trace=%T/output1 -ftime-trace-granularity=0 -o %T/check-time-trace %s +// RUN: cat %T/output1/check-time-trace.json \ +// RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \ +// RUN: | FileCheck %s +// RUN: mkdir %T/output2 +// RUN: %clangxx -S -ftime-trace=%T/output2/ -ftime-trace-granularity=0 -o %T/check-time-trace %s +// RUN: cat %T/output2/check-time-trace.json \ +// RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \ +// RUN: | FileCheck %s // CHECK: "beginningOfTime": {{[0-9]{16},}} // CHECK-NEXT: "traceEvents": [ diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -212,7 +212,9 @@ bool Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(), Argv, Diags, Argv0); - if (Clang->getFrontendOpts().TimeTrace) { + if (Clang->getFrontendOpts().TimeTrace || + !Clang->getFrontendOpts().TimeTracePath.empty()) { + Clang->getFrontendOpts().TimeTrace = 1; llvm::timeTraceProfilerInitialize( Clang->getFrontendOpts().TimeTraceGranularity, Argv0); } @@ -256,6 +258,15 @@ if (llvm::timeTraceProfilerEnabled()) { SmallString<128> Path(Clang->getFrontendOpts().OutputFile); llvm::sys::path::replace_extension(Path, "json"); + if (!Clang->getFrontendOpts().TimeTracePath.empty()) { + // replace the suffix to '.json' directly + SmallString<128> FileName(llvm::sys::path::filename(Path)); + SmallString<128> TracePath(Clang->getFrontendOpts().TimeTracePath); + if (llvm::sys::fs::is_directory(TracePath)) { + llvm::sys::path::append(TracePath, FileName); + } + Path.assign(TracePath); + } if (auto profilerOutput = Clang->createOutputFile( Path.str(), /*Binary=*/false, /*RemoveFileOnSignal=*/false, /*useTemporary=*/false)) {