On 2017-10-04 11:56:47 +0300, Ants Aasma wrote:
> On Wed, Oct 4, 2017 at 9:48 AM, Andres Freund <and...@anarazel.de> wrote:
> > Here's an updated version of the patchset.  There's some substantial
> > changes here, but it's still very obviously very far from committable as
> > a whole. There's some helper commmits that are simple and independent
> > enough to be committable earlier on.
>
> Looks pretty impressive already.

Thanks!


> I wanted to take it for a spin, but got errors about the following
> symbols being missing:
>
> LLVMOrcUnregisterPerf
> LLVMOrcRegisterGDB
> LLVMOrcRegisterPerf
> LLVMOrcGetSymbolAddressIn
> LLVMLinkModules2Needed
>
> As far as I can tell these are not in mainline LLVM. Is there a branch
> or patchset of LLVM available somewhere that I need to use this?

Oops, I'd forgotten about the modifications. Sorry. I've attached them
here.  The GDB and Perf stuff should now be an optional dependency,
too.  The required changes are fairly small, so they hopefully shouldn't
be too hard to upstream.

Please check the git tree for a rebased version of the pg patches, with
a bunch bugfixes (oops, some last minute "cleanups") and performance
fixes.

Here's some numbers for a a TPC-H scale 5 run. Obviously the Q01 numbers
are pretty nice in partcular. But it's also visible that the shorter
query can loose, which is largely due to the JIT overhead - that can be
ameliorated to some degree, but JITing obviously isn't always going to
be a win.

It's pretty impressive that in q01, even after all of this, expression
evaluation *still* is 35% of the total time (25% in the aggregate
transition function). That's partially just because the query does
primarily aggregation, but also because the generated code can stand a
good chunk of improvements.

master q01 min: 14146.498     dev min: 11479.05 [diff -23.24]     dev-jit min: 
8659.961 [diff -63.36]     dev-jit-deform min: 7279.395 [diff -94.34]     
dev-jit-deform-inline min: 6997.956 [diff -102.15]
master q02 min: 1234.229     dev min: 1208.102 [diff -2.16]     dev-jit min: 
1292.983 [diff +4.54]     dev-jit-deform min: 1580.505 [diff +21.91]     
dev-jit-deform-inline min: 1809.046 [diff +31.77]
master q03 min: 6220.814     dev min: 5424.107 [diff -14.69]     dev-jit min: 
5175.125 [diff -20.21]     dev-jit-deform min: 4257.368 [diff -46.12]     
dev-jit-deform-inline min: 4218.115 [diff -47.48]
master q04 min: 947.476     dev min: 970.608 [diff +2.38]     dev-jit min: 
969.944 [diff +2.32]     dev-jit-deform min: 999.006 [diff +5.16]     
dev-jit-deform-inline min: 1033.78 [diff +8.35]
master q05 min: 4729.9     dev min: 4059.665 [diff -16.51]     dev-jit min: 
4182.941 [diff -13.08]     dev-jit-deform min: 4147.493 [diff -14.04]     
dev-jit-deform-inline min: 4284.473 [diff -10.40]
master q06 min: 1603.708     dev min: 1592.107 [diff -0.73]     dev-jit min: 
1556.216 [diff -3.05]     dev-jit-deform min: 1516.078 [diff -5.78]     
dev-jit-deform-inline min: 1579.839 [diff -1.51]
master q07 min: 4549.738     dev min: 4331.565 [diff -5.04]     dev-jit min: 
4475.654 [diff -1.66]     dev-jit-deform min: 4645.773 [diff +2.07]     
dev-jit-deform-inline min: 4885.781 [diff +6.88]
master q08 min: 1394.428     dev min: 1350.363 [diff -3.26]     dev-jit min: 
1434.366 [diff +2.78]     dev-jit-deform min: 1716.65 [diff +18.77]     
dev-jit-deform-inline min: 1938.152 [diff +28.05]
master q09 min: 5958.198     dev min: 5700.329 [diff -4.52]     dev-jit min: 
5491.683 [diff -8.49]     dev-jit-deform min: 5582.431 [diff -6.73]     
dev-jit-deform-inline min: 5797.475 [diff -2.77]
master q10 min: 5228.69     dev min: 4475.154 [diff -16.84]     dev-jit min: 
4269.365 [diff -22.47]     dev-jit-deform min: 3767.888 [diff -38.77]     
dev-jit-deform-inline min: 3962.084 [diff -31.97]
master q11 min: 281.201     dev min: 280.132 [diff -0.38]     dev-jit min: 
351.85 [diff +20.08]     dev-jit-deform min: 455.885 [diff +38.32]     
dev-jit-deform-inline min: 532.093 [diff +47.15]
master q12 min: 4289.268     dev min: 4082.359 [diff -5.07]     dev-jit min: 
4007.199 [diff -7.04]     dev-jit-deform min: 3752.396 [diff -14.31]     
dev-jit-deform-inline min: 3916.653 [diff -9.51]
master q13 min: 7110.545     dev min: 6898.576 [diff -3.07]     dev-jit min: 
6579.554 [diff -8.07]     dev-jit-deform min: 6304.15 [diff -12.79]     
dev-jit-deform-inline min: 6135.952 [diff -15.88]
master q14 min: 678.024     dev min: 650.943 [diff -4.16]     dev-jit min: 
682.387 [diff +0.64]     dev-jit-deform min: 746.354 [diff +9.16]     
dev-jit-deform-inline min: 878.437 [diff +22.81]
master q15 min: 1641.897     dev min: 1650.57 [diff +0.53]     dev-jit min: 
1661.591 [diff +1.19]     dev-jit-deform min: 1821.02 [diff +9.84]     
dev-jit-deform-inline min: 1863.304 [diff +11.88]
master q16 min: 1890.246     dev min: 1819.423 [diff -3.89]     dev-jit min: 
1838.079 [diff -2.84]     dev-jit-deform min: 1962.274 [diff +3.67]     
dev-jit-deform-inline min: 2096.154 [diff +9.82]
master q17 min: 502.605     dev min: 462.881 [diff -8.58]     dev-jit min: 
495.648 [diff -1.40]     dev-jit-deform min: 537.666 [diff +6.52]     
dev-jit-deform-inline min: 613.144 [diff +18.03]
master q18 min: 12863.972     dev min: 11257.57 [diff -14.27]     dev-jit min: 
10847.61 [diff -18.59]     dev-jit-deform min: 10119.769 [diff -27.12]     
dev-jit-deform-inline min: 10103.051 [diff -27.33]
master q19 min: 281.991     dev min: 264.191 [diff -6.74]     dev-jit min: 
331.102 [diff +14.83]     dev-jit-deform min: 373.759 [diff +24.55]     
dev-jit-deform-inline min: 531.07 [diff +46.90]
master q20 min: 541.154     dev min: 511.372 [diff -5.82]     dev-jit min: 
565.378 [diff +4.28]     dev-jit-deform min: 662.926 [diff +18.37]     
dev-jit-deform-inline min: 805.835 [diff +32.85]
master q22 min: 678.266     dev min: 656.643 [diff -3.29]     dev-jit min: 
676.886 [diff -0.20]     dev-jit-deform min: 735.058 [diff +7.73]     
dev-jit-deform-inline min: 943.013 [diff +28.07]

