Maetveis created this revision.
Maetveis added a reviewer: clang.
Herald added a project: All.
Maetveis requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay.
Herald added a project: clang.

This is an alternative approach for [D131469 
<https://reviews.llvm.org/D131469>](https://reviews.llvm.org/D131469].

The difference in behavior compared to D131469 
<https://reviews.llvm.org/D131469> is that instead of looking for linking jobs, 
here if a "main" output is available ('-o <output>' is given) the directory of 
it is used for '-ftime-trace'.
Another is that time traces in offloading tool-chain (e.g. CUDA or HIP) 
compilation steps are also supported by saving them to the  same directory as 
the host trace, with naming similar to '-save-temps'.
If save temps the file type suffix is also included to keep the trace from e.g 
the front-end compilation overwriting the back-end trace.

The final behavior is this:

- if '-ftime-trace=path/to/trace.json' is given, then use it for the final 
compilation, and use the directory where it is for the rest (offloading or 
'-save-temps')
- if '-ftime-trace=path/to/trace/folder' is given:
  - for the main output use 'path/to/trace/folder/<output-name>,json' if '-o 
<output-name>.o' is given
  - if no output path is specified or for the rest of the files use 
'path/to/trace/folder/<input-name>.json' similar to '-save-temps'
- if '-ftime-trace' is given and there is a main output ('-o output') use the 
directory of it to store the traces
- if '-ftime-trace' but no '-o <output>' use the current working directory


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D133662

Files:
  clang/include/clang/Driver/Compilation.h
  clang/include/clang/Driver/Driver.h
  clang/include/clang/Driver/Options.td
  clang/include/clang/Driver/Tool.h
  clang/include/clang/Frontend/FrontendOptions.h
  clang/lib/Driver/Driver.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Driver/ToolChains/Clang.h
  clang/tools/driver/cc1_main.cpp

Index: clang/tools/driver/cc1_main.cpp
===================================================================
--- clang/tools/driver/cc1_main.cpp
+++ clang/tools/driver/cc1_main.cpp
@@ -212,9 +212,7 @@
   bool Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
                                                     Argv, Diags, Argv0);
 
-  if (Clang->getFrontendOpts().TimeTrace ||
-      !Clang->getFrontendOpts().TimeTracePath.empty()) {
-    Clang->getFrontendOpts().TimeTrace = 1;
+  if (!Clang->getFrontendOpts().TimeTracePath.empty()) {
     llvm::timeTraceProfilerInitialize(
         Clang->getFrontendOpts().TimeTraceGranularity, Argv0);
   }
@@ -256,17 +254,10 @@
   llvm::TimerGroup::clearAll();
 
   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> TracePath(Clang->getFrontendOpts().TimeTracePath);
-      if (llvm::sys::fs::is_directory(TracePath))
-        llvm::sys::path::append(TracePath, llvm::sys::path::filename(Path));
-      Path.assign(TracePath);
-    }
+    const StringRef TracePath = Clang->getFrontendOpts().TimeTracePath;
+    assert(!TracePath.empty() && "`-ftime-trace=<path>` is empty");
     if (auto profilerOutput = Clang->createOutputFile(
-            Path.str(), /*Binary=*/false, /*RemoveFileOnSignal=*/false,
+            TracePath, /*Binary=*/false, /*RemoveFileOnSignal=*/false,
             /*useTemporary=*/false)) {
       llvm::timeTraceProfilerWrite(*profilerOutput);
       profilerOutput.reset();
Index: clang/lib/Driver/ToolChains/Clang.h
===================================================================
--- clang/lib/Driver/ToolChains/Clang.h
+++ clang/lib/Driver/ToolChains/Clang.h
@@ -113,6 +113,7 @@
   bool hasIntegratedBackend() const override { return HasBackend; }
   bool hasIntegratedCPP() const override { return true; }
   bool canEmitIR() const override { return true; }
+  bool supportsTimeTrace() const override { return true; }
 
   void ConstructJob(Compilation &C, const JobAction &JA,
                     const InputInfo &Output, const InputInfoList &Inputs,
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -6230,9 +6230,11 @@
   Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
   Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
   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_EQ);
+
+  if (const char *Name = C.getTimeTraceFileForJob(&JA))
+    CmdArgs.push_back(Args.MakeArgString("-ftime-trace=" + Twine(Name)));
+
   Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
   Args.AddLastArg(CmdArgs, options::OPT_malign_double);
   Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file);
Index: clang/lib/Driver/Driver.cpp
===================================================================
--- clang/lib/Driver/Driver.cpp
+++ clang/lib/Driver/Driver.cpp
@@ -4510,6 +4510,82 @@
   llvm_unreachable("invalid phase in ConstructPhaseAction");
 }
 
