Add basic clang-like support for XRay, through -fxray-instrument and -fxray-instruction-threshold=. (#2465)

Currently only fully working on Linux.
See https://llvm.org/docs/XRay.html
This commit is contained in:
Johan Engelen 2018-01-23 22:06:05 +01:00 committed by GitHub
parent 43c02cecc0
commit 1da088330d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 148 additions and 0 deletions

View file

@ -767,9 +767,13 @@ if (LDC_INSTALL_LLVM_RUNTIME_LIBS)
copy_compilerrt_lib("darwin/libclang_rt.asan_osx_dynamic.dylib" "libldc_rt.asan_osx_dynamic.dylib" TRUE) copy_compilerrt_lib("darwin/libclang_rt.asan_osx_dynamic.dylib" "libldc_rt.asan_osx_dynamic.dylib" TRUE)
if(NOT (LDC_LLVM_VER LESS 600)) if(NOT (LDC_LLVM_VER LESS 600))
copy_compilerrt_lib("darwin/libclang_rt.fuzzer_osx.a" "libldc_rt.fuzzer_osx.a" FALSE) copy_compilerrt_lib("darwin/libclang_rt.fuzzer_osx.a" "libldc_rt.fuzzer_osx.a" FALSE)
copy_compilerrt_lib("darwin/libclang_rt.xray_osx.a" "libldc_rt.xray_osx.a" FALSE)
endif() endif()
elseif(UNIX) elseif(UNIX)
copy_compilerrt_lib("linux/libclang_rt.asan-x86_64.a" "libldc_rt.asan-x86_64.a" FALSE) copy_compilerrt_lib("linux/libclang_rt.asan-x86_64.a" "libldc_rt.asan-x86_64.a" FALSE)
if(NOT (LDC_LLVM_VER LESS 500))
copy_compilerrt_lib("linux/libclang_rt.xray-x86_64.a" "libldc_rt.xray-x86_64.a" FALSE)
endif()
if(NOT (LDC_LLVM_VER LESS 600)) if(NOT (LDC_LLVM_VER LESS 600))
copy_compilerrt_lib("linux/libclang_rt.fuzzer-x86_64.a" "libldc_rt.fuzzer-x86_64.a" FALSE) copy_compilerrt_lib("linux/libclang_rt.fuzzer-x86_64.a" "libldc_rt.fuzzer-x86_64.a" FALSE)
endif() endif()

View file

@ -17,6 +17,7 @@
#include "errors.h" #include "errors.h"
#include "globals.h" #include "globals.h"
#include "gen/to_string.h"
#include "llvm/ADT/Triple.h" #include "llvm/ADT/Triple.h"
namespace { namespace {
@ -52,6 +53,15 @@ cl::opt<std::string> ASTPGOInstrUseFile(
cl::desc("Use instrumentation data for profile-guided optimization"), cl::desc("Use instrumentation data for profile-guided optimization"),
cl::ValueRequired); cl::ValueRequired);
#if LDC_LLVM_VER >= 500
cl::opt<int> fXRayInstructionThreshold(
"fxray-instruction-threshold", cl::value_desc("value"),
cl::desc("Sets the minimum function size to instrument with XRay"),
cl::init(200), cl::ZeroOrMore, cl::ValueRequired);
#else
constexpr int fXRayInstructionThreshold = 200;
#endif
} // anonymous namespace } // anonymous namespace
namespace opts { namespace opts {
@ -68,6 +78,20 @@ static cl::opt<bool> dmdFunctionTrace(
"fdmd-trace-functions", cl::ZeroOrMore, "fdmd-trace-functions", cl::ZeroOrMore,
cl::desc("DMD-style runtime performance profiling of generated code")); cl::desc("DMD-style runtime performance profiling of generated code"));
#if LDC_LLVM_VER >= 500
cl::opt<bool> fXRayInstrument(
"fxray-instrument", cl::ZeroOrMore,
cl::desc("Generate XRay instrumentation sleds on function entry and exit"));
#endif
llvm::StringRef getXRayInstructionThresholdString() {
// The instruction threshold is constant during one compiler invoke, so we
// can cache the int->string conversion result.
static std::string thresholdString =
ldc::to_string(fXRayInstructionThreshold);
return thresholdString;
}
void initializeInstrumentationOptionsFromCmdline(const llvm::Triple &triple) { void initializeInstrumentationOptionsFromCmdline(const llvm::Triple &triple) {
if (ASTPGOInstrGenFile.getNumOccurrences() > 0) { if (ASTPGOInstrGenFile.getNumOccurrences() > 0) {
pgoMode = PGO_ASTBasedInstr; pgoMode = PGO_ASTBasedInstr;

View file

@ -27,6 +27,13 @@ namespace cl = llvm::cl;
extern cl::opt<bool> instrumentFunctions; extern cl::opt<bool> instrumentFunctions;
#if LDC_LLVM_VER >= 500
extern cl::opt<bool> fXRayInstrument;
#else
constexpr bool fXRayInstrument = false;
#endif
llvm::StringRef getXRayInstructionThresholdString();
/// This initializes the instrumentation options, and checks the validity of the /// This initializes the instrumentation options, and checks the validity of the
/// commandline flags. targetTriple should be initialized before calling this. /// commandline flags. targetTriple should be initialized before calling this.
/// It should be called only once. /// It should be called only once.

View file

@ -53,6 +53,7 @@ private:
virtual void addASanLinkFlags(const llvm::Triple &triple); virtual void addASanLinkFlags(const llvm::Triple &triple);
virtual void addFuzzLinkFlags(const llvm::Triple &triple); virtual void addFuzzLinkFlags(const llvm::Triple &triple);
virtual void addCppStdlibLinkFlags(const llvm::Triple &triple); virtual void addCppStdlibLinkFlags(const llvm::Triple &triple);
virtual void addXRayLinkFlags(const llvm::Triple &triple);
virtual void addLinker(); virtual void addLinker();
virtual void addUserSwitches(); virtual void addUserSwitches();
@ -312,6 +313,32 @@ void ArgsBuilder::addFuzzLinkFlags(const llvm::Triple &triple) {
} }
} }
// Adds all required link flags for -fxray-instrument when the xray library is
// found.
void ArgsBuilder::addXRayLinkFlags(const llvm::Triple &triple) {
std::string searchPaths[] = {
getFullCompilerRTLibPath(triple, "libldc_rt.xray"),
getFullCompilerRTLibPath(triple, "libclang_rt.xray"),
getFullClangCompilerRTLibPath(triple, "libclang_rt.xray"),
};
bool linkerDarwin = triple.isOSDarwin();
if (!triple.isOSLinux())
warning(Loc(), "XRay is not (fully) supported on non-Linux target OS.");
for (const auto &filepath : searchPaths) {
if (!linkerDarwin)
addLdFlag("--whole-archive");
args.push_back(filepath);
if (!linkerDarwin)
addLdFlag("--no-whole-archive");
return;
}
}
void ArgsBuilder::addCppStdlibLinkFlags(const llvm::Triple &triple) { void ArgsBuilder::addCppStdlibLinkFlags(const llvm::Triple &triple) {
if (linkNoCpp) if (linkNoCpp)
return; return;
@ -410,6 +437,10 @@ void ArgsBuilder::build(llvm::StringRef outputPath,
addSanitizers(*global.params.targetTriple); addSanitizers(*global.params.targetTriple);
if (opts::fXRayInstrument) {
addXRayLinkFlags(*global.params.targetTriple);
}
#if LDC_LLVM_VER >= 309 #if LDC_LLVM_VER >= 309
// Add LTO link flags before adding the user link switches, such that the user // Add LTO link flags before adding the user link switches, such that the user
// can pass additional options to the LTO plugin. // can pass additional options to the LTO plugin.

View file

@ -19,6 +19,7 @@
#include "statement.h" #include "statement.h"
#include "template.h" #include "template.h"
#include "driver/cl_options.h" #include "driver/cl_options.h"
#include "driver/cl_options_instrumentation.h"
#include "driver/cl_options_sanitizers.h" #include "driver/cl_options_sanitizers.h"
#include "gen/abi.h" #include "gen/abi.h"
#include "gen/arrays.h" #include "gen/arrays.h"
@ -463,6 +464,18 @@ void applyTargetMachineAttributes(llvm::Function &func,
willEliminateFramePointer() ? "false" : "true"); willEliminateFramePointer() ? "false" : "true");
} }
void applyXRayAttributes(FuncDeclaration &fdecl, llvm::Function &func) {
if (!opts::fXRayInstrument)
return;
if (!fdecl.emitInstrumentation) {
func.addFnAttr("function-instrument", "xray-never");
} else {
func.addFnAttr("xray-instruction-threshold",
opts::getXRayInstructionThresholdString());
}
}
} // anonymous namespace } // anonymous namespace
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1010,6 +1023,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
func->addFnAttr(LLAttribute::SanitizeThread); func->addFnAttr(LLAttribute::SanitizeThread);
} }
} }
applyXRayAttributes(*fd, *func);
llvm::BasicBlock *beginbb = llvm::BasicBlock *beginbb =
llvm::BasicBlock::Create(gIR->context(), "", func); llvm::BasicBlock::Create(gIR->context(), "", func);