master total min: 76772.848     dev min: 69125.71 [diff -11.06]     dev-jit 
min: 65545.522 [diff -17.13]     dev-jit-deform min: 62963.844 [diff -21.93]    
 dev-jit-deform-inline min: 64925.407 [diff -18.25]


Greetings,

Andres Freund
>From f636e4caf62ed2a29851b9cca8bb664df73c7bb9 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Wed, 4 Oct 2017 15:36:51 -0700
Subject: [PATCH 1/6] [ORC] Add findSymbolIn() wrapper to C bindings.

---
 include/llvm-c/OrcBindings.h                |  5 +++++
 lib/ExecutionEngine/Orc/OrcCBindings.cpp    |  8 ++++++++
 lib/ExecutionEngine/Orc/OrcCBindingsStack.h | 22 ++++++++++++++++++++++
 3 files changed, 35 insertions(+)

diff --git a/include/llvm-c/OrcBindings.h b/include/llvm-c/OrcBindings.h
index abb3ac6a7f0..4ff1f47e87d 100644
--- a/include/llvm-c/OrcBindings.h
+++ b/include/llvm-c/OrcBindings.h
@@ -170,6 +170,11 @@ LLVMOrcErrorCode LLVMOrcGetSymbolAddress(LLVMOrcJITStackRef JITStack,
                                          LLVMOrcTargetAddress *RetAddr,
                                          const char *SymbolName);
 
+LLVMOrcErrorCode LLVMOrcGetSymbolAddressIn(LLVMOrcJITStackRef JITStack,
+                                           LLVMOrcTargetAddress *RetAddr,
+                                           LLVMOrcModuleHandle H,
+                                           const char *SymbolName);
+
 /**
  * Dispose of an ORC JIT stack.
  */
diff --git a/lib/ExecutionEngine/Orc/OrcCBindings.cpp b/lib/ExecutionEngine/Orc/OrcCBindings.cpp
index f945acaf95e..9b9c1512402 100644
--- a/lib/ExecutionEngine/Orc/OrcCBindings.cpp
+++ b/lib/ExecutionEngine/Orc/OrcCBindings.cpp
@@ -120,6 +120,14 @@ LLVMOrcErrorCode LLVMOrcGetSymbolAddress(LLVMOrcJITStackRef JITStack,
   return J.findSymbolAddress(*RetAddr, SymbolName, true);
 }
 
+LLVMOrcErrorCode LLVMOrcGetSymbolAddressIn(LLVMOrcJITStackRef JITStack,
+                                           LLVMOrcTargetAddress *RetAddr,
+                                           LLVMOrcModuleHandle H,
+                                           const char *SymbolName) {
+  OrcCBindingsStack &J = *unwrap(JITStack);
+  return J.findSymbolAddressIn(*RetAddr, H, SymbolName, true);
+}
+
 LLVMOrcErrorCode LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack) {
   auto *J = unwrap(JITStack);
   auto Err = J->shutdown();
diff --git a/lib/ExecutionEngine/Orc/OrcCBindingsStack.h b/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
index 405970e063d..6eaac01d52f 100644
--- a/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
+++ b/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
@@ -354,6 +354,28 @@ public:
     return LLVMOrcErrSuccess;
   }
 
+
+  LLVMOrcErrorCode findSymbolAddressIn(JITTargetAddress &RetAddr,
+                                       ModuleHandleT H,
+                                       const std::string &Name,
+                                       bool ExportedSymbolsOnly) {
+    RetAddr = 0;
+    if (auto Sym = findSymbolIn(H, Name, ExportedSymbolsOnly)) {
+      // Successful lookup, non-null symbol:
+      if (auto AddrOrErr = Sym.getAddress()) {
+        RetAddr = *AddrOrErr;
+        return LLVMOrcErrSuccess;
+      } else
+        return mapError(AddrOrErr.takeError());
+    } else if (auto Err = Sym.takeError()) {
+      // Lookup failure - report error.
+      return mapError(std::move(Err));
+    }
+    // Otherwise we had a successful lookup but got a null result. We already
+    // set RetAddr to '0' above, so just return success.
+    return LLVMOrcErrSuccess;
+  }
+
   const std::string &getErrorMessage() const { return ErrMsg; }
 
 private:
-- 
2.14.1.536.g6867272d5b.dirty

>From 98716f882cf08f521dc8e57693d224006e3f3b68 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Wed, 4 Oct 2017 23:38:46 -0700
Subject: [PATCH 2/6] [C-API] WIP: Add LLVMGetHostCPUName().

---
 include/llvm-c/TargetMachine.h | 4 ++++
 lib/Target/TargetMachineC.cpp  | 8 ++++++++
 2 files changed, 12 insertions(+)

