[llvm] 00f4121 - [ORC][JITLink] Add Intel VTune support to JITLink (#83957)

via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 7 11:15:20 PST 2024


Author: Hongyu Chen
Date: 2024-03-07T11:15:16-08:00
New Revision: 00f412168cf6aee234615a11d1424fc58221eb78

URL: https://github.com/llvm/llvm-project/commit/00f412168cf6aee234615a11d1424fc58221eb78
DIFF: https://github.com/llvm/llvm-project/commit/00f412168cf6aee234615a11d1424fc58221eb78.diff

LOG: [ORC][JITLink] Add Intel VTune support to JITLink (#83957)

[ORC] Re-land https://github.com/llvm/llvm-project/pull/81826

This patch adds two plugins: VTuneSupportPlugin.cpp and
JITLoaderVTune.cpp. The testing is done in a manner similar to
llvm-jitlistener. Currently, we only support the old version of Intel
VTune API.

Added: 
    llvm/include/llvm/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.h
    llvm/include/llvm/ExecutionEngine/Orc/Shared/VTuneSharedStructs.h
    llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.h
    llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp
    llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.cpp
    llvm/test/ExecutionEngine/JITLink/x86-64/ELF_vtune.s

Modified: 
    llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt
    llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
    llvm/test/ExecutionEngine/JITLink/x86-64/lit.local.cfg
    llvm/tools/llvm-jitlink/llvm-jitlink.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.h b/llvm/include/llvm/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.h
new file mode 100644
index 00000000000000..9deb38a1a71fb1
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.h
@@ -0,0 +1,66 @@
+//===--- VTuneSupportPlugin.h -- Support for VTune profiler ---*- C++ -*---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Handles support for registering code with VIntel Tune's Amplifier JIT API.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_DEBUGGING_VTUNESUPPORT_H
+#define LLVM_EXECUTIONENGINE_ORC_DEBUGGING_VTUNESUPPORT_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
+#include "llvm/ExecutionEngine/Orc/Shared/VTuneSharedStructs.h"
+
+namespace llvm {
+
+namespace orc {
+
+class VTuneSupportPlugin : public ObjectLinkingLayer::Plugin {
+public:
+  VTuneSupportPlugin(ExecutorProcessControl &EPC, ExecutorAddr RegisterImplAddr,
+                     ExecutorAddr UnregisterImplAddr, bool EmitDebugInfo)
+      : EPC(EPC), RegisterVTuneImplAddr(RegisterImplAddr),
+        UnregisterVTuneImplAddr(UnregisterImplAddr),
+        EmitDebugInfo(EmitDebugInfo) {}
+
+  void modifyPassConfig(MaterializationResponsibility &MR,
+                        jitlink::LinkGraph &G,
+                        jitlink::PassConfiguration &Config) override;
+
+  Error notifyEmitted(MaterializationResponsibility &MR) override;
+  Error notifyFailed(MaterializationResponsibility &MR) override;
+  Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override;
+  void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
+                                   ResourceKey SrcKey) override;
+
+  static Expected<std::unique_ptr<VTuneSupportPlugin>>
+  Create(ExecutorProcessControl &EPC, JITDylib &JD, bool EmitDebugInfo,
+         bool TestMode = false);
+
+private:
+  ExecutorProcessControl &EPC;
+  ExecutorAddr RegisterVTuneImplAddr;
+  ExecutorAddr UnregisterVTuneImplAddr;
+  std::mutex PluginMutex;
+  uint64_t NextMethodID = 0;
+  DenseMap<MaterializationResponsibility *, std::pair<uint64_t, uint64_t>>
+      PendingMethodIDs;
+  DenseMap<ResourceKey, SmallVector<std::pair<uint64_t, uint64_t>>>
+      LoadedMethodIDs;
+  bool EmitDebugInfo;
+};
+
+} // end namespace orc
+
+} // end namespace llvm
+
+#endif

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/VTuneSharedStructs.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/VTuneSharedStructs.h
new file mode 100644
index 00000000000000..667d3446faff74
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/VTuneSharedStructs.h
@@ -0,0 +1,102 @@
+//===-------------------- VTuneSharedStructs.h ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Structs and serialization to share VTune-related information
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_VTUNESHAREDSTRUCTS_H
+#define LLVM_EXECUTIONENGINE_ORC_SHARED_VTUNESHAREDSTRUCTS_H
+
+namespace llvm {
+namespace orc {
+
+using VTuneLineTable = std::vector<std::pair<unsigned, unsigned>>;
+
+// SI = String Index, 1-indexed into the VTuneMethodBatch::Strings table.
+// SI == 0 means replace with nullptr.
+
+// MI = Method Index, 1-indexed into the VTuneMethodBatch::Methods table.
+// MI == 0 means this is a parent method and was not inlined.
+
+struct VTuneMethodInfo {
+  VTuneLineTable LineTable;
+  ExecutorAddr LoadAddr;
+  uint64_t LoadSize;
+  uint64_t MethodID;
+  uint32_t NameSI;
+  uint32_t ClassFileSI;
+  uint32_t SourceFileSI;
+  uint32_t ParentMI;
+};
+
+using VTuneMethodTable = std::vector<VTuneMethodInfo>;
+using VTuneStringTable = std::vector<std::string>;
+
+struct VTuneMethodBatch {
+  VTuneMethodTable Methods;
+  VTuneStringTable Strings;
+};
+
+using VTuneUnloadedMethodIDs = SmallVector<std::pair<uint64_t, uint64_t>>;
+
+namespace shared {
+
+using SPSVTuneLineTable = SPSSequence<SPSTuple<uint32_t, uint32_t>>;
+using SPSVTuneMethodInfo =
+    SPSTuple<SPSVTuneLineTable, SPSExecutorAddr, uint64_t, uint64_t, uint32_t,
+             uint32_t, uint32_t, uint32_t>;
+using SPSVTuneMethodTable = SPSSequence<SPSVTuneMethodInfo>;
+using SPSVTuneStringTable = SPSSequence<SPSString>;
+using SPSVTuneMethodBatch = SPSTuple<SPSVTuneMethodTable, SPSVTuneStringTable>;
+using SPSVTuneUnloadedMethodIDs = SPSSequence<SPSTuple<uint64_t, uint64_t>>;
+
+template <> class SPSSerializationTraits<SPSVTuneMethodInfo, VTuneMethodInfo> {
+public:
+  static size_t size(const VTuneMethodInfo &MI) {
+    return SPSVTuneMethodInfo::AsArgList::size(
+        MI.LineTable, MI.LoadAddr, MI.LoadSize, MI.MethodID, MI.NameSI,
+        MI.ClassFileSI, MI.SourceFileSI, MI.ParentMI);
+  }
+
+  static bool deserialize(SPSInputBuffer &IB, VTuneMethodInfo &MI) {
+    return SPSVTuneMethodInfo::AsArgList::deserialize(
+        IB, MI.LineTable, MI.LoadAddr, MI.LoadSize, MI.MethodID, MI.NameSI,
+        MI.ClassFileSI, MI.SourceFileSI, MI.ParentMI);
+  }
+
+  static bool serialize(SPSOutputBuffer &OB, const VTuneMethodInfo &MI) {
+    return SPSVTuneMethodInfo::AsArgList::serialize(
+        OB, MI.LineTable, MI.LoadAddr, MI.LoadSize, MI.MethodID, MI.NameSI,
+        MI.ClassFileSI, MI.SourceFileSI, MI.ParentMI);
+  }
+};
+
+template <>
+class SPSSerializationTraits<SPSVTuneMethodBatch, VTuneMethodBatch> {
+public:
+  static size_t size(const VTuneMethodBatch &MB) {
+    return SPSVTuneMethodBatch::AsArgList::size(MB.Methods, MB.Strings);
+  }
+
+  static bool deserialize(SPSInputBuffer &IB, VTuneMethodBatch &MB) {
+    return SPSVTuneMethodBatch::AsArgList::deserialize(IB, MB.Methods,
+                                                       MB.Strings);
+  }
+
+  static bool serialize(SPSOutputBuffer &OB, const VTuneMethodBatch &MB) {
+    return SPSVTuneMethodBatch::AsArgList::serialize(OB, MB.Methods,
+                                                     MB.Strings);
+  }
+};
+
+} // end namespace shared
+} // end namespace orc
+} // end namespace llvm
+
+#endif

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.h
new file mode 100644
index 00000000000000..afb7df592faf27
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.h
@@ -0,0 +1,31 @@
+
+//===------ JITLoaderVTune.h --- Register profiler objects ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Register objects for access by profilers via the perf JIT interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_JITLOADERVTUNE_H
+#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_JITLOADERVTUNE_H
+
+#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
+#include <cstdint>
+
+extern "C" llvm::orc::shared::CWrapperFunctionResult
+llvm_orc_registerVTuneImpl(const char *Data, uint64_t Size);
+
+extern "C" llvm::orc::shared::CWrapperFunctionResult
+llvm_orc_unregisterVTuneImpl(const char *Data, uint64_t Size);
+
+extern "C" llvm::orc::shared::CWrapperFunctionResult
+llvm_orc_test_registerVTuneImpl(const char *Data, uint64_t Size);
+
+#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_JITLOADERVTUNE_H
+
+

diff  --git a/llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt
index 5bf23a7ec0bc89..ed52692662a8a3 100644
--- a/llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt
@@ -8,6 +8,7 @@ add_llvm_component_library(LLVMOrcDebugging
   DebuggerSupportPlugin.cpp
   LLJITUtilsCBindings.cpp
   PerfSupportPlugin.cpp
+  VTuneSupportPlugin.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc/Debugging/

diff  --git a/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp b/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp
new file mode 100644
index 00000000000000..30a9728c8c20e3
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.cpp
@@ -0,0 +1,185 @@
+//===--- VTuneSupportPlugin.cpp -- Support for VTune profiler --*- C++ -*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Handles support for registering code with VIntel Tune's Amplfiier JIT API.
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"
+
+using namespace llvm;
+using namespace llvm::orc;
+using namespace llvm::jitlink;
+
+static constexpr StringRef RegisterVTuneImplName = "llvm_orc_registerVTuneImpl";
+static constexpr StringRef UnregisterVTuneImplName =
+    "llvm_orc_unregisterVTuneImpl";
+static constexpr StringRef RegisterTestVTuneImplName =
+    "llvm_orc_test_registerVTuneImpl";
+
+static VTuneMethodBatch getMethodBatch(LinkGraph &G, bool EmitDebugInfo) {
+  VTuneMethodBatch Batch;
+  std::unique_ptr<DWARFContext> DC;
+  StringMap<std::unique_ptr<MemoryBuffer>> DCBacking;
+  if (EmitDebugInfo) {
+    auto EDC = createDWARFContext(G);
+    if (!EDC) {
+      EmitDebugInfo = false;
+    } else {
+      DC = std::move(EDC->first);
+      DCBacking = std::move(EDC->second);
+    }
+  }
+
+  auto GetStringIdx = [Deduplicator = StringMap<uint32_t>(),
+                       &Batch](StringRef S) mutable {
+    auto I = Deduplicator.find(S);
+    if (I != Deduplicator.end())
+      return I->second;
+
+    Batch.Strings.push_back(S.str());
+    return Deduplicator[S] = Batch.Strings.size();
+  };
+  for (auto Sym : G.defined_symbols()) {
+    if (!Sym->isCallable())
+      continue;
+
+    Batch.Methods.push_back(VTuneMethodInfo());
+    auto &Method = Batch.Methods.back();
+    Method.MethodID = 0;
+    Method.ParentMI = 0;
+    Method.LoadAddr = Sym->getAddress();
+    Method.LoadSize = Sym->getSize();
+    Method.NameSI = GetStringIdx(Sym->getName());
+    Method.ClassFileSI = 0;
+    Method.SourceFileSI = 0;
+
+    if (!EmitDebugInfo)
+      continue;
+
+    auto &Section = Sym->getBlock().getSection();
+    auto Addr = Sym->getAddress();
+    auto SAddr =
+        object::SectionedAddress{Addr.getValue(), Section.getOrdinal()};
+    DILineInfoTable LinesInfo = DC->getLineInfoForAddressRange(
+        SAddr, Sym->getSize(),
+        DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
+    Method.SourceFileSI = Batch.Strings.size();
+    Batch.Strings.push_back(DC->getLineInfoForAddress(SAddr).FileName);
+    for (auto &LInfo : LinesInfo) {
+      Method.LineTable.push_back(
+          std::pair<unsigned, unsigned>{/*unsigned*/ Sym->getOffset(),
+                                        /*DILineInfo*/ LInfo.second.Line});
+    }
+  }
+  return Batch;
+}
+
+void VTuneSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,
+                                          LinkGraph &G,
+                                          PassConfiguration &Config) {
+  Config.PostFixupPasses.push_back([this, MR = &MR](LinkGraph &G) {
+    // the object file is generated but not linked yet
+    auto Batch = getMethodBatch(G, EmitDebugInfo);
+    if (Batch.Methods.empty()) {
+      return Error::success();
+    }
+    {
+      std::lock_guard<std::mutex> Lock(PluginMutex);
+      uint64_t Allocated = Batch.Methods.size();
+      uint64_t Start = NextMethodID;
+      NextMethodID += Allocated;
+      for (size_t i = Start; i < NextMethodID; ++i) {
+        Batch.Methods[i - Start].MethodID = i;
+      }
+      this->PendingMethodIDs[MR] = {Start, Allocated};
+    }
+    G.allocActions().push_back(
+        {cantFail(shared::WrapperFunctionCall::Create<
+                  shared::SPSArgList<shared::SPSVTuneMethodBatch>>(
+             RegisterVTuneImplAddr, Batch)),
+         {}});
+    return Error::success();
+  });
+}
+
+Error VTuneSupportPlugin::notifyEmitted(MaterializationResponsibility &MR) {
+  if (auto Err = MR.withResourceKeyDo([this, MR = &MR](ResourceKey K) {
+        std::lock_guard<std::mutex> Lock(PluginMutex);
+        auto I = PendingMethodIDs.find(MR);
+        if (I == PendingMethodIDs.end())
+          return;
+
+        LoadedMethodIDs[K].push_back(I->second);
+        PendingMethodIDs.erase(I);
+      })) {
+    return Err;
+  }
+  return Error::success();
+}
+
+Error VTuneSupportPlugin::notifyFailed(MaterializationResponsibility &MR) {
+  std::lock_guard<std::mutex> Lock(PluginMutex);
+  PendingMethodIDs.erase(&MR);
+  return Error::success();
+}
+
+Error VTuneSupportPlugin::notifyRemovingResources(JITDylib &JD, ResourceKey K) {
+  // Unregistration not required if not provided
+  if (!UnregisterVTuneImplAddr) {
+    return Error::success();
+  }
+  VTuneUnloadedMethodIDs UnloadedIDs;
+  {
+    std::lock_guard<std::mutex> Lock(PluginMutex);
+    auto I = LoadedMethodIDs.find(K);
+    if (I == LoadedMethodIDs.end())
+      return Error::success();
+
+    UnloadedIDs = std::move(I->second);
+    LoadedMethodIDs.erase(I);
+  }
+  if (auto Err = EPC.callSPSWrapper<void(shared::SPSVTuneUnloadedMethodIDs)>(
+          UnregisterVTuneImplAddr, UnloadedIDs))
+    return Err;
+
+  return Error::success();
+}
+
+void VTuneSupportPlugin::notifyTransferringResources(JITDylib &JD,
+                                                     ResourceKey DstKey,
+                                                     ResourceKey SrcKey) {
+  std::lock_guard<std::mutex> Lock(PluginMutex);
+  auto I = LoadedMethodIDs.find(SrcKey);
+  if (I == LoadedMethodIDs.end())
+    return;
+
+  auto &Dest = LoadedMethodIDs[DstKey];
+  Dest.insert(Dest.end(), I->second.begin(), I->second.end());
+  LoadedMethodIDs.erase(SrcKey);
+}
+
+Expected<std::unique_ptr<VTuneSupportPlugin>>
+VTuneSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
+                           bool EmitDebugInfo, bool TestMode) {
+  auto &ES = EPC.getExecutionSession();
+  auto RegisterImplName =
+      ES.intern(TestMode ? RegisterTestVTuneImplName : RegisterVTuneImplName);
+  auto UnregisterImplName = ES.intern(UnregisterVTuneImplName);
+  SymbolLookupSet SLS{RegisterImplName, UnregisterImplName};
+  auto Res = ES.lookup(makeJITDylibSearchOrder({&JD}), std::move(SLS));
+  if (!Res)
+    return Res.takeError();
+  ExecutorAddr RegisterImplAddr(
+      Res->find(RegisterImplName)->second.getAddress());
+  ExecutorAddr UnregisterImplAddr(
+      Res->find(UnregisterImplName)->second.getAddress());
+  return std::make_unique<VTuneSupportPlugin>(
+      EPC, RegisterImplAddr, UnregisterImplAddr, EmitDebugInfo);
+}

diff  --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
index f2005dc1775e3c..3d1dfe758c79dd 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
@@ -2,10 +2,18 @@ if( CMAKE_HOST_UNIX AND HAVE_LIBRT )
   set(rt_lib rt)
 endif()
 
+set(intel_jit_profiling )
+if( LLVM_USE_INTEL_JITEVENTS )
+  set(intel_jit_profiling IntelJITProfiling)
+  include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../IntelJITProfiling)
+  include_directories(${PROJECT_BINARY_DIR}/ittapi/include/ )
+endif()
+
 add_llvm_component_library(LLVMOrcTargetProcess
   ExecutorSharedMemoryMapperService.cpp
   JITLoaderGDB.cpp
   JITLoaderPerf.cpp
+  JITLoaderVTune.cpp
   OrcRTBootstrap.cpp
   RegisterEHFrames.cpp
   SimpleExecutorDylibManager.cpp
@@ -21,6 +29,7 @@ add_llvm_component_library(LLVMOrcTargetProcess
   ${rt_lib}
 
   LINK_COMPONENTS
+  ${intel_jit_profiling}
   OrcShared
   Support
   TargetParser

diff  --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.cpp
new file mode 100644
index 00000000000000..d346214d3ae291
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.cpp
@@ -0,0 +1,224 @@
+//===------- JITLoaderVTune.cpp - Register profiler objects -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Register objects for access by profilers via the VTune JIT interface.
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.h"
+#include "llvm/ExecutionEngine/Orc/Shared/VTuneSharedStructs.h"
+#include <map>
+
+#if LLVM_USE_INTEL_JITEVENTS
+#include "IntelJITEventsWrapper.h"
+#include "ittnotify.h"
+
+using namespace llvm;
+using namespace llvm::orc;
+
+namespace {
+class JITEventWrapper {
+public:
+  static std::unique_ptr<IntelJITEventsWrapper> Wrapper;
+};
+std::unique_ptr<IntelJITEventsWrapper> JITEventWrapper::Wrapper;
+} // namespace
+
+static Error registerJITLoaderVTuneRegisterImpl(const VTuneMethodBatch &MB) {
+  const size_t StringsSize = MB.Strings.size();
+
+  for (const auto &MethodInfo : MB.Methods) {
+    iJIT_Method_Load MethodMessage;
+    memset(&MethodMessage, 0, sizeof(iJIT_Method_Load));
+
+    MethodMessage.method_id = MethodInfo.MethodID;
+    if (MethodInfo.NameSI != 0 && MethodInfo.NameSI < StringsSize) {
+      MethodMessage.method_name =
+          const_cast<char *>(MB.Strings.at(MethodInfo.NameSI).data());
+    } else {
+      MethodMessage.method_name = NULL;
+    }
+    if (MethodInfo.ClassFileSI != 0 && MethodInfo.ClassFileSI < StringsSize) {
+      MethodMessage.class_file_name =
+          const_cast<char *>(MB.Strings.at(MethodInfo.ClassFileSI).data());
+    } else {
+      MethodMessage.class_file_name = NULL;
+    }
+    if (MethodInfo.SourceFileSI != 0 && MethodInfo.SourceFileSI < StringsSize) {
+      MethodMessage.source_file_name =
+          const_cast<char *>(MB.Strings.at(MethodInfo.SourceFileSI).data());
+    } else {
+      MethodMessage.source_file_name = NULL;
+    }
+
+    MethodMessage.method_load_address = MethodInfo.LoadAddr.toPtr<void *>();
+    MethodMessage.method_size = MethodInfo.LoadSize;
+    MethodMessage.class_id = 0;
+
+    MethodMessage.user_data = NULL;
+    MethodMessage.user_data_size = 0;
+    MethodMessage.env = iJDE_JittingAPI;
+
+    std::vector<LineNumberInfo> LineInfo;
+    for (const auto &LInfo : MethodInfo.LineTable) {
+      LineInfo.push_back(LineNumberInfo{LInfo.first, LInfo.second});
+    }
+
+    if (LineInfo.size() == 0) {
+      MethodMessage.line_number_size = 0;
+      MethodMessage.line_number_table = 0;
+    } else {
+      MethodMessage.line_number_size = LineInfo.size();
+      MethodMessage.line_number_table = &*LineInfo.begin();
+    }
+    JITEventWrapper::Wrapper->iJIT_NotifyEvent(
+        iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &MethodMessage);
+  }
+
+  return Error::success();
+}
+
+static void registerJITLoaderVTuneUnregisterImpl(
+    const std::vector<std::pair<uint64_t, uint64_t>> &UM) {
+  for (auto &Method : UM) {
+    JITEventWrapper::Wrapper->iJIT_NotifyEvent(
+        iJVM_EVENT_TYPE_METHOD_UNLOAD_START,
+        const_cast<unsigned long *>(&Method.first));
+  }
+}
+
+extern "C" llvm::orc::shared::CWrapperFunctionResult
+llvm_orc_registerVTuneImpl(const char *Data, uint64_t Size) {
+  using namespace orc::shared;
+  if (!JITEventWrapper::Wrapper)
+    JITEventWrapper::Wrapper.reset(new IntelJITEventsWrapper);
+
+  return WrapperFunction<SPSError(SPSVTuneMethodBatch)>::handle(
+             Data, Size, registerJITLoaderVTuneRegisterImpl)
+      .release();
+}
+
+extern "C" llvm::orc::shared::CWrapperFunctionResult
+llvm_orc_unregisterVTuneImpl(const char *Data, uint64_t Size) {
+  using namespace orc::shared;
+  return WrapperFunction<void(SPSVTuneUnloadedMethodIDs)>::handle(
+             Data, Size, registerJITLoaderVTuneUnregisterImpl)
+      .release();
+}
+
+// For Testing: following code comes from llvm-jitlistener.cpp in llvm tools
+namespace {
+using SourceLocations = std::vector<std::pair<std::string, unsigned int>>;
+using NativeCodeMap = std::map<uint64_t, SourceLocations>;
+NativeCodeMap ReportedDebugFuncs;
+} // namespace
+
+static int NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData) {
+  switch (EventType) {
+  case iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED: {
+    if (!EventSpecificData) {
+      errs() << "Error: The JIT event listener did not provide a event data.";
+      return -1;
+    }
+    iJIT_Method_Load *msg = static_cast<iJIT_Method_Load *>(EventSpecificData);
+
+    ReportedDebugFuncs[msg->method_id];
+
+    outs() << "Method load [" << msg->method_id << "]: " << msg->method_name
+           << ", Size = " << msg->method_size << "\n";
+
+    for (unsigned int i = 0; i < msg->line_number_size; ++i) {
+      if (!msg->line_number_table) {
+        errs() << "A function with a non-zero line count had no line table.";
+        return -1;
+      }
+      std::pair<std::string, unsigned int> loc(
+          std::string(msg->source_file_name),
+          msg->line_number_table[i].LineNumber);
+      ReportedDebugFuncs[msg->method_id].push_back(loc);
+      outs() << "  Line info @ " << msg->line_number_table[i].Offset << ": "
+             << msg->source_file_name << ", line "
+             << msg->line_number_table[i].LineNumber << "\n";
+    }
+    outs() << "\n";
+  } break;
+  case iJVM_EVENT_TYPE_METHOD_UNLOAD_START: {
+    if (!EventSpecificData) {
+      errs() << "Error: The JIT event listener did not provide a event data.";
+      return -1;
+    }
+    unsigned int UnloadId =
+        *reinterpret_cast<unsigned int *>(EventSpecificData);
+    assert(1 == ReportedDebugFuncs.erase(UnloadId));
+    outs() << "Method unload [" << UnloadId << "]\n";
+  } break;
+  default:
+    break;
+  }
+  return 0;
+}
+
+static iJIT_IsProfilingActiveFlags IsProfilingActive(void) {
+  // for testing, pretend we have an Intel Parallel Amplifier XE 2011
+  // instance attached
+  return iJIT_SAMPLING_ON;
+}
+
+static unsigned int GetNewMethodID(void) {
+  static unsigned int id = 0;
+  return ++id;
+}
+
+extern "C" llvm::orc::shared::CWrapperFunctionResult
+llvm_orc_test_registerVTuneImpl(const char *Data, uint64_t Size) {
+  using namespace orc::shared;
+  JITEventWrapper::Wrapper.reset(new IntelJITEventsWrapper(
+      NotifyEvent, NULL, NULL, IsProfilingActive, 0, 0, GetNewMethodID));
+  return WrapperFunction<SPSError(SPSVTuneMethodBatch)>::handle(
+             Data, Size, registerJITLoaderVTuneRegisterImpl)
+      .release();
+}
+
+#else
+
+using namespace llvm;
+using namespace llvm::orc;
+
+static Error unsupportedBatch(const VTuneMethodBatch &MB) {
+  return llvm::make_error<StringError>("unsupported for Intel VTune",
+                                       inconvertibleErrorCode());
+}
+
+static void unsuppported(const std::vector<std::pair<uint64_t, uint64_t>> &UM) {
+
+}
+
+extern "C" llvm::orc::shared::CWrapperFunctionResult
+llvm_orc_registerVTuneImpl(const char *Data, uint64_t Size) {
+  using namespace orc::shared;
+  return WrapperFunction<SPSError(SPSVTuneMethodBatch)>::handle(
+             Data, Size, unsupportedBatch)
+      .release();
+}
+
+extern "C" llvm::orc::shared::CWrapperFunctionResult
+llvm_orc_unregisterVTuneImpl(const char *Data, uint64_t Size) {
+  using namespace orc::shared;
+  return WrapperFunction<void(SPSVTuneUnloadedMethodIDs)>::handle(Data, Size,
+                                                                  unsuppported)
+      .release();
+}
+
+extern "C" llvm::orc::shared::CWrapperFunctionResult
+llvm_orc_test_registerVTuneImpl(const char *Data, uint64_t Size) {
+  using namespace orc::shared;
+  return WrapperFunction<SPSError(SPSVTuneMethodBatch)>::handle(
+             Data, Size, unsupportedBatch)
+      .release();
+}
+
+#endif

diff  --git a/llvm/test/ExecutionEngine/JITLink/x86-64/ELF_vtune.s b/llvm/test/ExecutionEngine/JITLink/x86-64/ELF_vtune.s
new file mode 100644
index 00000000000000..1c95bde51e1211
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/x86-64/ELF_vtune.s
@@ -0,0 +1,52 @@
+# REQUIRES: native && x86_64-linux && intel-jitevents
+
+# RUN: rm -rf %t && mkdir %t
+# RUN: llvm-mc -triple=x86_64-unknown-linux \
+# RUN:     -filetype=obj -o %t/ELF_x86-64_vtune.o %s
+# RUN: llvm-jitlink -vtune-support %t/ELF_x86-64_vtune.o | \
+# RUN: FileCheck %s
+
+# CHECK: Method load [0]: {{.*}}, Size = {{[0-9]+}}
+# CHECK: Method unload [0]
+        .file   "test.c"
+        .text
+        .globl  main
+        .type   main, @function
+main:
+.LFB0:
+        .cfi_startproc
+        endbr64
+        pushq   %rbp
+        .cfi_def_cfa_offset 16
+        .cfi_offset 6, -16
+        movq    %rsp, %rbp
+        .cfi_def_cfa_register 6
+        movl    %edi, -4(%rbp)
+        movq    %rsi, -16(%rbp)
+        movl    -4(%rbp), %ebx
+        addl    $1, %ebx
+	movl   $0, %eax
+        popq    %rbp
+        .cfi_def_cfa 7, 8
+        ret
+        .cfi_endproc
+.LFE0:
+        .size   main, .-main
+        .ident  "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0"
+        .section        .note.GNU-stack,"", at progbits
+        .section        .note.gnu.property,"a"
+        .align 8
+        .long    1f - 0f
+        .long    4f - 1f
+        .long    5
+0:
+        .string  "GNU"
+1:
+        .align 8
+        .long    0xc0000002
+        .long    3f - 2f
+2:
+        .long    0x3
+3:
+        .align 8
+4:

diff  --git a/llvm/test/ExecutionEngine/JITLink/x86-64/lit.local.cfg b/llvm/test/ExecutionEngine/JITLink/x86-64/lit.local.cfg
index 42bf50dcc13c35..d5a1ad626b657d 100644
--- a/llvm/test/ExecutionEngine/JITLink/x86-64/lit.local.cfg
+++ b/llvm/test/ExecutionEngine/JITLink/x86-64/lit.local.cfg
@@ -1,2 +1,5 @@
 if not "X86" in config.root.targets:
     config.unsupported = True
+
+if config.llvm_use_intel_jitevents:
+    config.available_features.add("intel-jitevents")

diff  --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
index f0b8310a32efd3..09b2a5900eb0b7 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
@@ -21,6 +21,7 @@
 #include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"
 #include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupportPlugin.h"
 #include "llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h"
+#include "llvm/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.h"
 #include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h"
 #include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
 #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
@@ -34,6 +35,7 @@
 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
 #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
 #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderPerf.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.h"
 #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCContext.h"
@@ -148,6 +150,10 @@ static cl::opt<bool> PerfSupport("perf-support",
                                  cl::init(false), cl::Hidden,
                                  cl::cat(JITLinkCategory));
 
+static cl::opt<bool> VTuneSupport("vtune-support",
+                                  cl::desc("Enable vtune profiling support"),
+                                  cl::init(false), cl::Hidden,
+                                  cl::cat(JITLinkCategory));
 static cl::opt<bool>
     NoProcessSymbols("no-process-syms",
                      cl::desc("Do not resolve to llvm-jitlink process symbols"),
@@ -264,7 +270,10 @@ static LLVM_ATTRIBUTE_USED void linkComponents() {
          << (void *)&llvm_orc_registerJITLoaderGDBAllocAction << '\n'
          << (void *)&llvm_orc_registerJITLoaderPerfStart << '\n'
          << (void *)&llvm_orc_registerJITLoaderPerfEnd << '\n'
-         << (void *)&llvm_orc_registerJITLoaderPerfImpl << '\n';
+         << (void *)&llvm_orc_registerJITLoaderPerfImpl << '\n'
+         << (void *)&llvm_orc_registerVTuneImpl << '\n'
+         << (void *)&llvm_orc_unregisterVTuneImpl << '\n'
+         << (void *)&llvm_orc_test_registerVTuneImpl << '\n';
 }
 
 static bool UseTestResultOverride = false;
@@ -1004,6 +1013,14 @@ Session::Session(std::unique_ptr<ExecutorProcessControl> EPC, Error &Err)
         this->ES.getExecutorProcessControl(), *ProcessSymsJD, true, true)));
   }
 
+  if (VTuneSupport && TT.isOSBinFormatELF()) {
+    ObjLayer.addPlugin(ExitOnErr(DebugInfoPreservationPlugin::Create()));
+    ObjLayer.addPlugin(ExitOnErr(
+        VTuneSupportPlugin::Create(this->ES.getExecutorProcessControl(),
+                                   *ProcessSymsJD, /*EmitDebugInfo=*/true,
+                                   /*TestMode=*/true)));
+  }
+
   // Set up the platform.
   if (!OrcRuntime.empty()) {
     assert(ProcessSymsJD && "ProcessSymsJD should have been set");


        


More information about the llvm-commits mailing list