vsk created this revision.
vsk added a reviewer: davidxl.
vsk added a subscriber: cfe-commits.

**Summary**

Using memory-mapped profile counters makes it possible to take snapshots of a 
running process's profiling information without changing the program. This is 
useful if the process exits abnormally, or if profiling data needs to be 
collected periodically.

Add the clang support required to create instrumented programs which memory-map 
their counters directly onto a raw profile.

**More details**

This patch teaches clang to page-align the __llvm_prf_counts section (just on 
Darwin, initially). Because clang only knows the host system's page size -- not 
the target system's -- this is a best-effort attempt. If the instrumented 
program detects that the counters section has the wrong alignment, it will 
disable the memory-mapped counters feature.

I can add support for other platforms and linkers in follow-up patches.

Depends on: http://reviews.llvm.org/D19293 (llvm)

http://reviews.llvm.org/D19295

Files:
  include/clang/Driver/ToolChain.h
  lib/Driver/ToolChain.cpp
  lib/Driver/ToolChains.cpp
  lib/Driver/ToolChains.h
  lib/Driver/Tools.cpp
  test/Driver/instrprof-ld.c

Index: test/Driver/instrprof-ld.c
===================================================================
--- test/Driver/instrprof-ld.c
+++ test/Driver/instrprof-ld.c
@@ -73,38 +73,43 @@
 //
 // CHECK-DARWIN-X86-64: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
 // CHECK-DARWIN-X86-64: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.profile_osx.a"
+// CHECK-DARWIN-X86-64: "-sectalign" "__DATA" "__llvm_prf_cnts" "0x{{[0-9a-f]+}}"
 //
 // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
 // RUN:     -target x86_64-apple-darwin14 -fprofile-instr-generate -nostdlib \
 // RUN:     -resource-dir=%S/Inputs/resource_dir \
 // RUN:   | FileCheck --check-prefix=CHECK-DARWIN-NOSTDLIB-X86-64 %s
 //
 // CHECK-DARWIN-NOSTDLIB-X86-64: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
 // CHECK-DARWIN-NOSTDLIB-X86-64: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.profile_osx.a"
+// CHECK-DARWIN-NOSTDLIB-X86-64: "-sectalign" "__DATA" "__llvm_prf_cnts" "0x{{[0-9a-f]+}}"
 //
 // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
 // RUN:     -target arm64-apple-ios -fprofile-instr-generate \
 // RUN:     -resource-dir=%S/Inputs/resource_dir \
 // RUN:   | FileCheck --check-prefix=CHECK-DARWIN-ARM64 %s
 //
 // CHECK-DARWIN-ARM64: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
 // CHECK-DARWIN-ARM64: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.profile_ios.a"
+// CHECK-DARWIN-ARM64-X86-64: "-sectalign" "__DATA" "__llvm_prf_cnts" "0x{{[0-9a-f]+}}"
 //
 // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
 // RUN:     -target armv7-apple-darwin -mtvos-version-min=8.3 -fprofile-instr-generate \
 // RUN:     -resource-dir=%S/Inputs/resource_dir \
 // RUN:   | FileCheck --check-prefix=CHECK-TVOS-ARMV7 %s
 //
 // CHECK-TVOS-ARMV7: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
 // CHECK-TVOS-ARMV7: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.profile_tvos.a"
+// CHECK-TVOS-ARMV7: "-sectalign" "__DATA" "__llvm_prf_cnts" "0x{{[0-9a-f]+}}"
 //
 // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
 // RUN:     -target armv7s-apple-darwin10 -mwatchos-version-min=2.0 -arch armv7k -fprofile-instr-generate \
 // RUN:     -resource-dir=%S/Inputs/resource_dir \
 // RUN:   | FileCheck --check-prefix=CHECK-WATCHOS-ARMV7 %s
 //
 // CHECK-WATCHOS-ARMV7: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
 // CHECK-WATCHOS-ARMV7: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.profile_watchos.a"
