forked from OSchip/llvm-project
[xray] Function coverage groups
Add the ability to selectively instrument a subset of functions by dividing the functions into N logical groups and then selecting a group to cover. By selecting different groups over time you could cover the entire application incrementally with lower overhead than instrumenting the entire application at once. Differential Revision: https://reviews.llvm.org/D87953
This commit is contained in:
parent
8c98c88034
commit
6f7fbdd285
|
@ -120,6 +120,12 @@ CODEGENOPT(XRayOmitFunctionIndex , 1, 0)
|
|||
///< XRay instrumentation.
|
||||
VALUE_CODEGENOPT(XRayInstructionThreshold , 32, 200)
|
||||
|
||||
///< Only instrument 1 in N functions, by dividing functions into N total groups and
|
||||
///< instrumenting only the specified group at a time. Group numbers start at 0
|
||||
///< and end at N-1.
|
||||
VALUE_CODEGENOPT(XRayTotalFunctionGroups, 32, 1)
|
||||
VALUE_CODEGENOPT(XRaySelectedFunctionGroup, 32, 0)
|
||||
|
||||
VALUE_CODEGENOPT(PatchableFunctionEntryCount , 32, 0) ///< Number of NOPs at function entry
|
||||
VALUE_CODEGENOPT(PatchableFunctionEntryOffset , 32, 0)
|
||||
|
||||
|
|
|
@ -1339,6 +1339,17 @@ def fxray_instrumentation_bundle :
|
|||
Group<f_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Select which XRay instrumentation points to emit. Options: all, none, function-entry, function-exit, function, custom. Default is 'all'. 'function' includes both 'function-entry' and 'function-exit'.">;
|
||||
|
||||
def fxray_function_groups :
|
||||
Joined<["-"], "fxray-function-groups=">,
|
||||
Group<f_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Only instrument 1 of N groups">;
|
||||
|
||||
def fxray_selected_function_group :
|
||||
Joined<["-"], "fxray-selected-function-group=">,
|
||||
Group<f_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"When using -fxray-function-groups, select which group of functions to instrument. Valid range is 0 to fxray-function-groups - 1">;
|
||||
|
||||
|
||||
def ffine_grained_bitfield_accesses : Flag<["-"],
|
||||
"ffine-grained-bitfield-accesses">, Group<f_clang_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Use separate accesses for consecutive bitfield runs with legal widths and alignments.">;
|
||||
|
|
|
@ -32,6 +32,8 @@ class XRayArgs {
|
|||
bool XRayRT = true;
|
||||
bool XRayIgnoreLoops = false;
|
||||
bool XRayFunctionIndex;
|
||||
int XRayFunctionGroups = 1;
|
||||
int XRaySelectedFunctionGroup;
|
||||
|
||||
public:
|
||||
/// Parses the XRay arguments from an argument list.
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/CodeGen/CGFunctionInfo.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
|
@ -40,6 +41,7 @@
|
|||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/MDBuilder.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/Support/CRC.h"
|
||||
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
@ -772,13 +774,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
|
|||
SanOpts.Mask &= ~SanitizerKind::Null;
|
||||
|
||||
// Apply xray attributes to the function (as a string, for now)
|
||||
bool AlwaysXRayAttr = false;
|
||||
if (const auto *XRayAttr = D ? D->getAttr<XRayInstrumentAttr>() : nullptr) {
|
||||
if (CGM.getCodeGenOpts().XRayInstrumentationBundle.has(
|
||||
XRayInstrKind::FunctionEntry) ||
|
||||
CGM.getCodeGenOpts().XRayInstrumentationBundle.has(
|
||||
XRayInstrKind::FunctionExit)) {
|
||||
if (XRayAttr->alwaysXRayInstrument() && ShouldXRayInstrumentFunction())
|
||||
if (XRayAttr->alwaysXRayInstrument() && ShouldXRayInstrumentFunction()) {
|
||||
Fn->addFnAttr("function-instrument", "xray-always");
|
||||
AlwaysXRayAttr = true;
|
||||
}
|
||||
if (XRayAttr->neverXRayInstrument())
|
||||
Fn->addFnAttr("function-instrument", "xray-never");
|
||||
if (const auto *LogArgs = D->getAttr<XRayLogArgsAttr>())
|
||||
|
@ -804,6 +809,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
|
|||
if (!CGM.getCodeGenOpts().XRayInstrumentationBundle.has(
|
||||
XRayInstrKind::FunctionEntry))
|
||||
Fn->addFnAttr("xray-skip-entry");
|
||||
|
||||
auto FuncGroups = CGM.getCodeGenOpts().XRayTotalFunctionGroups;
|
||||
if (FuncGroups > 1) {
|
||||
auto FuncName = llvm::makeArrayRef<uint8_t>(
|
||||
CurFn->getName().bytes_begin(), CurFn->getName().bytes_end());
|
||||
auto Group = crc32(FuncName) % FuncGroups;
|
||||
if (Group != CGM.getCodeGenOpts().XRaySelectedFunctionGroup &&
|
||||
!AlwaysXRayAttr)
|
||||
Fn->addFnAttr("function-instrument", "xray-never");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned Count, Offset;
|
||||
|
|
|
@ -186,6 +186,21 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
|
|||
Modes.push_back(std::string(M));
|
||||
}
|
||||
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_fxray_function_groups)) {
|
||||
StringRef S = A->getValue();
|
||||
if (S.getAsInteger(0, XRayFunctionGroups) || XRayFunctionGroups < 1)
|
||||
D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
|
||||
}
|
||||
|
||||
if (const Arg *A =
|
||||
Args.getLastArg(options::OPT_fxray_selected_function_group)) {
|
||||
StringRef S = A->getValue();
|
||||
if (S.getAsInteger(0, XRaySelectedFunctionGroup) ||
|
||||
XRaySelectedFunctionGroup < 0 ||
|
||||
XRaySelectedFunctionGroup >= XRayFunctionGroups)
|
||||
D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
|
||||
}
|
||||
|
||||
// Then we want to sort and unique the modes we've collected.
|
||||
llvm::sort(Modes);
|
||||
Modes.erase(std::unique(Modes.begin(), Modes.end()), Modes.end());
|
||||
|
@ -210,6 +225,17 @@ void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args,
|
|||
if (!XRayFunctionIndex)
|
||||
CmdArgs.push_back("-fno-xray-function-index");
|
||||
|
||||
if (XRayFunctionGroups > 1) {
|
||||
CmdArgs.push_back(Args.MakeArgString(Twine("-fxray-function-groups=") +
|
||||
Twine(XRayFunctionGroups)));
|
||||
}
|
||||
|
||||
if (XRaySelectedFunctionGroup != 0) {
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString(Twine("-fxray-selected-function-group=") +
|
||||
Twine(XRaySelectedFunctionGroup)));
|
||||
}
|
||||
|
||||
CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) +
|
||||
Twine(InstructionThreshold)));
|
||||
|
||||
|
|
|
@ -1130,6 +1130,10 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
|
|||
getLastArgIntValue(Args, OPT_fxray_instruction_threshold_EQ, 200, Diags);
|
||||
Opts.XRayIgnoreLoops = Args.hasArg(OPT_fxray_ignore_loops);
|
||||
Opts.XRayOmitFunctionIndex = Args.hasArg(OPT_fno_xray_function_index);
|
||||
Opts.XRayTotalFunctionGroups =
|
||||
getLastArgIntValue(Args, OPT_fxray_function_groups, 1, Diags);
|
||||
Opts.XRaySelectedFunctionGroup =
|
||||
getLastArgIntValue(Args, OPT_fxray_selected_function_group, 0, Diags);
|
||||
|
||||
auto XRayInstrBundles =
|
||||
Args.getAllArgValues(OPT_fxray_instrumentation_bundle);
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
// RUN: %clang_cc1 -fxray-instrument -fxray-instruction-threshold=1 -fxray-function-groups=3 -fxray-selected-function-group=0 \
|
||||
// RUN: -emit-llvm -o - %s -triple x86_64-unknown-linux-gnu | FileCheck --check-prefix=GROUP0 %s
|
||||
|
||||
// RUN: %clang_cc1 -fxray-instrument -fxray-instruction-threshold=1 -fxray-function-groups=3 -fxray-selected-function-group=1 \
|
||||
// RUN: -emit-llvm -o - %s -triple x86_64-unknown-linux-gnu | FileCheck --check-prefix=GROUP1 %s
|
||||
|
||||
// RUN: %clang_cc1 -fxray-instrument -fxray-instruction-threshold=1 -fxray-function-groups=3 -fxray-selected-function-group=2 \
|
||||
// RUN: -emit-llvm -o - %s -triple x86_64-unknown-linux-gnu | FileCheck --check-prefix=GROUP2 %s
|
||||
|
||||
static int foo() { // part of group 0
|
||||
return 1;
|
||||
}
|
||||
|
||||
int bar() { // part of group 2
|
||||
return 1;
|
||||
}
|
||||
|
||||
int yarr() { // part of group 1
|
||||
foo();
|
||||
return 1;
|
||||
}
|
||||
|
||||
[[clang::xray_always_instrument]] int always() { // part of group 0
|
||||
return 1;
|
||||
}
|
||||
|
||||
[[clang::xray_never_instrument]] int never() { // part of group 1
|
||||
return 1;
|
||||
}
|
||||
|
||||
// GROUP0: define{{.*}} i32 @_Z3barv() #[[ATTRS_BAR:[0-9]+]] {
|
||||
// GROUP0: define{{.*}} i32 @_Z4yarrv() #[[ATTRS_BAR]] {
|
||||
// GROUP0: define{{.*}} i32 @_ZL3foov() #[[ATTRS_FOO:[0-9]+]] {
|
||||
// GROUP0: define{{.*}} i32 @_Z6alwaysv() #[[ATTRS_ALWAYS:[0-9]+]] {
|
||||
// GROUP0: define{{.*}} i32 @_Z5neverv() #[[ATTRS_NEVER:[0-9]+]] {
|
||||
// GROUP0-DAG: attributes #[[ATTRS_BAR]] = {{.*}} "function-instrument"="xray-never" {{.*}}
|
||||
// GROUP0-DAG: attributes #[[ATTRS_ALWAYS]] = {{.*}} "function-instrument"="xray-always" {{.*}}
|
||||
// GROUP0-DAG: attributes #[[ATTRS_NEVER]] = {{.*}} "function-instrument"="xray-never" {{.*}}
|
||||
|
||||
// GROUP1: define{{.*}} i32 @_Z3barv() #[[ATTRS_BAR:[0-9]+]] {
|
||||
// GROUP1: define{{.*}} i32 @_Z4yarrv() #[[ATTRS_YARR:[0-9]+]] {
|
||||
// GROUP1: define{{.*}} i32 @_ZL3foov() #[[ATTRS_BAR]] {
|
||||
// GROUP1: define{{.*}} i32 @_Z6alwaysv() #[[ATTRS_ALWAYS:[0-9]+]] {
|
||||
// GROUP1: define{{.*}} i32 @_Z5neverv() #[[ATTRS_NEVER:[0-9]+]] {
|
||||
// GROUP1-DAG: attributes #[[ATTRS_BAR]] = {{.*}} "function-instrument"="xray-never" {{.*}}
|
||||
// GROUP1-DAG: attributes #[[ATTRS_ALWAYS]] = {{.*}} "function-instrument"="xray-always" {{.*}}
|
||||
// GROUP1-DAG: attributes #[[ATTRS_NEVER]] = {{.*}} "function-instrument"="xray-never" {{.*}}
|
||||
|
||||
// GROUP2: define{{.*}} i32 @_Z3barv() #[[ATTRS_BAR:[0-9]+]] {
|
||||
// GROUP2: define{{.*}} i32 @_Z4yarrv() #[[ATTRS_YARR:[0-9]+]] {
|
||||
// GROUP2: define{{.*}} i32 @_ZL3foov() #[[ATTRS_YARR]] {
|
||||
// GROUP2: define{{.*}} i32 @_Z6alwaysv() #[[ATTRS_ALWAYS:[0-9]+]] {
|
||||
// GROUP2: define{{.*}} i32 @_Z5neverv() #[[ATTRS_NEVER:[0-9]+]] {
|
||||
// GROUP2-DAG: attributes #[[ATTRS_YARR]] = {{.*}} "function-instrument"="xray-never" {{.*}}
|
||||
// GROUP2-DAG: attributes #[[ATTRS_ALWAYS]] = {{.*}} "function-instrument"="xray-always" {{.*}}
|
||||
// GROUP2-DAG: attributes #[[ATTRS_NEVER]] = {{.*}} "function-instrument"="xray-never" {{.*}}
|
|
@ -62,17 +62,18 @@ For example:
|
|||
|
||||
clang -fxray-instrument ...
|
||||
|
||||
By default, functions that have at least 200 instructions will get XRay
|
||||
instrumentation points. You can tweak that number through the
|
||||
By default, functions that have at least 200 instructions (or contain a loop) will
|
||||
get XRay instrumentation points. You can tweak that number through the
|
||||
``-fxray-instruction-threshold=`` flag:
|
||||
|
||||
::
|
||||
|
||||
clang -fxray-instrument -fxray-instruction-threshold=1 ...
|
||||
|
||||
You can also specifically instrument functions in your binary to either always
|
||||
or never be instrumented using source-level attributes. You can do it using the
|
||||
GCC-style attributes or C++11-style attributes.
|
||||
The loop detection can be disabled with ``-fxray-ignore-loops`` to use only the
|
||||
instruction threshold. You can also specifically instrument functions in your
|
||||
binary to either always or never be instrumented using source-level attributes.
|
||||
You can do it using the GCC-style attributes or C++11-style attributes.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
@ -309,6 +310,35 @@ libraries, distributed with the LLVM distribution. These are:
|
|||
instrumentation map in XRay-instrumented object files and binaries. The
|
||||
``extract`` and ``stack`` subcommands uses this particular library.
|
||||
|
||||
|
||||
Minimizing Binary Size
|
||||
----------------------
|
||||
|
||||
XRay supports several different instrumentation points including ``function-entry``,
|
||||
``function-exit``, ``custom``, and ``typed`` points. These can be enabled individually
|
||||
using the ``-fxray-instrumentaton-bundle=`` flag. For example if you only wanted to
|
||||
instrument function entry and custom points you could specify:
|
||||
|
||||
::
|
||||
|
||||
clang -fxray-instrument -fxray-instrumentation-bundle=function-entry,custom ...
|
||||
|
||||
This will omit the other sled types entirely, reducing the binary size. You can also
|
||||
instrument just a sampled subset of functions using instrumentation groups.
|
||||
For example, to instrument only a quarter of available functions invoke:
|
||||
|
||||
::
|
||||
|
||||
clang -fxray-instrument -fxray-function-groups=4
|
||||
|
||||
A subset will be chosen arbitrarily based on a hash of the function name. To sample a
|
||||
different subset you can specify ``-fxray-selected-function-group=`` with a group number
|
||||
in the range of 0 to ``xray-function-groups`` - 1. Together these options could be used
|
||||
to produce multiple binaries with different instrumented subsets. If all you need is
|
||||
runtime control over which functions are being traced at any given time it is better
|
||||
to selectively patch and unpatch the individual functions you need using the XRay
|
||||
Runtime Library's ``__xray_patch_function()`` method.
|
||||
|
||||
Future Work
|
||||
===========
|
||||
|
||||
|
|
Loading…
Reference in New Issue