diff --git a/include/llvm-c/TargetMachine.h b/include/llvm-c/TargetMachine.h
index f4f7f7698c4..44f6b8babd1 100644
--- a/include/llvm-c/TargetMachine.h
+++ b/include/llvm-c/TargetMachine.h
@@ -137,6 +137,10 @@ LLVMBool LLVMTargetMachineEmitToMemoryBuffer(LLVMTargetMachineRef T, LLVMModuleR
   disposed with LLVMDisposeMessage. */
 char* LLVMGetDefaultTargetTriple(void);
 
+/** Get the host CPU as a string. The result needs to be disposed with
+  LLVMDisposeMessage. */
+char* LLVMGetHostCPUName(void);
+
 /** Adds the target-specific analysis passes to the pass manager. */
 void LLVMAddAnalysisPasses(LLVMTargetMachineRef T, LLVMPassManagerRef PM);
 
diff --git a/lib/Target/TargetMachineC.cpp b/lib/Target/TargetMachineC.cpp
index 210375ff828..63d0bbf74bc 100644
--- a/lib/Target/TargetMachineC.cpp
+++ b/lib/Target/TargetMachineC.cpp
@@ -238,6 +238,14 @@ char *LLVMGetDefaultTargetTriple(void) {
   return strdup(sys::getDefaultTargetTriple().c_str());
 }
 
+/** Get the host CPU as a string. The result needs to be disposed with
+  LLVMDisposeMessage. */
+char* LLVMGetHostCPUName(void)
+{
+  /* XXX: verify it's null terminated */
+  return strdup(sys::getHostCPUName().data());
+}
+
 void LLVMAddAnalysisPasses(LLVMTargetMachineRef T, LLVMPassManagerRef PM) {
   unwrap(PM)->add(
       createTargetTransformInfoWrapperPass(unwrap(T)->getTargetIRAnalysis()));
-- 
2.14.1.536.g6867272d5b.dirty

>From c0cb3ec7472d4667226d0183382e165a7a6d2c30 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Wed, 4 Oct 2017 12:55:38 -0700
Subject: [PATCH 3/6] [C API] Add LLVMLinkModules2Needed().

---
 include/llvm-c/Linker.h    | 1 +
 lib/Linker/LinkModules.cpp | 6 ++++++
 2 files changed, 7 insertions(+)

diff --git a/include/llvm-c/Linker.h b/include/llvm-c/Linker.h
index d02c37f94c8..06af8193e57 100644
--- a/include/llvm-c/Linker.h
+++ b/include/llvm-c/Linker.h
@@ -33,6 +33,7 @@ typedef enum {
  * Use the diagnostic handler to get any diagnostic message.
 */
 LLVMBool LLVMLinkModules2(LLVMModuleRef Dest, LLVMModuleRef Src);
+LLVMBool LLVMLinkModules2Needed(LLVMModuleRef Dest, LLVMModuleRef Src);
 
 #ifdef __cplusplus
 }
diff --git a/lib/Linker/LinkModules.cpp b/lib/Linker/LinkModules.cpp
index 25f31a3401a..9a34c9ecce8 100644
--- a/lib/Linker/LinkModules.cpp
+++ b/lib/Linker/LinkModules.cpp
@@ -604,3 +604,9 @@ LLVMBool LLVMLinkModules2(LLVMModuleRef Dest, LLVMModuleRef Src) {
   std::unique_ptr<Module> M(unwrap(Src));
   return Linker::linkModules(*D, std::move(M));
 }
+
+LLVMBool LLVMLinkModules2Needed(LLVMModuleRef Dest, LLVMModuleRef Src) {
+  Module *D = unwrap(Dest);
+  std::unique_ptr<Module> M(unwrap(Src));
+  return Linker::linkModules(*D, std::move(M), Linker::Flags::LinkOnlyNeeded);
+}
-- 
2.14.1.536.g6867272d5b.dirty

>From 389e5cca8e5145c9378730479de4b42870a8b347 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Wed, 1 Feb 2017 21:18:54 -0800
Subject: [PATCH 4/6] [MCJIT] Call JIT notifiers only after code sections are
 ready.

Previously JIT notifiers were called before relocations were
performed (leading to ominious function call of "0"), and before
memory marked executable (confusing some profilers).

Move notifications to finalizeLoadedModules().
---
 lib/ExecutionEngine/MCJIT/MCJIT.cpp | 16 ++++++++++++++--
 lib/ExecutionEngine/MCJIT/MCJIT.h   |  2 ++
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/lib/ExecutionEngine/MCJIT/MCJIT.cpp
index 1164d60ffc1..2dd92164794 100644
--- a/lib/ExecutionEngine/MCJIT/MCJIT.cpp
+++ b/lib/ExecutionEngine/MCJIT/MCJIT.cpp
@@ -222,8 +222,10 @@ void MCJIT::generateCodeForModule(Module *M) {
   if (Dyld.hasError())
     report_fatal_error(Dyld.getErrorString());
 
-  NotifyObjectEmitted(*LoadedObject.get(), *L);
-
+  // Can't call notifiers yet as relocations have not yet been performed, and
+  // memory hasn't been marked executable.
+  PendingLoadedObjects.push_back(LoadedObject->get());
+  PendingLoadedObjectInfos.push_back(std::move(L));
   Buffers.push_back(std::move(ObjectToLoad));
   LoadedObjects.push_back(std::move(*LoadedObject));
 
@@ -243,6 +245,16 @@ void MCJIT::finalizeLoadedModules() {
 
   // Set page permissions.
   MemMgr->finalizeMemory();
+
+  // Notify listeners about loaded objects now that memory is marked executable
+  // and relocations have been performed.
+  for (size_t i = 0; i < PendingLoadedObjects.size(); i++) {
+    auto &Obj = PendingLoadedObjects[i];
+    auto &Info = PendingLoadedObjectInfos[i];
+    NotifyObjectEmitted(*Obj, *Info);
+  }
+  PendingLoadedObjects.clear();
+  PendingLoadedObjectInfos.clear();
 }
 
 // FIXME: Rename this.
diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.h b/lib/ExecutionEngine/MCJIT/MCJIT.h
index daf578f5daa..418578fc7a3 100644
--- a/lib/ExecutionEngine/MCJIT/MCJIT.h
+++ b/lib/ExecutionEngine/MCJIT/MCJIT.h
@@ -189,6 +189,8 @@ class MCJIT : public ExecutionEngine {
   SmallVector<std::unique_ptr<MemoryBuffer>, 2> Buffers;
 
   SmallVector<std::unique_ptr<object::ObjectFile>, 2> LoadedObjects;
+  SmallVector<object::ObjectFile*, 2> PendingLoadedObjects;
+  SmallVector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>, 2> PendingLoadedObjectInfos;
 
   // An optional ObjectCache to be notified of compiled objects and used to
   // perform lookup of pre-compiled code to avoid re-compilation.
-- 
2.14.1.536.g6867272d5b.dirty

>From 1db0527249415c5abbcf7425f05e04c7dc1713ef Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Wed, 1 Feb 2017 23:10:45 -0800
Subject: [PATCH 5/6] Add PerfJITEventListener for perf profiling support.

---
 CMakeLists.txt                                     |  13 +
 include/llvm/Config/config.h.cmake                 |   3 +
 include/llvm/Config/llvm-config.h.cmake            |   3 +
 include/llvm/ExecutionEngine/JITEventListener.h    |   9 +
 lib/ExecutionEngine/CMakeLists.txt                 |   4 +
 lib/ExecutionEngine/LLVMBuild.txt                  |   2 +-
 lib/ExecutionEngine/Orc/LLVMBuild.txt              |   2 +-
 lib/ExecutionEngine/PerfJITEvents/CMakeLists.txt   |   5 +
 .../{Orc => PerfJITEvents}/LLVMBuild.txt           |   8 +-
 .../PerfJITEvents/PerfJITEventListener.cpp         | 530 +++++++++++++++++++++
 tools/lli/CMakeLists.txt                           |   9 +
 tools/lli/lli.cpp                                  |   2 +
 12 files changed, 584 insertions(+), 6 deletions(-)
 create mode 100644 lib/ExecutionEngine/PerfJITEvents/CMakeLists.txt
 copy lib/ExecutionEngine/{Orc => PerfJITEvents}/LLVMBuild.txt (72%)
 create mode 100644 lib/ExecutionEngine/PerfJITEvents/PerfJITEventListener.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3e2e548df3f..dac3b817477 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -433,6 +433,16 @@ if( LLVM_USE_OPROFILE )
   endif( NOT CMAKE_SYSTEM_NAME MATCHES "Linux" )
 endif( LLVM_USE_OPROFILE )
 
+option(LLVM_USE_PERF
+  "Use perf JIT interface to inform perf about JIT code" OFF)
+
+# If enabled, verify we are on a platform that supports perf.
+if( LLVM_USE_PERF )
+  if( NOT CMAKE_SYSTEM_NAME MATCHES "Linux" )
+    message(FATAL_ERROR "perf support is available on Linux only.")
+  endif( NOT CMAKE_SYSTEM_NAME MATCHES "Linux" )
+endif( LLVM_USE_PERF )
+
 set(LLVM_USE_SANITIZER "" CACHE STRING
   "Define the sanitizer used to build binaries and tests.")
 
@@ -639,6 +649,9 @@ endif (LLVM_USE_INTEL_JITEVENTS)
 if (LLVM_USE_OPROFILE)
   set(LLVMOPTIONALCOMPONENTS ${LLVMOPTIONALCOMPONENTS} OProfileJIT)
 endif (LLVM_USE_OPROFILE)
+if (LLVM_USE_PERF)
+  set(LLVMOPTIONALCOMPONENTS PerfJITEvents)
+endif (LLVM_USE_PERF)
 
 message(STATUS "Constructing LLVMBuild project information")
 execute_process(
diff --git a/include/llvm/Config/config.h.cmake b/include/llvm/Config/config.h.cmake
index d67148f6aa3..59a504ca3cf 100644
--- a/include/llvm/Config/config.h.cmake
+++ b/include/llvm/Config/config.h.cmake
@@ -374,6 +374,9 @@
 /* Define if we have the oprofile JIT-support library */
 #cmakedefine01 LLVM_USE_OPROFILE
 
+/* Define if we have the perf JIT-support library */
+#cmakedefine01 LLVM_USE_PERF
+
 /* LLVM version information */
 #cmakedefine LLVM_VERSION_INFO "${LLVM_VERSION_INFO}"
 
diff --git a/include/llvm/Config/llvm-config.h.cmake b/include/llvm/Config/llvm-config.h.cmake
index 4b0c5946061..4003b4d7b15 100644
--- a/include/llvm/Config/llvm-config.h.cmake
+++ b/include/llvm/Config/llvm-config.h.cmake
@@ -62,6 +62,9 @@
 /* Define if we have the oprofile JIT-support library */
 #cmakedefine01 LLVM_USE_OPROFILE
 
+/* Define if we have the perf JIT-support library */
+#cmakedefine01 LLVM_USE_PERF
+
 /* Major version of the LLVM API */
 #define LLVM_VERSION_MAJOR ${LLVM_VERSION_MAJOR}
 
diff --git a/include/llvm/ExecutionEngine/JITEventListener.h b/include/llvm/ExecutionEngine/JITEventListener.h
index ff7840f00a4..ad89599f717 100644
--- a/include/llvm/ExecutionEngine/JITEventListener.h
+++ b/include/llvm/ExecutionEngine/JITEventListener.h
@@ -115,6 +115,15 @@ public:
   }
 #endif // USE_OPROFILE
 
+#if LLVM_USE_PERF
+  static JITEventListener *createPerfJITEventListener();
+#else
+  static JITEventListener *createPerfJITEventListener()
+  {
+    return nullptr;
+  }
+#endif // USE_PERF
+
 private:
   virtual void anchor();
 };
diff --git a/lib/ExecutionEngine/CMakeLists.txt b/lib/ExecutionEngine/CMakeLists.txt
index 84b34919e44..c0dea0550fb 100644
--- a/lib/ExecutionEngine/CMakeLists.txt
+++ b/lib/ExecutionEngine/CMakeLists.txt
@@ -30,3 +30,7 @@ endif( LLVM_USE_OPROFILE )
 if( LLVM_USE_INTEL_JITEVENTS )
   add_subdirectory(IntelJITEvents)
 endif( LLVM_USE_INTEL_JITEVENTS )
+
+if( LLVM_USE_PERF )
+  add_subdirectory(PerfJITEvents)
+endif( LLVM_USE_PERF )
diff --git a/lib/ExecutionEngine/LLVMBuild.txt b/lib/ExecutionEngine/LLVMBuild.txt
index 9d29a41f504..b6e1bda6a51 100644
--- a/lib/ExecutionEngine/LLVMBuild.txt
+++ b/lib/ExecutionEngine/LLVMBuild.txt
@@ -16,7 +16,7 @@
 ;===------------------------------------------------------------------------===;
 
 [common]
-subdirectories = Interpreter MCJIT RuntimeDyld IntelJITEvents OProfileJIT Orc
+subdirectories = Interpreter MCJIT RuntimeDyld IntelJITEvents OProfileJIT Orc PerfJITEvents
 
 [component_0]
 type = Library
diff --git a/lib/ExecutionEngine/Orc/LLVMBuild.txt b/lib/ExecutionEngine/Orc/LLVMBuild.txt
index 8f05172e77a..ef4ae64e823 100644
--- a/lib/ExecutionEngine/Orc/LLVMBuild.txt
+++ b/lib/ExecutionEngine/Orc/LLVMBuild.txt
@@ -19,4 +19,4 @@
 type = Library
 name = OrcJIT
 parent = ExecutionEngine
-required_libraries = Core ExecutionEngine Object RuntimeDyld Support TransformUtils
+required_libraries = Core ExecutionEngine Object RuntimeDyld Support TransformUtils PerfJITEvents
diff --git a/lib/ExecutionEngine/PerfJITEvents/CMakeLists.txt b/lib/ExecutionEngine/PerfJITEvents/CMakeLists.txt
new file mode 100644
index 00000000000..136cc429d02
--- /dev/null
+++ b/lib/ExecutionEngine/PerfJITEvents/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_llvm_library(LLVMPerfJITEvents
+  PerfJITEventListener.cpp
+  )
+
+add_dependencies(LLVMPerfJITEvents LLVMCodeGen)
diff --git a/lib/ExecutionEngine/Orc/LLVMBuild.txt b/lib/ExecutionEngine/PerfJITEvents/LLVMBuild.txt
similarity index 72%
copy from lib/ExecutionEngine/Orc/LLVMBuild.txt
copy to lib/ExecutionEngine/PerfJITEvents/LLVMBuild.txt
index 8f05172e77a..5175f9dd791 100644
--- a/lib/ExecutionEngine/Orc/LLVMBuild.txt
+++ b/lib/ExecutionEngine/PerfJITEvents/LLVMBuild.txt
@@ -1,4 +1,4 @@
-;===- ./lib/ExecutionEngine/MCJIT/LLVMBuild.txt ----------------*- Conf -*--===;
+;===- ./lib/ExecutionEngine/PerfJITEvents/LLVMBuild.txt ----------------*- Conf -*--===;
 ;
 ;                     The LLVM Compiler Infrastructure
 ;
@@ -16,7 +16,7 @@
 ;===------------------------------------------------------------------------===;
 
 [component_0]
-type = Library
-name = OrcJIT
+type = OptionalLibrary
+name = PerfJITEvents
 parent = ExecutionEngine
-required_libraries = Core ExecutionEngine Object RuntimeDyld Support TransformUtils
+required_libraries = CodeGen Core DebugInfoDWARF Support Object ExecutionEngine
diff --git a/lib/ExecutionEngine/PerfJITEvents/PerfJITEventListener.cpp b/lib/ExecutionEngine/PerfJITEvents/PerfJITEventListener.cpp
new file mode 100644
index 00000000000..d8b40e8b949
--- /dev/null
+++ b/lib/ExecutionEngine/PerfJITEvents/PerfJITEventListener.cpp
@@ -0,0 +1,530 @@
+//===-- PerfJITEventListener.cpp - Tell Linux's perf about JITted code ----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a JITEventListener object that tells perf JITted functions,
+// including source line information.
+//
+// Documentation for perf jit integration is available at:
+// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jitdump-specification.txt
+// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jit-interface.txt
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Config/config.h"
+
+#include <unistd.h> // for getpid(), sysconf()
+#include <syscall.h> // for gettid() */
+#include <time.h> // clock_gettime(), time(), localtime_r() */
+#include <sys/mman.h> // mmap() */
+#include <sys/types.h> // getpid(), open()
+#include <sys/stat.h> // open()
+#include <fcntl.h> // open()
+
+#include "llvm/ExecutionEngine/JITEventListener.h"
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/SymbolSize.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/MutexGuard.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind;
+
+namespace {
+
+// language identifier (XXX: should we generate something better from debug info?)
+#define JIT_LANG "llvm-IR"
+#define LLVM_PERF_JIT_MAGIC ((uint32_t) 'J' << 24 | (uint32_t) 'i' << 16 | (uint32_t) 'T' << 8 | (uint32_t) 'D')
+#define LLVM_PERF_JIT_VERSION 1
+
+/* bit 0: set if the jitdump file is using an architecture-specific timestamp clock source */
+#define JITDUMP_FLAGS_ARCH_TIMESTAMP  (1ULL << 0)
+
+struct LLVMPerfJitHeader;
+
+class PerfJITEventListener : public JITEventListener {
+public:
+  PerfJITEventListener();
+  ~PerfJITEventListener() {
+    if (MarkerAddr)
+      CloseMarker();
+  }
+
+  void NotifyObjectEmitted(const ObjectFile &Obj,
+                           const RuntimeDyld::LoadedObjectInfo &L) override;
+
+  void NotifyFreeingObject(const ObjectFile &Obj) override;
+
+private:
+
+  bool InitDebuggingDir();
+  bool OpenMarker();
+  void CloseMarker();
+  bool FillMachine(LLVMPerfJitHeader &hdr);
+
+  void NotifyCode(Expected<llvm::StringRef> &Symbol, uint64_t CodeAddr, uint64_t CodeSize);
+  void NotifyDebug(uint64_t CodeAddr, DILineInfoTable Lines);
+
+  // output data stream
+  std::unique_ptr<raw_fd_ostream> Dumpstream;
+
+  // output data stream, lifeliness managed via Dumpstream
+  int Fd;
+
+  // prevent concurrent dumps from messing up the output file
+  sys::Mutex Mutex;
+
+  // cache lookups
+  pid_t Pid;
+
+  // base directory for output data
+  std::string JitPath;
+
+  // perf mmap marker
+  void *MarkerAddr = NULL;
+
+  // perf support ready
+  bool SuccessfullyInitialized = false;
+};
+
+// The following are POD struct definitions from the perf jit specification
+
+enum LLVMPerfJitRecordType {
+  JIT_CODE_LOAD = 0,
+  JIT_CODE_MOVE = 1,
+  JIT_CODE_DEBUG_INFO = 2,
+  JIT_CODE_CLOSE = 3,
+  JIT_CODE_UNWINDING_INFO = 4,
+
+  JIT_CODE_MAX,
+};
+
+struct LLVMPerfJitHeader {
+  uint32_t Magic; /* characters "JiTD" */
+  uint32_t Version; /* header version */
+  uint32_t TotalSize; /* total size of header */
+  uint32_t ElfMach; /* elf mach target */
+  uint32_t Pad1; /* reserved */
+  uint32_t Pid;
+  uint64_t Timestamp; /* timestamp */
+  uint64_t Flags; /* flags */
+};
+
+/* record prefix (mandatory in each record) */
+struct LLVMPerfJitRecordPrefix {
+  uint32_t Id; /* record type identifier */
+  uint32_t TotalSize;
+  uint64_t Timestamp;
+};
+
+struct LLVMPerfJitRecordCodeLoad {
+  LLVMPerfJitRecordPrefix Prefix;
+
+  uint32_t Pid;
+  uint32_t Tid;
+  uint64_t Vma;
+  uint64_t CodeAddr;
+  uint64_t CodeSize;
+  uint64_t CodeIndex;
+};
+
+struct LLVMPerfJitRecordClose {
+  LLVMPerfJitRecordPrefix Prefix;
+};
+
+struct LLVMPerfJitRecordMoveCode {
+  LLVMPerfJitRecordPrefix Prefix;
+
+  uint32_t Pid;
+  uint32_t Tid;
+  uint64_t Vma;
+  uint64_t OldCodeAddr;
+  uint64_t NewCodeAddr;
+  uint64_t CodeSize;
+  uint64_t CodeIndex;
+};
+
+struct LLVMPerfJitDebugEntry {
+  uint64_t Addr;
+  int Lineno; /* source line number starting at 1 */
+  int Discrim; /* column discriminator, 0 is default */
+  char Name[]; /* null terminated filename, \xff\0 if same as previous entry */
+};
+
+struct LLVMPerfJitRecordDebugInfo {
+  LLVMPerfJitRecordPrefix Prefix;
+
+  uint64_t CodeAddr;
+  uint64_t NrEntry;
+  LLVMPerfJitDebugEntry Entries[];
+};
+
+struct LLVMPerfJitRecordUnwindInfo {
+  LLVMPerfJitRecordPrefix prefix;
+
+  uint64_t UnwindingSize;
+  uint64_t EhFrameHdrSize;
+  uint64_t MappedSize;
+  const char UnwindingData[];
+};
+
+// not available otherwise
+static inline pid_t gettid(void) {
+  return (pid_t)syscall(__NR_gettid);
+}
+
+static inline uint64_t
+timespec_to_ns(const struct timespec *ts) {
+  const uint64_t NanoSecPerSec = 1000000000;
+  return ((uint64_t) ts->tv_sec * NanoSecPerSec) + ts->tv_nsec;
+}
+
+static inline uint64_t
+perf_get_timestamp(void) {
+  struct timespec ts;
+  int ret;
+
+  ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+  if (ret)
+    return 0;
+
+  return timespec_to_ns(&ts);
+}
+
+
+PerfJITEventListener::PerfJITEventListener()
+    : Pid(getpid()) {
+
+  LLVMPerfJitHeader Header = {0};
+  std::string Filename;
+  raw_string_ostream FilenameBuf(Filename);
+
+  // check if clock-source is supported
+  if (!perf_get_timestamp()) {
+    errs() << "kernel does not support CLOCK_MONOTONIC("<<CLOCK_MONOTONIC<<")\n";
+    return;
+  }
+
+  memset(&Header, 0, sizeof(Header));
+
+  if (!InitDebuggingDir()) {
+    errs() << "could not initialize debugging directory\n";
+    return;
+  }
+
+  FilenameBuf << JitPath << "/jit-"<<Pid<<".dump";
+
+  Fd = ::open(FilenameBuf.str().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666);
+  if (Fd == -1) {
+    errs() << "could not open JIT dump file "<<FilenameBuf.str()<<"\n";
+    return;
+  }
+
+  std::error_code EC;
+  Dumpstream = make_unique<raw_fd_ostream>(Fd, true);
+  assert(!EC);
+
+  if (!OpenMarker()) {
+    return;
+  }
+
+  if (!FillMachine(Header)) {
+    return;
+  }
+
+  Header.Magic = LLVM_PERF_JIT_MAGIC;
+  Header.Version = LLVM_PERF_JIT_VERSION;
+  Header.TotalSize = sizeof(Header);
+  Header.Pid = Pid;
+  Header.Timestamp = perf_get_timestamp();
+
+  Dumpstream->write((char *) &Header, sizeof(Header));
+
+  // Everything initialized, can do profiling now.
+  if (!Dumpstream->has_error())
+    SuccessfullyInitialized = true;
+}
+
+void PerfJITEventListener::NotifyObjectEmitted(
+    const ObjectFile &Obj,
+    const RuntimeDyld::LoadedObjectInfo &L) {
+
+  if (!SuccessfullyInitialized)
+    return;
+
+  OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj);
+  const ObjectFile &DebugObj = *DebugObjOwner.getBinary();
+
+  // Get the address of the object image for use as a unique identifier
+  std::unique_ptr<DIContext> Context = DWARFContext::create(DebugObj);
+
+  // Use symbol info to iterate functions in the object.
+  for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) {
+    SymbolRef Sym = P.first;
+    std::vector<LLVMPerfJitDebugEntry> LineInfo;
+    std::string SourceFileName;
+
+    Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType();
+    if (!SymTypeOrErr) {
+      // TODO: Actually report errors helpfully.
+      consumeError(SymTypeOrErr.takeError());
+      continue;
+    }
+    SymbolRef::Type SymType = *SymTypeOrErr;
+    if (SymType != SymbolRef::ST_Function)
+      continue;
+
+    Expected<StringRef> Name = Sym.getName();
+    if (!Name) {
+      // TODO: Actually report errors helpfully.
+      consumeError(Name.takeError());
+      continue;
+    }
+
+    Expected<uint64_t> AddrOrErr = Sym.getAddress();
+    if (!AddrOrErr) {
+      // TODO: Actually report errors helpfully.
+      consumeError(AddrOrErr.takeError());
+      continue;
+    }
+    uint64_t Addr = *AddrOrErr;
+    uint64_t Size = P.second;
+
+    // According to spec debugging info has to come before loading the
+    // corresonding code load.
+    DILineInfoTable Lines = Context->getLineInfoForAddressRange(
+        Addr, Size, FileLineInfoKind::AbsoluteFilePath);
+    NotifyDebug(Addr, Lines);
+
+    NotifyCode(Name, Addr, Size);
+  }
+
+  Dumpstream->flush();
+}
+
+void PerfJITEventListener::NotifyFreeingObject(const ObjectFile &Obj) {
+  /* perf currently doesn't have an interface for unloading */
+}
+
+bool PerfJITEventListener::InitDebuggingDir() {
+  const char *BaseDir;
+  llvm::SmallString<128> TestDir;
+  time_t Time;
+  struct tm LocalTime;
+  char TimeBuffer[sizeof("YYMMDD")];
+
+  time(&Time);
+  localtime_r(&Time, &LocalTime);
+
+  /* perf specific location */
+  BaseDir = getenv("JITDUMPDIR");
+  if (!BaseDir)
+    BaseDir = getenv("HOME");
+  if (!BaseDir)
+    BaseDir = ".";
+
+  strftime(TimeBuffer, sizeof(TimeBuffer), "%Y%m%d", &LocalTime);
+
+  std::string DebugDir(BaseDir);
+  DebugDir += "/.debug/jit/";
+
+  if (sys::fs::create_directories(DebugDir)) {
+    errs() << "could not create jit cache directory "<<DebugDir<<"\n";
+    return false;
+  }
+
+  SmallString<128> UniqueDebugDir;
+
+  if (sys::fs::createUniqueDirectory(Twine(DebugDir) + JIT_LANG"-jit-" + TimeBuffer,
+                                     UniqueDebugDir)) {
+    errs() << "could not create unique jit cache directory "<<DebugDir<<"\n";
+    return false;
+  }
+
+  JitPath = UniqueDebugDir.str();
+
+  return true;
+}
+
+bool PerfJITEventListener::OpenMarker() {
+  long pgsz;
+
+  pgsz = ::sysconf(_SC_PAGESIZE);
+  if (pgsz == -1)
+    return false;
+
+  /*
+   * We mmap the jitdump to create an MMAP RECORD in perf.data file.  The mmap
+   * is captured either live (perf record running when we mmap) or in deferred
+   * mode, via /proc/PID/maps the MMAP record is used as a marker of a jitdump
+   * file for more meta data info about the jitted code. Perf report/annotate
+   * detect this special filename and process the jitdump file.
+   *
+   * Mapping must be PROT_EXEC to ensure it is captured by perf record
+   * even when not using -d option.
+   */
+  MarkerAddr = ::mmap(NULL, pgsz, PROT_READ|PROT_EXEC, MAP_PRIVATE, Fd, 0);
+
+  if (MarkerAddr == MAP_FAILED) {
+    errs() << "could not mmap JIT marker\n";
+    return false;
+  }
+  return true;
+}
+
+bool PerfJITEventListener::FillMachine(LLVMPerfJitHeader &hdr) {
+  ssize_t sret;
+  char id[16];
+  int fd;
+  struct {
+    uint16_t e_type;
+    uint16_t e_machine;
+  } info;
+
+  fd = ::open("/proc/self/exe", O_RDONLY);
+  if (fd == -1) {
+    errs() << "could not open /proc/self/exe\n";
+    return false;
+  }
+
+  sret = ::read(fd, id, sizeof(id));
+  if (sret != sizeof(id)) {
+    errs() << "could not read elf signature from /proc/self/exe\n";
+    goto error;
+  }
+
+  /* check ELF signature */
+  if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F') {
+    errs() << "invalid elf signature\n";
+    goto error;
+  }
+
+  sret = ::read(fd, &info, sizeof(info));
+  if (sret != sizeof(info)) {
+    errs() << "could not read machine identification\n";
+    goto error;
+  }
+
+  hdr.ElfMach = info.e_machine;
+ error:
+  close(fd);
+  return true;
+}
+
+void PerfJITEventListener::CloseMarker() {
+  long pgsz;
+
+  if (!MarkerAddr)
+    return;
+
+  pgsz = ::sysconf(_SC_PAGESIZE);
+  if (pgsz == -1)
+    return;
+
+  munmap(MarkerAddr, pgsz);
+  MarkerAddr = nullptr;
+}
+
+void PerfJITEventListener::NotifyCode(Expected<llvm::StringRef> &Symbol, uint64_t CodeAddr, uint64_t CodeSize) {
+  static int code_generation = 1;
+  LLVMPerfJitRecordCodeLoad rec;
+
+  assert(SuccessfullyInitialized);
+
+  // 0 length functions can't have samples.
+  if (CodeSize == 0)
+    return;
+
+  rec.Prefix.Id = JIT_CODE_LOAD;
+  rec.Prefix.TotalSize =
+    sizeof(rec) + // debug record itself
+    Symbol->size() + 1 + // symbol name
+    CodeSize; // and code
+  rec.Prefix.Timestamp = perf_get_timestamp();
+
+  rec.CodeSize = CodeSize;
+  rec.Vma = 0;
+  rec.CodeAddr = CodeAddr;
+  rec.Pid = Pid;
+  rec.Tid = gettid();
+
+  // get code index inside lock to avoid race condition
+  MutexGuard Guard(Mutex);
+
+  rec.CodeIndex = code_generation++;
+
+  Dumpstream->write(reinterpret_cast<const char *>(&rec), sizeof(rec));
+  Dumpstream->write(Symbol->data(), Symbol->size() + 1);
+  Dumpstream->write(reinterpret_cast<const char *>(CodeAddr), CodeSize);
+}
+
+void PerfJITEventListener::NotifyDebug(uint64_t CodeAddr, DILineInfoTable Lines) {
+  LLVMPerfJitRecordDebugInfo rec;
+
+  assert(SuccessfullyInitialized);
+
+  // Didn't get useful debug info.
+  if (Lines.empty())
+    return;
+
+  rec.Prefix.Id = JIT_CODE_DEBUG_INFO;
+  rec.Prefix.TotalSize = sizeof(rec); // will be increased further
+  rec.Prefix.Timestamp = perf_get_timestamp();
+  rec.CodeAddr = CodeAddr;
+  rec.NrEntry = Lines.size();
+
+  /* compute total size size of record (variable due to filenames) */
+  DILineInfoTable::iterator Begin = Lines.begin();
+  DILineInfoTable::iterator End = Lines.end();
+  for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
+    DILineInfo &line = It->second;
+    rec.Prefix.TotalSize += sizeof(LLVMPerfJitDebugEntry);
+    rec.Prefix.TotalSize += line.FileName.size() + 1;
+  }
+
+  Dumpstream->write(reinterpret_cast<const char *>(&rec), sizeof(rec));
+
+  // The debug_entry describes the source line information. It is defined as follows in order:
+  // * uint64_t code_addr: address of function for which the debug information is generated
+  // * uint32_t line     : source file line number (starting at 1)
+  // * uint32_t discrim  : column discriminator, 0 is default
+  // * char name[n]      : source file name in ASCII, including null termination
+
+  MutexGuard Guard(Mutex);
+
+  for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
+    LLVMPerfJitDebugEntry LineInfo;
+    DILineInfo &Line = It->second;
+
+    LineInfo.Addr = It->first;
+    // For reasons unknown to me either llvm offsets or perf's use of them is
+    // offset by 0x40. Inquiring.
+    LineInfo.Addr += 0x40;
+    LineInfo.Lineno = Line.Line;
+    LineInfo.Discrim = Line.Discriminator;
+
+    Dumpstream->write(reinterpret_cast<const char *>(&LineInfo), sizeof(LineInfo));
+    Dumpstream->write(Line.FileName.c_str(), Line.FileName.size() + 1);
+  }
+}
+
+} // end anonymous namespace
+
+namespace llvm {
+JITEventListener *JITEventListener::createPerfJITEventListener() {
+  return new PerfJITEventListener();
+}
+} // end llvm namespace
diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt
index f02e19313b7..5f235b6f6f3 100644
--- a/tools/lli/CMakeLists.txt
+++ b/tools/lli/CMakeLists.txt
@@ -36,6 +36,15 @@ if( LLVM_USE_INTEL_JITEVENTS )
     )
 endif( LLVM_USE_INTEL_JITEVENTS )
 
