sepavloff updated this revision to Diff 261621.
sepavloff added a comment.

Updated patch

- added variant of the option without file, it is used to print statistics on 
stdout.
- Updated file locking mechanism.
- Updated test and documentation accordingly.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D78903/new/

https://reviews.llvm.org/D78903

Files:
  clang/docs/UsersManual.rst
  clang/include/clang/Driver/Job.h
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/Driver.cpp
  clang/lib/Driver/Job.cpp
  clang/test/Driver/report-stat.c

Index: clang/test/Driver/report-stat.c
===================================================================
--- /dev/null
+++ clang/test/Driver/report-stat.c
@@ -0,0 +1,6 @@
+// RUN: %clang -c -fproc-stat-report %s | FileCheck %s
+// CHECK: clang{{.*}}: output={{.*}}.o, total={{[0-9.]+}} ms, user={{[0-9.]+}} ms, mem={{[0-9]+}} Kb
+
+// RUN: %clang -c -fproc-stat-report=%t %s
+// RUN: cat %t | FileCheck --check-prefix=CSV %s
+// CSV: clang{{.*}},"{{.*}}.o",{{[0-9]+}},{{[0-9]+}},{{[0-9]+}}
Index: clang/lib/Driver/Job.cpp
===================================================================
--- clang/lib/Driver/Job.cpp
+++ clang/lib/Driver/Job.cpp
@@ -370,8 +370,8 @@
 
   auto Args = llvm::toStringRefArray(Argv.data());
   return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects,
-                                   /*secondsToWait*/ 0,
-                                   /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
+      /*secondsToWait*/ 0, /*memoryLimit*/ 0, ErrMsg, ExecutionFailed,
+      &ProcStat);
 }
 
 CC1Command::CC1Command(const Action &Source, const Tool &Creator,
Index: clang/lib/Driver/Driver.cpp
===================================================================
--- clang/lib/Driver/Driver.cpp
+++ clang/lib/Driver/Driver.cpp
@@ -80,6 +80,7 @@
 #include "llvm/Support/TargetRegistry.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/Support/raw_ostream.h"
+#include <iostream>
 #include <map>
 #include <memory>
 #include <utility>
@@ -3757,11 +3758,70 @@
                        /*TargetDeviceOffloadKind*/ Action::OFK_None);
   }
 
-  // If we have more than one job, then disable integrated-cc1 for now.
-  if (C.getJobs().size() > 1)
+  StringRef StatReportFile;
+  bool PrintProcessStat = false;
+  if (const Arg *A = C.getArgs().getLastArg(options::OPT_fproc_stat_report_EQ))
+    StatReportFile = A->getValue();
+  if (C.getArgs().hasArg(options::OPT_fproc_stat_report))
+    PrintProcessStat = true;
+
+  // If we have more than one job, then disable integrated-cc1 for now. Do this
+  // also when we need to report process execution statistics.
+  if (C.getJobs().size() > 1 || !StatReportFile.empty() || PrintProcessStat)
     for (auto &J : C.getJobs())
       J.InProcess = false;
 
+  if (!StatReportFile.empty() || PrintProcessStat) {
+    C.setPostCallback([=](const Command &Cmd, int Res) {
+      Optional<llvm::sys::ProcessStatistics> ProcStat
+          = Cmd.getProcessStatistics();
+      if (ProcStat) {
+        if (PrintProcessStat) {
+          using namespace llvm;
+          // Human readable output.
+          outs() << sys::path::filename(Cmd.getExecutable()) << ": "
+                 << "output=";
+          if (Cmd.getOutputFilenames().empty())
+            outs() << "\"\"";
+          else
+            outs() << Cmd.getOutputFilenames().front();
+          outs() << ", total="
+                 << format("%.3f", ProcStat->TotalTime.count() / 1000.) << " ms"
+                 << ", user="
+                 << format("%.3f", ProcStat->UserTime.count() / 1000.) << " ms"
+                 << ", mem=" << ProcStat->PeakMemory << " Kb\n";
+        }
+        if (!StatReportFile.empty()) {
+          // CSV format.
+          std::string Buffer;
+          llvm::raw_string_ostream Out(Buffer);
+          Out << llvm::sys::path::filename(Cmd.getExecutable()) << ',';
+          if (Cmd.getOutputFilenames().empty())
+            Out << "\"\"";
+          else
+            Command::printArg(Out, Cmd.getOutputFilenames().front(), true);
+          Out << ','
+              << ProcStat->TotalTime.count() << ','
+              << ProcStat->UserTime.count() << ','
+              << ProcStat->PeakMemory << '\n';
+          Out.flush();
+          std::error_code EC;
+          llvm::raw_fd_ostream OS(StatReportFile, EC, llvm::sys::fs::OF_Append);
+          if (!EC) {
+            if (auto L = llvm::sys::fs::tryLock(OS.getFD()))
+              OS << Buffer;
+            else
+              handleAllErrors(std::move(L.takeError()),
+                              [&](llvm::ErrorInfoBase &EIB) {
+                llvm::errs() << "ERROR: Cannot lock file " << StatReportFile
+                             << "n";
+              });
+          }
+        }
+      }
+    });
+  }
+
   // If the user passed -Qunused-arguments or there were errors, don't warn
   // about any unused arguments.
   if (Diags.hasErrorOccurred() ||
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1909,6 +1909,10 @@
 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]>;
