Skip to content

Commit 7278ec6

Browse files
committed
[cling] Enable JITLink debugging and profiling support
`CLING_PROFILE=1` enables perf profiling using `jitdump` format. Profiling now requires a `perf inject` step (with JITLink): ``` perf record -k 1 <cling> perf inject -j -i perf.data -o perf.jitted.data perf report -i perf.jitted.data ```
1 parent 451b70e commit 7278ec6

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

interpreter/cling/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,26 @@ or
119119
[cling]$ .help
120120
```
121121

122+
Debugging and Profiling JITted Code
123+
-----------------------------------
124+
125+
Cling provides support for debugging and profiling interpreted (JITted) code.
126+
- `CLING_DEBUG=1` enables debug symbol emission on interpreted code, allowing
127+
the use of a standard debugger. Debugging is aided by switching off
128+
optimisations and adding frame pointers for better stack traces.
129+
- `CLING_PROFILE=1` enables perf profiling:
130+
- When `jitlink` is enabled (`CLING_JITLINK=1`, soon the default), profiling
131+
requires a [`perf inject`](https://linux.die.net/man/1/perf-inject) step:
132+
```bash
133+
perf record -k 1 <cling>
134+
perf inject -j -i perf.data -o perf.jitted.data
135+
perf report -i perf.jitted.data
136+
```
137+
- When `jitlink` is disabled, perf support is enabled with "perf map" (legacy)
138+
instead of "JIT dump" and there is no need for an inject step.
139+
140+
Debugging and Profiling, both have a runtime cost, and is therefore disabled by
141+
default.
122142

123143
Jupyter
124144
-------

interpreter/cling/lib/Interpreter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ set(LLVM_LINK_COMPONENTS
4848
object
4949
option
5050
orcjit
51+
orcdebugging
5152
runtimedyld
5253
scalaropts
5354
support

interpreter/cling/lib/Interpreter/IncrementalJIT.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@
1919
#include <clang/Basic/TargetOptions.h>
2020
#include <clang/Frontend/CompilerInstance.h>
2121

22+
#include <llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h>
23+
#include <llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h>
24+
#include <llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h>
2225
#include <llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h>
2326
#include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>
2427
#include <llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h>
28+
#include <llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderPerf.h>
2529
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
2630
#include <llvm/IR/LLVMContext.h>
2731
#include <llvm/MC/TargetRegistry.h>
@@ -40,7 +44,57 @@ using namespace llvm;
4044
using namespace llvm::jitlink;
4145
using namespace llvm::orc;
4246

47+
static LLVM_ATTRIBUTE_USED void linkComponents() {
48+
errs() << "Linking in runtime functions\n"
49+
<< (void*)&llvm_orc_registerJITLoaderPerfStart << '\n'
50+
<< (void*)&llvm_orc_registerJITLoaderPerfEnd << '\n'
51+
<< (void*)&llvm_orc_registerJITLoaderPerfImpl << '\n';
52+
}
53+
4354
namespace {
55+
// This could potentially be upstreamed, similar to enableDebuggerSupport()
56+
Error enablePerfSupport(LLJIT& J) {
57+
auto* ObjLinkingLayer =
58+
dyn_cast<ObjectLinkingLayer>(&J.getObjLinkingLayer());
59+
if (!ObjLinkingLayer)
60+
return make_error<StringError>("Cannot enable LLJIT perf support: "
61+
"perf support requires JITLink",
62+
inconvertibleErrorCode());
63+
auto ProcessSymsJD = J.getProcessSymbolsJITDylib();
64+
if (!ProcessSymsJD)
65+
return make_error<StringError>("Cannot enable LLJIT perf support: "
66+
"Process symbols are not available",
67+
inconvertibleErrorCode());
68+
69+
auto& ES = J.getExecutionSession();
70+
const auto& TT = J.getTargetTriple();
71+
72+
switch (TT.getObjectFormat()) {
73+
case Triple::ELF: {
74+
auto debugInfoPreservationPlugin =
75+
DebugInfoPreservationPlugin::Create();
76+
if (!debugInfoPreservationPlugin)
77+
return debugInfoPreservationPlugin.takeError();
78+
79+
auto perfSupportPlugin =
80+
PerfSupportPlugin::Create(ES.getExecutorProcessControl(),
81+
*ProcessSymsJD, true, true);
82+
if (!perfSupportPlugin)
83+
return perfSupportPlugin.takeError();
84+
85+
ObjLinkingLayer->addPlugin(std::move(*debugInfoPreservationPlugin));
86+
ObjLinkingLayer->addPlugin(std::move(*perfSupportPlugin));
87+
88+
return Error::success();
89+
}
90+
default:
91+
return make_error<StringError>("Cannot enable LLJIT perf support: " +
92+
Triple::getObjectFormatTypeName(
93+
TT.getObjectFormat()) +
94+
" is not supported",
95+
inconvertibleErrorCode());
96+
}
97+
}
4498

4599
class ClingMMapper final : public SectionMemoryManager::MemoryMapper {
46100
public:
@@ -491,6 +545,18 @@ IncrementalJIT::IncrementalJIT(
491545
Builder.setDataLayout(m_TM->createDataLayout());
492546
Builder.setExecutorProcessControl(std::move(EPC));
493547

548+
if (m_JITLink) {
549+
Builder.setPrePlatformSetup([](llvm::orc::LLJIT& J) {
550+
// Try to enable debugging of JIT'd code (only works with JITLink for
551+
// ELF and MachO).
552+
if (cling::utils::ConvertEnvValueToBool(std::getenv("CLING_DEBUG")))
553+
consumeError(enableDebuggerSupport(J));
554+
if (cling::utils::ConvertEnvValueToBool(std::getenv("CLING_PROFILE")))
555+
consumeError(enablePerfSupport(J));
556+
return llvm::Error::success();
557+
});
558+
}
559+
494560
// Create ObjectLinkingLayer with our own MemoryManager.
495561
Builder.setObjectLinkingLayerCreator([&](ExecutionSession& ES,
496562
const Triple& TT)

0 commit comments

Comments
 (0)