+if( LLVM_USE_PERF )
+  set(LLVM_LINK_COMPONENTS
+    ${LLVM_LINK_COMPONENTS}
+    DebugInfoDWARF
+    PerfJITEvents
+    Object
+    )
+endif( LLVM_USE_PERF )
+
 add_llvm_tool(lli
   lli.cpp
   OrcLazyJIT.cpp
diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp
index cd43e9d5791..a6c22526ea6 100644
--- a/tools/lli/lli.cpp
+++ b/tools/lli/lli.cpp
@@ -496,6 +496,8 @@ int main(int argc, char **argv, char * const *envp) {
                 JITEventListener::createOProfileJITEventListener());
   EE->RegisterJITEventListener(
                 JITEventListener::createIntelJITEventListener());
+  EE->RegisterJITEventListener(
+                JITEventListener::createPerfJITEventListener());
 
   if (!NoLazyCompilation && RemoteMCJIT) {
     errs() << "warning: remote mcjit does not support lazy compilation\n";
-- 
2.14.1.536.g6867272d5b.dirty

>From c97ed210b4a3400e23639cc10e746b231729dd82 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Wed, 4 Oct 2017 15:37:27 -0700
Subject: [PATCH 6/6] [ORC] JIT event listener support.

---
 include/llvm-c/OrcBindings.h                       |  4 ++
 .../ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h | 22 +++++++++-
 lib/ExecutionEngine/Orc/OrcCBindings.cpp           | 25 ++++++++++++
 lib/ExecutionEngine/Orc/OrcCBindingsStack.h        | 47 +++++++++++++++++++++-
 4 files changed, 94 insertions(+), 4 deletions(-)

diff --git a/include/llvm-c/OrcBindings.h b/include/llvm-c/OrcBindings.h
index 4ff1f47e87d..38fa44c231d 100644
--- a/include/llvm-c/OrcBindings.h
+++ b/include/llvm-c/OrcBindings.h
@@ -180,6 +180,10 @@ LLVMOrcErrorCode LLVMOrcGetSymbolAddressIn(LLVMOrcJITStackRef JITStack,
  */
 LLVMOrcErrorCode LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack);
 
+void LLVMOrcRegisterPerf(LLVMOrcJITStackRef JITStack);
+void LLVMOrcRegisterGDB(LLVMOrcJITStackRef JITStack);
+void LLVMOrcUnregisterPerf(LLVMOrcJITStackRef JITStack);
+
 #ifdef __cplusplus
 }
 #endif /* extern "C" */
diff --git a/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h b/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h
index 246c57341f3..d720f4053a3 100644
--- a/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h
+++ b/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h
@@ -75,6 +75,8 @@ protected:
       return JITSymbol(SymEntry->second);
     }
 