+// Infer data storing path of the options `-ftime-trace`, `-ftime-trace=<path>`
+static void inferTimeTracePath(Compilation &C, const Arg *FinalOutput) {
+  const ArgList &Args = C.getArgs();
+  const bool HasTimeTrace = Args.hasArgNoClaim(options::OPT_ftime_trace);
+  const bool HasTimeTraceFile = Args.hasArgNoClaim(options::OPT_ftime_trace_EQ);
+
+  // Whether `-ftime-trace` or `-ftime-trace=<path>` are specified
+  if (!HasTimeTrace && !HasTimeTraceFile)
+    return;
+
+  if (HasTimeTraceFile) {
+    StringRef TracePath =
+        Args.getLastArgNoClaim(options::OPT_ftime_trace_EQ)->getValue();
+    if (!llvm::sys::fs::is_directory(TracePath))
+      TracePath = llvm::sys::path::parent_path(TracePath);
+    C.setTimeTracePath(TracePath);
+    return;
+  }
+
+  if (FinalOutput != nullptr) {
+    C.setTimeTracePath(llvm::sys::path::parent_path(FinalOutput->getValue()));
+    return;
+  }
+
+  // Empty trace path prefix, use the current working directory
+  C.setTimeTracePath(StringRef());
+}
+
+const char *Driver::getTimeTraceOutputPath(Compilation &C, const JobAction &JA,
+                                           StringRef OrigFileName,
+                                           StringRef OrigBoundArch,
+                                           bool AtTopLevel, bool MultipleArchs,
+                                           StringRef OffloadingPrefix) const {
+  StringRef FileName = OrigFileName;
+  if (AtTopLevel) {
+    // Output to a user requested destination?
+    if (const Arg *TimeTraceFile =
+            C.getArgs().getLastArg(options::OPT_ftime_trace_EQ)) {
+      if (!llvm::sys::fs::is_directory(TimeTraceFile->getValue()))
+        return TimeTraceFile->getValue();
+      assert(TimeTraceFile->getValue() == C.getTimeTracePath() &&
+             "C.getTimeTracePath() should match the value of -ftime-trace=");
+    }
+
+    // "-o output.o" -> "output.json"
+    if (const Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
+      FileName = FinalOutput->getValue();
+  }
+  const StringRef Stem = llvm::sys::path::stem(FileName);
+
+  llvm::SmallString<64> BoundArch(OrigBoundArch);
+  if (is_style_windows(llvm::sys::path::Style::native)) {
+    // BoundArch may contains ':', which is invalid in file names on Windows,
+    // therefore replace it with '%'.
+    std::replace(BoundArch.begin(), BoundArch.end(), ':', '@');
+  }
+
+  SmallString<128> TraceFileName(C.getTimeTracePath());
+  llvm::sys::path::append(TraceFileName, Stem);
+  TraceFileName += OffloadingPrefix;
+  if (MultipleArchs && !BoundArch.empty()) {
+    TraceFileName += "-";
+    TraceFileName.append(BoundArch);
+  }
+  if (isSaveTempsEnabled()) {
+    const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode());
+    assert(Suffix && "All types used for output should have a suffix.");
+    TraceFileName += ".";
+    TraceFileName += Suffix;
+  }
+
+  TraceFileName += ".json";
+
+  return C.addResultFile(C.getArgs().MakeArgString(TraceFileName.c_str()), &JA);
+}
+
 void Driver::BuildJobs(Compilation &C) const {
   llvm::PrettyStackTraceString CrashInfo("Building compilation jobs");
 
@@ -4572,6 +4648,8 @@
       if (A->getOption().matches(options::OPT_arch))
         ArchNames.insert(A->getValue());
 
+  inferTimeTracePath(C, FinalOutput);
+
   // Set of (Action, canonical ToolChain triple) pairs we've built jobs for.
   std::map<std::pair<const Action *, std::string>, InputInfoList> CachedResults;
   for (Action *A : C.getActions()) {
@@ -5325,6 +5403,22 @@
                        BaseInput);
   }
 