+def fproc_stat_report : Joined<["-"], "fproc-stat-report">, Group<f_Group>,
+  Flags<[DriverOption]>, HelpText<"Print subprocess statistics">;
+def fproc_stat_report_EQ : Joined<["-"], "fproc-stat-report=">, Group<f_Group>,
+  Flags<[DriverOption]>, HelpText<"Save subprocess statistics to the given file">;
 def ftlsmodel_EQ : Joined<["-"], "ftls-model=">, Group<f_Group>, Flags<[CC1Option]>;
 def ftrapv : Flag<["-"], "ftrapv">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Trap on integer overflow">;
Index: clang/include/clang/Driver/Job.h
===================================================================
--- clang/include/clang/Driver/Job.h
+++ clang/include/clang/Driver/Job.h
@@ -16,6 +16,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/iterator.h"
 #include "llvm/Option/Option.h"
+#include "llvm/Support/Program.h"
 #include <memory>
 #include <string>
 #include <utility>
@@ -73,6 +74,9 @@
   /// See Command::setEnvironment
   std::vector<const char *> Environment;
 
+  /// Information on executable run provided by OS.
+  mutable llvm::sys::ProcessStatistics ProcStat;
+
   /// When a response file is needed, we try to put most arguments in an
   /// exclusive file, while others remains as regular command line arguments.
   /// This functions fills a vector with the regular command line arguments,
@@ -139,6 +143,12 @@
     return OutputFilenames;
   }
 
+  Optional<llvm::sys::ProcessStatistics> getProcessStatistics() const {
+    if (ProcStat.isSet())
+      return ProcStat;
+    return None;
+  }
+
   /// Print a command argument, and optionally quote it.
   static void printArg(llvm::raw_ostream &OS, StringRef Arg, bool Quote);
 
Index: clang/docs/UsersManual.rst
===================================================================
--- clang/docs/UsersManual.rst
+++ clang/docs/UsersManual.rst
@@ -747,6 +747,51 @@
    translated from debug annotations. That translation can be lossy,
    which results in some remarks having no location information.
 
+Options to Emit Resource Consumption Reports
+--------------------------------------------
+
+These are options that report execution time and consumed memory of different
+compilations steps.
+
+.. option:: -fproc-stat-report=
+
+  This option requests driver to print used memory and execution time of each
+  compilation step. The ``clang`` driver during execution calls different tools,
+  like compiler, assembler, linker etc. With this option the driver reports
+  total execution time, the execution time spent in user mode and peak memory
+  usage of each the called tool. Value of the option specifies where the report
+  is sent to. If it specifies a regular file, the data are saved to this file in
+  CSV format:
+
+.. code-block:: console
+
+   $ clang -fproc-stat-report=abc foo.c
+   $ cat abc
+   clang-11,"/tmp/foo-123456.o",92000,84000,87536
+   ld,"a.out",900,8000,53568
+
+  The data on each row represent:
+  
+  * file name of the tool executable,
+  * output file name in quotes,
+  * total execution time in microseconds,
+  * execution time in user mode in microseconds,
+  * peak memory usage in Kb.
+  
+  It is possible to specify this option without any value. In this case statistics
+  is printed on standard output in human readable format:
+  
+.. code-block:: console
+
+  $ clang -fproc-stat-report foo.c
+  clang-11: output=/tmp/foo-855a8e.o, total=68.000 ms, user=60.000 ms, mem=86920 Kb
+  ld: output=a.out, total=8.000 ms, user=4.000 ms, mem=52320 Kb
+  
+  The report file specified in the option is locked for write, so this option
+  can be used to collect statistics in parallel builds. The report file is not
+  cleared, new data is appended to it, thus making posible to accumulate build
+  statistics.
+
 Other Options
 -------------
 Clang options that don't fit neatly into other categories.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to