+    virtual ObjectPtr getObject() const = 0;
+
   protected:
     StringMap<JITEvaluatedSymbol> SymbolTable;
     bool Finalized = false;
@@ -106,6 +108,10 @@ public:
   /// @brief Functor for receiving finalization notifications.
   using NotifyFinalizedFtor = std::function<void(ObjHandleT)>;
 
+
+  /// @brief Functor for receiving freeing notifications.
+  using NotifyFreedFtor = std::function<void(ObjHandleT)>;
+
 private:
 
 
@@ -117,7 +123,8 @@ private:
                          SymbolResolverPtrT Resolver,
                          FinalizerFtor Finalizer,
                          bool ProcessAllSections)
-      : MemMgr(std::move(MemMgr)),
+        : MemMgr(std::move(MemMgr)),
+          Obj(Obj),
         PFC(llvm::make_unique<PreFinalizeContents>(std::move(Obj),
                                                    std::move(Resolver),
                                                    std::move(Finalizer),
@@ -168,6 +175,10 @@ private:
       PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
     }
 
+    ObjectPtr getObject() const override {
+      return Obj;
+    };
+
   private:
 
     void buildInitialSymbolTable(const ObjectPtr &Obj) {
@@ -209,6 +220,7 @@ private:
     };
 
     MemoryManagerPtrT MemMgr;
+    ObjectPtr Obj;
     std::unique_ptr<PreFinalizeContents> PFC;
   };
 