+  // Only claim the options if the tool supports '-ftime-trace'
+  if (T->supportsTimeTrace() &&
+      Args.hasArg(options::OPT_ftime_trace, options::OPT_ftime_trace_EQ)) {
+    // We only have to generate a prefix for the host if this is not a top-level
+    // action.
+    std::string OffloadingPrefix = Action::GetOffloadingFileNamePrefix(
+        A->getOffloadingDeviceKind(), TC->getTriple().normalize(),
+        /*CreatePrefixForHost=*/
+        !(A->getOffloadingHostActiveKinds() == Action::OFK_None || AtTopLevel));
+
+    const char *TimeTraceOutputPath =
+        getTimeTraceOutputPath(C, *JA, BaseInput, BoundArch, AtTopLevel,
+                               MultipleArchs, OffloadingPrefix);
+    C.setTimeTraceFileForJob(JA, TimeTraceOutputPath);
+  }
+
   if (CCCPrintBindings && !CCGenDiagnostics) {
     llvm::errs() << "# \"" << T->getToolChain().getTripleString() << '"'
                  << " - \"" << T->getName() << "\", inputs: [";
Index: clang/include/clang/Frontend/FrontendOptions.h
===================================================================
--- clang/include/clang/Frontend/FrontendOptions.h
+++ clang/include/clang/Frontend/FrontendOptions.h
@@ -283,9 +283,6 @@
   /// print the supported cpus for the current target
   unsigned PrintSupportedCPUs : 1;
 
-  /// Output time trace profile.
-  unsigned TimeTrace : 1;
-
   /// Show the -version text.
   unsigned ShowVersion : 1;
 
@@ -508,16 +505,15 @@
 public:
   FrontendOptions()
       : DisableFree(false), RelocatablePCH(false), ShowHelp(false),
-        ShowStats(false), TimeTrace(false), ShowVersion(false),
-        FixWhatYouCan(false), FixOnlyWarnings(false), FixAndRecompile(false),
-        FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false),
-        SkipFunctionBodies(false), UseGlobalModuleIndex(true),
-        GenerateGlobalModuleIndex(true), ASTDumpDecls(false),
-        ASTDumpLookups(false), BuildingImplicitModule(false),
-        BuildingImplicitModuleUsesLock(true), ModulesEmbedAllFiles(false),
-        IncludeTimestamps(true), UseTemporary(true),
-        AllowPCMWithCompilerErrors(false), ModulesShareFileManager(true),
-        TimeTraceGranularity(500) {}
+        ShowStats(false), ShowVersion(false), FixWhatYouCan(false),
+        FixOnlyWarnings(false), FixAndRecompile(false), FixToTemporaries(false),
+        ARCMTMigrateEmitARCErrors(false), SkipFunctionBodies(false),
+        UseGlobalModuleIndex(true), GenerateGlobalModuleIndex(true),
+        ASTDumpDecls(false), ASTDumpLookups(false),
+        BuildingImplicitModule(false), BuildingImplicitModuleUsesLock(true),
+        ModulesEmbedAllFiles(false), IncludeTimestamps(true),
+        UseTemporary(true), AllowPCMWithCompilerErrors(false),
+        ModulesShareFileManager(true), TimeTraceGranularity(500) {}
 
   /// getInputKindForExtension - Return the appropriate input kind for a file
   /// extension. For example, "c" would return Language::C.
Index: clang/include/clang/Driver/Tool.h
===================================================================
--- clang/include/clang/Driver/Tool.h
+++ clang/include/clang/Driver/Tool.h
@@ -62,6 +62,8 @@
   /// driver add an additional "command failed" diagnostic on failures.
   virtual bool hasGoodDiagnostics() const { return false; }
 
+  virtual bool supportsTimeTrace() const { return false; }
+
   /// ConstructJob - Construct jobs to perform the action \p JA,
   /// writing to \p Output and with \p Inputs, and add the jobs to
   /// \p C.
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -2872,8 +2872,7 @@
 Turn on time profiler. Generates JSON file based on output filename. Results
 can be analyzed with chrome://tracing or `Speedscope App
 <https://www.speedscope.app>`_ for flamegraph visualization.}]>,
-  Flags<[CC1Option, CoreOption]>,
-  MarshallingInfoFlag<FrontendOpts<"TimeTrace">>;
+  Flags<[CoreOption]>;
 def ftime_trace_granularity_EQ : Joined<["-"], "ftime-trace-granularity=">, Group<f_Group>,
   HelpText<"Minimum time granularity (in microseconds) traced by time profiler">,
   Flags<[CC1Option, CoreOption]>,
Index: clang/include/clang/Driver/Driver.h
===================================================================
--- clang/include/clang/Driver/Driver.h
+++ clang/include/clang/Driver/Driver.h
@@ -721,6 +721,12 @@
           &CachedResults,
       Action::OffloadKind TargetDeviceOffloadKind) const;
 
+  const char *getTimeTraceOutputPath(Compilation &C, const JobAction &JA,
+                                     StringRef OrigFileName,
+                                     StringRef OrigBoundArch, bool AtTopLevel,
+                                     bool MultipleArchs,
+                                     StringRef OffloadingPrefix) const;
+
 public:
   /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and
   /// return the grouped values as integers. Numbers which are not
Index: clang/include/clang/Driver/Compilation.h
===================================================================
--- clang/include/clang/Driver/Compilation.h
+++ clang/include/clang/Driver/Compilation.h
@@ -129,6 +129,10 @@
   /// Whether to keep temporary files regardless of -save-temps.
   bool ForceKeepTempFiles = false;
 
+  StringRef TimeTracePath;
+
+  llvm::SmallDenseMap<const JobAction *, const char *, 4> TimeTraceFiles;
+
 public:
   Compilation(const Driver &D, const ToolChain &DefaultToolChain,
               llvm::opt::InputArgList *Args,
@@ -269,6 +273,21 @@
     return Name;
   }
 
+  void setTimeTraceFileForJob(const JobAction *JA,
+                              const char *TimeTraceFileName) {
+    TimeTraceFiles[JA] = TimeTraceFileName;
+  }
+
+  const char *getTimeTraceFileForJob(const JobAction *JA) const {
+    return TimeTraceFiles.lookup(JA);
+  }
+
+  void setTimeTracePath(llvm::StringRef _TimeTracePath) {
+    TimeTracePath = _TimeTracePath;
+  }
+
+  llvm::StringRef getTimeTracePath() const { return TimeTracePath; }
+
   /// CleanupFile - Delete a given file.
   ///
   /// \param IssueErrors - Report failures as errors.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to