+// CHECK-WATCHOS-ARMV7: "-sectalign" "__DATA" "__llvm_prf_cnts" "0x{{[0-9a-f]+}}"
 //
 // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
 // RUN:     -target i386-pc-win32 -fprofile-instr-generate \
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -7583,7 +7583,7 @@
   if (Args.hasArg(options::OPT_fnested_functions))
     CmdArgs.push_back("-allow_stack_execute");
 
-  getMachOToolChain().addProfileRTLibs(Args, CmdArgs);
+  getMachOToolChain().addProfileRTOpts(Args, CmdArgs);
 
   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
     if (getToolChain().getDriver().CCCIsCXX())
@@ -7779,7 +7779,7 @@
   }
   CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
 
-  getToolChain().addProfileRTLibs(Args, CmdArgs);
+  getToolChain().addProfileRTOpts(Args, CmdArgs);
 
   const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
   C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
@@ -8384,7 +8384,7 @@
     CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
   }
 
-  ToolChain.addProfileRTLibs(Args, CmdArgs);
+  ToolChain.addProfileRTOpts(Args, CmdArgs);
 
   const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
   C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
@@ -8677,7 +8677,7 @@
     CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
   }
 
-  getToolChain().addProfileRTLibs(Args, CmdArgs);
+  getToolChain().addProfileRTOpts(Args, CmdArgs);
 
   const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
   C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
@@ -9217,7 +9217,7 @@
   bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
   AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
   // The profile runtime also needs access to system libraries.
-  getToolChain().addProfileRTLibs(Args, CmdArgs);
+  getToolChain().addProfileRTOpts(Args, CmdArgs);
 
   if (D.CCCIsCXX() &&
       !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
@@ -9526,7 +9526,7 @@
 
   AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
 
-  getToolChain().addProfileRTLibs(Args, CmdArgs);
+  getToolChain().addProfileRTOpts(Args, CmdArgs);
 
   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
     if (D.CCCIsCXX()) {
@@ -9695,7 +9695,7 @@
     CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
   }
 
-  getToolChain().addProfileRTLibs(Args, CmdArgs);
+  getToolChain().addProfileRTOpts(Args, CmdArgs);
 
   const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
   C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
@@ -9865,7 +9865,7 @@
     A.renderAsInput(Args, CmdArgs);
   }
 
-  TC.addProfileRTLibs(Args, CmdArgs);
+  TC.addProfileRTOpts(Args, CmdArgs);
 
   // We need to special case some linker paths.  In the case of lld, we need to
   // translate 'lld' into 'lld-link', and in the case of the regular msvc
Index: lib/Driver/ToolChains.h
===================================================================
--- lib/Driver/ToolChains.h
+++ lib/Driver/ToolChains.h
@@ -289,7 +289,7 @@
 
   /// Add any profiling runtime libraries that are needed. This is essentially a
   /// MachO specific version of addProfileRT in Tools.cpp.
-  void addProfileRTLibs(const llvm::opt::ArgList &Args,
+  void addProfileRTOpts(const llvm::opt::ArgList &Args,
                         llvm::opt::ArgStringList &CmdArgs) const override {
     // There aren't any profiling libs for embedded targets currently.
   }
@@ -403,7 +403,7 @@
             !isTargetWatchOS());
   }
 
-  void addProfileRTLibs(const llvm::opt::ArgList &Args,
+  void addProfileRTOpts(const llvm::opt::ArgList &Args,
                         llvm::opt::ArgStringList &CmdArgs) const override;
 
 protected:
@@ -808,7 +808,7 @@
                           llvm::opt::ArgStringList &CC1Args) const override;
   bool isPIEDefault() const override;
   SanitizerMask getSupportedSanitizers() const override;