@@ -238,10 +250,12 @@ public:
   RTDyldObjectLinkingLayer(
       MemoryManagerGetter GetMemMgr,
       NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
-      NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor())
+      NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor(),
+      NotifyFreedFtor NotifyFreed = NotifyFreedFtor())
       : GetMemMgr(GetMemMgr),
         NotifyLoaded(std::move(NotifyLoaded)),
         NotifyFinalized(std::move(NotifyFinalized)),
+        NotifyFreed(std::move(NotifyFreed)),
         ProcessAllSections(false) {}
 
   /// @brief Set the 'ProcessAllSections' flag.
@@ -300,6 +314,9 @@ public:
   /// required to detect or resolve such issues it should be added at a higher
   /// layer.
   Error removeObject(ObjHandleT H) {
+    if (this->NotifyFreed)
+      this->NotifyFreed(H);
+
     // How do we invalidate the symbols in H?
     LinkedObjList.erase(H);
     return Error::success();
@@ -350,6 +367,7 @@ private:
   MemoryManagerGetter GetMemMgr;
   NotifyLoadedFtor NotifyLoaded;
   NotifyFinalizedFtor NotifyFinalized;
+  NotifyFreedFtor NotifyFreed;
   bool ProcessAllSections = false;
 };
 
diff --git a/lib/ExecutionEngine/Orc/OrcCBindings.cpp b/lib/ExecutionEngine/Orc/OrcCBindings.cpp
index 9b9c1512402..9c83ce2c340 100644
--- a/lib/ExecutionEngine/Orc/OrcCBindings.cpp
+++ b/lib/ExecutionEngine/Orc/OrcCBindings.cpp
@@ -10,6 +10,8 @@
 #include "OrcCBindingsStack.h"
 #include "llvm-c/OrcBindings.h"
 