View file

@ -0,0 +1,10 @@
import os
import platform
import re
# Add "XRay_RT" feature if the runtime library is available
for file in os.listdir(config.ldc2_lib_dir):
m = re.match('.*xray.*', file)
if m is not None:
config.available_features.add('XRay')
continue

View file

@ -0,0 +1,11 @@
// Check that the LLVM pipeline is set up correctly to generate XRay sleds.
// If we have the XRay runtime lib for this platform, then we can also do machinecodegen:
// REQUIRES: XRay_RT
// RUN: %ldc -c -output-s -betterC -fxray-instrument -fxray-instruction-threshold=1 -of=%t.s %s && FileCheck %s < %t.s
// CHECK: xray_sled
void instrument()
{
}

View file

@ -0,0 +1,21 @@
// REQUIRES: atleast_llvm500
// RUN: %ldc -c -output-ll -fxray-instrument -of=%t.ll %s && FileCheck %s < %t.ll
import ldc.attributes;
// CHECK-LABEL: define{{.*}} @{{.*}}10instrument
// CHECK-SAME: #[[INSTR:[0-9]+]]
void instrument()
{
}
// CHECK-LABEL: define{{.*}} @{{.*}}15dont_instrument
// CHECK-SAME: #[[DONT_INSTR:[0-9]+]]
void dont_instrument()
{
pragma(LDC_profile_instr, false);
}
// CHECK-DAG: attributes #[[INSTR]] ={{.*}} "xray-instruction-threshold"=
// CHECK-DAG: attributes #[[DONT_INSTR]] ={{.*}} "function-instrument"="xray-never"

View file

@ -0,0 +1,11 @@
// REQUIRES: atleast_llvm500
// RUN: %ldc -c -output-ll -fxray-instrument -fxray-instruction-threshold=543 -of=%t.ll %s && FileCheck %s < %t.ll
// CHECK-LABEL: define{{.*}} @{{.*}}10instrument
// CHECK-SAME: #[[INSTR:[0-9]+]]
void instrument()
{
}
// CHECK-DAG: attributes #[[INSTR]] ={{.*}} "xray-instruction-threshold"="543"

View file

@ -0,0 +1,15 @@
// REQUIRES: XRay_RT
// RUN: %ldc -fxray-instrument -fxray-instruction-threshold=1 -of=%t%exe %s -vv | FileCheck %s
void foo()
{
}
void main()
{
foo();
}
// CHECK: Linking with:
// CHECK-NEXT: rt.xray