-  void addProfileRTLibs(const llvm::opt::ArgList &Args,
+  void addProfileRTOpts(const llvm::opt::ArgList &Args,
                         llvm::opt::ArgStringList &CmdArgs) const override;
   virtual std::string computeSysRoot() const;
 
Index: lib/Driver/ToolChains.cpp
===================================================================
--- lib/Driver/ToolChains.cpp
+++ lib/Driver/ToolChains.cpp
@@ -30,6 +30,7 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
 #include "llvm/Support/Program.h"
 #include "llvm/Support/TargetParser.h"
 #include "llvm/Support/raw_ostream.h"
@@ -349,13 +350,25 @@
   llvm_unreachable("Unsupported platform");
 }
 
-void Darwin::addProfileRTLibs(const ArgList &Args,
+void Darwin::addProfileRTOpts(const ArgList &Args,
                               ArgStringList &CmdArgs) const {
   if (!needsProfileRT(Args)) return;
 
   AddLinkRuntimeLib(Args, CmdArgs, (Twine("libclang_rt.profile_") +
        getOSLibraryNameSuffix() + ".a").str(),
                     /*AlwaysLink*/ true);
+
+  const char *PageSizeStr = Args.MakeArgString(
+      "0x" + llvm::utohexstr(llvm::sys::Process::getPageSize()));
+  auto AlignSection = [&](StringRef SectionName) {
+    CmdArgs.push_back("-sectalign");
+    CmdArgs.push_back("__DATA");
+    CmdArgs.push_back(SectionName.data());
+    CmdArgs.push_back(PageSizeStr);
+  };
+
+  // Try to page-align the counter section so that it can be mmap'd to disk.
+  AlignSection(llvm::getInstrProfCountersSectionName(/*AddSegment*/ false));
 }
 
 void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args,
@@ -4158,16 +4171,16 @@
   return Res;
 }
 
-void Linux::addProfileRTLibs(const llvm::opt::ArgList &Args,
+void Linux::addProfileRTOpts(const llvm::opt::ArgList &Args,
                              llvm::opt::ArgStringList &CmdArgs) const {
   if (!needsProfileRT(Args)) return;
 
   // Add linker option -u__llvm_runtime_variable to cause runtime
   // initialization module to be linked in.
   if (!Args.hasArg(options::OPT_coverage))
     CmdArgs.push_back(Args.MakeArgString(
         Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
-  ToolChain::addProfileRTLibs(Args, CmdArgs);
+  ToolChain::addProfileRTOpts(Args, CmdArgs);
 }
 
 /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly.
Index: lib/Driver/ToolChain.cpp
===================================================================
--- lib/Driver/ToolChain.cpp
+++ lib/Driver/ToolChain.cpp
@@ -518,7 +518,7 @@
 
 void ToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {}
 
-void ToolChain::addProfileRTLibs(const llvm::opt::ArgList &Args,
+void ToolChain::addProfileRTOpts(const llvm::opt::ArgList &Args,
                                  llvm::opt::ArgStringList &CmdArgs) const {
   if (!needsProfileRT(Args)) return;
 
Index: include/clang/Driver/ToolChain.h
===================================================================
--- include/clang/Driver/ToolChain.h
+++ include/clang/Driver/ToolChain.h
@@ -408,9 +408,10 @@
   /// This checks for presence of the -Ofast, -ffast-math or -funsafe-math flags.
   virtual bool AddFastMathRuntimeIfAvailable(
       const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const;
-  /// addProfileRTLibs - When -fprofile-instr-profile is specified, try to pass
+
+  /// addProfileRTOpts - When -fprofile-instr-profile is specified, try to pass
   /// a suitable profile runtime library to the linker.
-  virtual void addProfileRTLibs(const llvm::opt::ArgList &Args,
+  virtual void addProfileRTOpts(const llvm::opt::ArgList &Args,
                                 llvm::opt::ArgStringList &CmdArgs) const;
 
   /// \brief Add arguments to use system-specific CUDA includes.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to