+#include "llvm/ExecutionEngine/JITEventListener.h"
+
 using namespace llvm;
 
 LLVMSharedModuleRef LLVMOrcMakeSharedModule(LLVMModuleRef Mod) {
@@ -134,3 +136,26 @@ LLVMOrcErrorCode LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack) {
   delete J;
   return Err;
 }
+
+
+static JITEventListener *perf_listener_orc = NULL;
+static JITEventListener *gdb_listener_orc = NULL;
+
+void LLVMOrcRegisterGDB(LLVMOrcJITStackRef JITStack) {
+  if (!gdb_listener_orc)
+    gdb_listener_orc = JITEventListener::createGDBRegistrationListener();
+  unwrap(JITStack)->RegisterJITEventListener(gdb_listener_orc);
+}
+
+void LLVMOrcRegisterPerf(LLVMOrcJITStackRef JITStack) {
+  if (!perf_listener_orc)
+    perf_listener_orc = JITEventListener::createPerfJITEventListener();
+  unwrap(JITStack)->RegisterJITEventListener(perf_listener_orc);
+}
+
+void LLVMOrcUnregisterPerf(LLVMOrcJITStackRef JITStack) {
+  if (perf_listener_orc) {
+    delete perf_listener_orc;
+    perf_listener_orc = NULL;
+  }
+}
diff --git a/lib/ExecutionEngine/Orc/OrcCBindingsStack.h b/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
index 6eaac01d52f..b448a9c370c 100644
--- a/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
+++ b/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
@@ -15,6 +15,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ExecutionEngine/JITSymbol.h"
+#include "llvm/ExecutionEngine/JITEventListener.h"
 #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
@@ -24,8 +25,10 @@
 #include "llvm/ExecutionEngine/RuntimeDyld.h"
 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
 #include "llvm/IR/DataLayout.h"
+#include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Mangler.h"
 #include "llvm/IR/Module.h"
+#include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/CBindingWrapping.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/raw_ostream.h"
@@ -137,13 +140,18 @@ public:
         ObjectLayer(
           []() {
             return std::make_shared<SectionMemoryManager>();
-          }),
+          },
+          std::bind(&OrcCBindingsStack::notifyLoaded, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3),
+          std::bind(&OrcCBindingsStack::notifyFinalized, this, std::placeholders::_1),
+          std::bind(&OrcCBindingsStack::notifyFreed, this, std::placeholders::_1)),
         CompileLayer(ObjectLayer, orc::SimpleCompiler(TM)),
         CODLayer(CompileLayer,
                  [](Function &F) { return std::set<Function *>({&F}); },
                  *this->CCMgr, std::move(IndirectStubsMgrBuilder), false),
         CXXRuntimeOverrides(
-            [this](const std::string &S) { return mangle(S); }) {}
+            [this](const std::string &S) { return mangle(S); }) {
+    ObjectLayer.setProcessAllSections(true);
+  }
 
   LLVMOrcErrorCode shutdown() {
     // Run any destructors registered with __cxa_atexit.
@@ -378,6 +386,10 @@ public:
 
   const std::string &getErrorMessage() const { return ErrMsg; }
 
+  void RegisterJITEventListener(JITEventListener *l) {
+    EventListeners.push_back(l);
+  }
+
 private:
   template <typename LayerT, typename HandleT>
   unsigned createHandle(LayerT &Layer, HandleT Handle) {
@@ -408,6 +420,33 @@ private:
     return Result;
   }
 
+  void notifyLoaded(orc::RTDyldObjectLinkingLayerBase::ObjHandleT H,
+                    const orc::RTDyldObjectLinkingLayerBase::ObjectPtr &Obj,
+                    const RuntimeDyld::LoadedObjectInfo &LoadedObjInfo) {
+    PendingLoadedObjectInfos.push_back(&LoadedObjInfo);
+    PendingLoadedObjects.push_back(Obj->getBinary());
+  }
+
+
+  void notifyFinalized(orc::RTDyldObjectLinkingLayerBase::ObjHandleT H) {
+    for (auto &Listener : EventListeners) {
+      for (size_t I = 0, S = PendingLoadedObjects.size(); I < S; ++I) {
+        auto &Obj = PendingLoadedObjects[I];
+        auto &Info = PendingLoadedObjectInfos[I];
+        Listener->NotifyObjectEmitted(*Obj, *Info);
+      }
+    }
+
+    PendingLoadedObjects.clear();
+    PendingLoadedObjectInfos.clear();
+  }
+
+  void notifyFreed(orc::RTDyldObjectLinkingLayerBase::ObjHandleT H) {
+    for (auto &Listener : EventListeners) {
+      Listener->NotifyFreeingObject(*(*H)->getObject()->getBinary());
+    }
+  }
+
   DataLayout DL;
   SectionMemoryManager CCMgrMemMgr;
 
@@ -424,6 +463,10 @@ private:
   orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides;
   std::vector<orc::CtorDtorRunner<OrcCBindingsStack>> IRStaticDestructorRunners;
   std::string ErrMsg;
+
+  std::vector<JITEventListener *> EventListeners;
+  std::vector<const RuntimeDyld::LoadedObjectInfo *> PendingLoadedObjectInfos;
+  std::vector<const object::ObjectFile*> PendingLoadedObjects;
 };
 
 } // end namespace llvm
-- 
2.14.1.536.g6867272d5b.dirty

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to