Compare commits

..

1 Commits

Author SHA1 Message Date
Matt Arsenault
ae56b6712d RuntimeLibcalls: Add entries for stackprotector globals
Add entries for_stack_chk_guard, __ssp_canary_word, __security_cookie,
and __guard_local. As far as I can tell these are all just different
names for the same shaped functionality on different systems.

These aren't really functions, but special global variable names. They
should probably be treated the same way; all the same contexts that
need to know about emittable function names also need to know about
this. This avoids a special case check in IRSymtab.

This isn't a complete change, there's a lot more cleanup which
should be done. The stack protector configuration system is a
complete mess. There are multiple overlapping controls, used in
3 different places. Some of the target control implementations overlap
with conditions used in the emission points, and some use correlated
but not identical conditions in different contexts.

i.e. useLoadStackGuardNode, getIRStackGuard, getSSPStackGuardCheck and
insertSSPDeclarations are all used in inconsistent ways so I don't know
if I've tracked the intention of the system correctly.

The PowerPC test change is a bug fix on linux. Previously the manual
conditions were based around !isOSOpenBSD, which is not the condition
where __stack_chk_guard are used. Now getSDagStackGuard returns the
proper global reference, resulting in LOAD_STACK_GUARD getting a
MachineMemOperand which allows scheduling.
2025-08-22 20:18:30 +09:00
63 changed files with 226 additions and 7407 deletions

View File

@ -280,7 +280,6 @@ set(TARGET_LIBC_ENTRYPOINTS
set(TARGET_LIBM_ENTRYPOINTS
# math.h entrypoints
libc.src.math.acos
libc.src.math.acosf
libc.src.math.acoshf
libc.src.math.asin

View File

@ -2432,6 +2432,14 @@ functions:
return_type: double
arguments:
- type: double
- name: sincosf
standards:
- gnu
return_type: void
arguments:
- type: float
- type: float *
- type: float *
- name: sinf
standards:
- stdc
@ -2445,22 +2453,6 @@ functions:
arguments:
- type: _Float16
guard: LIBC_TYPES_HAS_FLOAT16
- name: sincos
standards:
- gnu
return_type: void
arguments:
- type: double
- type: double *
- type: double *
- name: sincosf
standards:
- gnu
return_type: void
arguments:
- type: float
- type: float *
- type: float *
- name: sinhf
standards:
- stdc

View File

@ -21,6 +21,7 @@ def isOSOpenBSD : RuntimeLibcallPredicate<"TT.isOSOpenBSD()">;
def isNotOSOpenBSD : RuntimeLibcallPredicate<"!TT.isOSOpenBSD()">;
def isOSWindows : RuntimeLibcallPredicate<"TT.isOSWindows()">;
def isNotOSWindows : RuntimeLibcallPredicate<"!TT.isOSWindows()">;
def isNotOSLinux : RuntimeLibcallPredicate<[{!TT.isOSLinux()}]>;
def isNotOSMSVCRT : RuntimeLibcallPredicate<"!TT.isOSMSVCRT()">;
def isPS : RuntimeLibcallPredicate<"TT.isPS()">;
def isNotOSWindowsOrIsCygwinMinGW
@ -28,6 +29,12 @@ def isNotOSWindowsOrIsCygwinMinGW
def isWindowsMSVCEnvironment : RuntimeLibcallPredicate<
[{TT.isWindowsMSVCEnvironment()}]>;
def isNotOSLinuxAndNotOSOpenBSD : RuntimeLibcallPredicate<
[{!TT.isOSLinux() && !TT.isOSOpenBSD()}]>;
def isWindowsMSVCOrItaniumEnvironment : RuntimeLibcallPredicate<
[{TT.isWindowsMSVCEnvironment() || TT.isWindowsItaniumEnvironment()}]>;
def isGNUEnvironment : RuntimeLibcallPredicate<"TT.isGNUEnvironment()">;
def darwinHasSinCosStret : RuntimeLibcallPredicate<"darwinHasSinCosStret(TT)">;
def darwinHasExp10 : RuntimeLibcallPredicate<"darwinHasExp10(TT)">;
@ -471,6 +478,16 @@ def OBJC_RETAIN_AUTORELEASE : RuntimeLibcall;
def OBJC_SYNC_ENTER : RuntimeLibcall;
def OBJC_SYNC_EXIT : RuntimeLibcall;
//--------------------------------------------------------------------
// Global variable references
//--------------------------------------------------------------------
//
// TODO: These are not libcalls and probably should be distinguished
// in some way from callable functions.
// --------------------------------------------------------------------
def STACK_CHECK_GUARD : RuntimeLibcall;
//--------------------------------------------------------------------
// Define implementation default libcalls
//--------------------------------------------------------------------
@ -1103,6 +1120,21 @@ defset list<RuntimeLibcallImpl> LibmF128FiniteLibcalls = {
def __powf128_finite : RuntimeLibcallImpl<POW_FINITE_F128>;
}
//--------------------------------------------------------------------
// Global variable references
//--------------------------------------------------------------------
def __stack_chk_guard : RuntimeLibcallImpl<STACK_CHECK_GUARD>;
// Name used on OpenBSD
def __guard_local : RuntimeLibcallImpl<STACK_CHECK_GUARD>;
// Name used with Windows MSVC
def __security_cookie : RuntimeLibcallImpl<STACK_CHECK_GUARD>;
// Name used on AIX
def __ssp_canary_word : RuntimeLibcallImpl<STACK_CHECK_GUARD>;
//===----------------------------------------------------------------------===//
// Common Libcall Sets
//===----------------------------------------------------------------------===//
@ -1159,7 +1191,8 @@ defvar DarwinSinCosStret = LibcallImpls<(add __sincosf_stret, __sincos_stret),
defvar DarwinExp10 = LibcallImpls<(add __exp10f, __exp10), darwinHasExp10>;
defvar SecurityCheckCookieIfWinMSVC =
LibcallImpls<(add __security_check_cookie), isWindowsMSVCEnvironment>;
LibcallImpls<(add __security_check_cookie, __security_cookie),
isWindowsMSVCOrItaniumEnvironment>;
defvar LibmHasSinCosF32 = LibcallImpls<(add sincosf), hasSinCos>;
defvar LibmHasSinCosF64 = LibcallImpls<(add sincos), hasSinCos>;
@ -1205,10 +1238,13 @@ defvar LibmHasFrexpF128 = LibcallImpls<(add frexp_f128), isNotOSWindowsOrIsCygwi
defvar LibmHasLdexpF128 = LibcallImpls<(add ldexp_f128), isNotOSWindowsOrIsCygwinMinGW>;
defvar has__stack_chk_fail = LibcallImpls<(add __stack_chk_fail), isNotOSOpenBSD>;
defvar has__stack_chk_guard =
LibcallImpls<(add __stack_chk_guard), isNotOSOpenBSD>;
defvar has__stack_smash_handler = LibcallImpls<(add __stack_smash_handler), isOSOpenBSD>;
defvar has___guard_local = LibcallImpls<(add __guard_local), isOSOpenBSD>;
defvar DefaultStackProtector = (add has__stack_chk_fail,
has__stack_smash_handler);
defvar DefaultStackProtector = (add has__stack_chk_fail, has__stack_chk_guard,
has__stack_smash_handler, has___guard_local);
//===----------------------------------------------------------------------===//
// Objective-C Runtime Libcalls
@ -1357,7 +1393,9 @@ def WindowsARM64ECSystemLibrary
: SystemRuntimeLibrary<isWindowsArm64EC,
(add WinArm64ECDefaultRuntimeLibcallImpls,
arm64ec___stack_chk_fail,
LibcallImpls<(add __security_check_cookie_arm64ec),
__stack_chk_guard,
LibcallImpls<(add __security_check_cookie_arm64ec,
__security_cookie),
isWindowsMSVCEnvironment>,
ExceptionModelCallsArm64EC)>;
@ -1848,7 +1886,7 @@ def HexagonSystemLibrary
__umoddi3, __divdf3, __muldf3, __divsi3, __subdf3, sqrtf,
__divdi3, __umodsi3, __moddi3, __modsi3), HexagonLibcalls,
LibmHasSinCosF32, LibmHasSinCosF64, LibmHasSinCosF128,
exp10f, exp10, exp10l_f128, __stack_chk_fail)>;
exp10f, exp10, exp10l_f128, __stack_chk_fail, __stack_chk_guard)>;
//===----------------------------------------------------------------------===//
// Lanai Runtime Libcalls
@ -1859,7 +1897,7 @@ def isLanai : RuntimeLibcallPredicate<"TT.getArch() == Triple::lanai">;
// Use fast calling convention for library functions.
def LanaiSystemLibrary
: SystemRuntimeLibrary<isLanai, (add DefaultRuntimeLibcallImpls,
__stack_chk_fail)> {
__stack_chk_fail, __stack_chk_guard)> {
let DefaultLibcallCallingConv = FASTCC;
}
@ -2157,7 +2195,8 @@ def MSP430SystemLibrary
__mspabi_slll,
// __mspabi_[srlll/srall/sllll/rlli/rlll] are NOT implemented in libgcc
__stack_chk_fail
__stack_chk_fail,
__stack_chk_guard
)
>;
@ -2251,7 +2290,11 @@ def PPCSystemLibrary
LibmHasSinCosPPCF128,
AvailableIf<memcpy, isNotAIX>,
LibcallImpls<(add Int128RTLibcalls), isPPC64>,
DefaultStackProtector)>;
has__stack_chk_fail,
has__stack_smash_handler,
has___guard_local,
AvailableIf<__ssp_canary_word, isAIX>,
AvailableIf<__stack_chk_guard, isNotAIX>)>;
//===----------------------------------------------------------------------===//
// RISCV Runtime Libcalls
@ -2334,7 +2377,10 @@ def SPARCSystemLibrary
LibcallImpls<(add _Q_qtoll, _Q_qtoull, _Q_lltoq, _Q_ulltoq), isSPARC32>,
LibcallImpls<(add SPARC64_MulDivCalls, Int128RTLibcalls), isSPARC64>,
LibmHasSinCosF32, LibmHasSinCosF64, LibmHasSinCosF128,
DefaultStackProtector)
has__stack_chk_fail,
has__stack_smash_handler,
has___guard_local,
AvailableIf<__stack_chk_guard, isNotOSLinuxAndNotOSOpenBSD>)
>;
//===----------------------------------------------------------------------===//
@ -2544,7 +2590,7 @@ def WasmSystemLibrary
exp10f, exp10,
_Unwind_CallPersonality,
emscripten_return_address,
__stack_chk_fail)>;
__stack_chk_fail, __stack_chk_guard)>;
//===----------------------------------------------------------------------===//
// Legacy Default Runtime Libcalls

View File

@ -18983,9 +18983,7 @@ SDValue DAGCombiner::visitFP_ROUND(SDNode *N) {
// single-step fp_round we want to fold to.
// In other words, double rounding isn't the same as rounding.
// Also, this is a value preserving truncation iff both fp_round's are.
if ((N->getFlags().hasAllowContract() &&
N0->getFlags().hasAllowContract()) ||
N0IsTrunc)
if (DAG.getTarget().Options.UnsafeFPMath || N0IsTrunc)
return DAG.getNode(
ISD::FP_ROUND, DL, VT, N0.getOperand(0),
DAG.getIntPtrConstant(NIsTrunc && N0IsTrunc, DL, /*isTarget=*/true));

View File

@ -2059,29 +2059,37 @@ Value *TargetLoweringBase::getIRStackGuard(IRBuilderBase &IRB) const {
// Currently only support "standard" __stack_chk_guard.
// TODO: add LOAD_STACK_GUARD support.
void TargetLoweringBase::insertSSPDeclarations(Module &M) const {
if (!M.getNamedValue("__stack_chk_guard")) {
auto *GV = new GlobalVariable(M, PointerType::getUnqual(M.getContext()),
false, GlobalVariable::ExternalLinkage,
nullptr, "__stack_chk_guard");
RTLIB::LibcallImpl StackGuardImpl = getLibcallImpl(RTLIB::STACK_CHECK_GUARD);
if (StackGuardImpl == RTLIB::Unsupported)
return;
// FreeBSD has "__stack_chk_guard" defined externally on libc.so
if (M.getDirectAccessExternalData() &&
!TM.getTargetTriple().isOSCygMing() &&
!(TM.getTargetTriple().isPPC64() &&
TM.getTargetTriple().isOSFreeBSD()) &&
(!TM.getTargetTriple().isOSDarwin() ||
TM.getRelocationModel() == Reloc::Static))
GV->setDSOLocal(true);
}
StringRef StackGuardVarName = getLibcallImplName(StackGuardImpl);
M.getOrInsertGlobal(
StackGuardVarName, PointerType::getUnqual(M.getContext()), [=, &M]() {
auto *GV = new GlobalVariable(M, PointerType::getUnqual(M.getContext()),
false, GlobalVariable::ExternalLinkage,
nullptr, StackGuardVarName);
// FreeBSD has "__stack_chk_guard" defined externally on libc.so
if (M.getDirectAccessExternalData() &&
!TM.getTargetTriple().isOSCygMing() &&
!(TM.getTargetTriple().isPPC64() &&
TM.getTargetTriple().isOSFreeBSD()) &&
(!TM.getTargetTriple().isOSDarwin() ||
TM.getRelocationModel() == Reloc::Static))
GV->setDSOLocal(true);
return GV;
});
}
// Currently only support "standard" __stack_chk_guard.
// TODO: add LOAD_STACK_GUARD support.
Value *TargetLoweringBase::getSDagStackGuard(const Module &M) const {
if (getTargetMachine().getTargetTriple().isOSOpenBSD()) {
return M.getNamedValue("__guard_local");
}
return M.getNamedValue("__stack_chk_guard");
RTLIB::LibcallImpl GuardVarImpl = getLibcallImpl(RTLIB::STACK_CHECK_GUARD);
if (GuardVarImpl == RTLIB::Unsupported)
return nullptr;
return M.getNamedValue(getLibcallImplName(GuardVarImpl));
}
Function *TargetLoweringBase::getSSPStackGuardCheck(const Module &M) const {

View File

@ -46,18 +46,6 @@ static cl::opt<bool> DisableBitcodeVersionUpgrade(
"disable-bitcode-version-upgrade", cl::Hidden,
cl::desc("Disable automatic bitcode upgrade for version mismatch"));
static constexpr StringLiteral PreservedSymbols[] = {
// There are global variables, so put it here instead of in
// RuntimeLibcalls.td.
// TODO: Are there similar such variables?
"__ssp_canary_word",
"__stack_chk_guard",
};
static bool isPreservedGlobalVarName(StringRef Name) {
return PreservedSymbols[0] == Name || PreservedSymbols[1] == Name;
}
namespace {
const char *getExpectedProducerName() {
@ -106,7 +94,7 @@ struct Builder {
std::vector<storage::Str> DependentLibraries;
bool isPreservedLibFuncName(StringRef Name) {
bool isPreservedName(StringRef Name) {
return Libcalls.getSupportedLibcallImpl(Name) != RTLIB::Unsupported;
}
@ -281,8 +269,7 @@ Error Builder::addSymbol(const ModuleSymbolTable &Msymtab,
StringRef GVName = GV->getName();
setStr(Sym.IRName, GVName);
if (Used.count(GV) || isPreservedLibFuncName(GVName) ||
isPreservedGlobalVarName(GVName))
if (Used.count(GV) || isPreservedName(GVName))
Sym.Flags |= 1 << storage::Symbol::FB_used;
if (GV->isThreadLocal())
Sym.Flags |= 1 << storage::Symbol::FB_tls;

View File

@ -28686,9 +28686,13 @@ void AArch64TargetLowering::insertSSPDeclarations(Module &M) const {
// MSVC CRT provides functionalities for stack protection.
RTLIB::LibcallImpl SecurityCheckCookieLibcall =
getLibcallImpl(RTLIB::SECURITY_CHECK_COOKIE);
if (SecurityCheckCookieLibcall != RTLIB::Unsupported) {
RTLIB::LibcallImpl SecurityCookieVar =
getLibcallImpl(RTLIB::STACK_CHECK_GUARD);
if (SecurityCheckCookieLibcall != RTLIB::Unsupported &&
SecurityCookieVar != RTLIB::Unsupported) {
// MSVC CRT has a global variable holding security cookie.
M.getOrInsertGlobal("__security_cookie",
M.getOrInsertGlobal(getLibcallImplName(SecurityCookieVar),
PointerType::getUnqual(M.getContext()));
// MSVC CRT has a function to validate security cookie.
@ -28705,13 +28709,6 @@ void AArch64TargetLowering::insertSSPDeclarations(Module &M) const {
TargetLowering::insertSSPDeclarations(M);
}
Value *AArch64TargetLowering::getSDagStackGuard(const Module &M) const {
// MSVC CRT has a global variable holding security cookie.
if (Subtarget->getTargetTriple().isWindowsMSVCEnvironment())
return M.getGlobalVariable("__security_cookie");
return TargetLowering::getSDagStackGuard(M);
}
Function *AArch64TargetLowering::getSSPStackGuardCheck(const Module &M) const {
// MSVC CRT has a function to validate security cookie.
RTLIB::LibcallImpl SecurityCheckCookieLibcall =

View File

@ -354,7 +354,6 @@ public:
Value *getIRStackGuard(IRBuilderBase &IRB) const override;
void insertSSPDeclarations(Module &M) const override;
Value *getSDagStackGuard(const Module &M) const override;
Function *getSSPStackGuardCheck(const Module &M) const override;
/// If the target has a standard location for the unsafe stack pointer,

View File

@ -6135,19 +6135,6 @@ unsigned AMDGPUTargetLowering::computeNumSignBitsForTargetInstr(
}
}
bool AMDGPUTargetLowering::canCreateUndefOrPoisonForTargetNode(
SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG,
bool PoisonOnly, bool ConsiderFlags, unsigned Depth) const {
unsigned Opcode = Op.getOpcode();
switch (Opcode) {
case AMDGPUISD::BFE_I32:
case AMDGPUISD::BFE_U32:
return false;
}
return TargetLowering::canCreateUndefOrPoisonForTargetNode(
Op, DemandedElts, DAG, PoisonOnly, ConsiderFlags, Depth);
}
bool AMDGPUTargetLowering::isKnownNeverNaNForTargetNode(
SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, bool SNaN,
unsigned Depth) const {

View File

@ -323,12 +323,6 @@ public:
const MachineRegisterInfo &MRI,
unsigned Depth = 0) const override;
bool canCreateUndefOrPoisonForTargetNode(SDValue Op,
const APInt &DemandedElts,
const SelectionDAG &DAG,
bool PoisonOnly, bool ConsiderFlags,
unsigned Depth) const override;
bool isKnownNeverNaNForTargetNode(SDValue Op, const APInt &DemandedElts,
const SelectionDAG &DAG, bool SNaN = false,
unsigned Depth = 0) const override;

View File

@ -21341,20 +21341,6 @@ void ARMTargetLowering::insertSSPDeclarations(Module &M) const {
F->addParamAttr(0, Attribute::AttrKind::InReg);
}
Value *ARMTargetLowering::getSDagStackGuard(const Module &M) const {
RTLIB::LibcallImpl SecurityCheckCookieLibcall =
getLibcallImpl(RTLIB::SECURITY_CHECK_COOKIE);
if (SecurityCheckCookieLibcall != RTLIB::Unsupported) {
// MSVC CRT has a global variable holding security cookie.
//
// FIXME: We have a libcall entry for the correlated check function, but not
// the global name.
return M.getGlobalVariable("__security_cookie");
}
return TargetLowering::getSDagStackGuard(M);
}
Function *ARMTargetLowering::getSSPStackGuardCheck(const Module &M) const {
// MSVC CRT has a function to validate security cookie.
RTLIB::LibcallImpl SecurityCheckCookie =

View File

@ -704,7 +704,6 @@ class VectorType;
bool useLoadStackGuardNode(const Module &M) const override;
void insertSSPDeclarations(Module &M) const override;
Value *getSDagStackGuard(const Module &M) const override;
Function *getSSPStackGuardCheck(const Module &M) const override;
bool canCombineStoreAndExtract(Type *VectorTy, Value *Idx,

View File

@ -158,8 +158,6 @@ static bool isNByteElemShuffleMask(ShuffleVectorSDNode *, unsigned, int);
static SDValue widenVec(SelectionDAG &DAG, SDValue Vec, const SDLoc &dl);
static const char AIXSSPCanaryWordName[] = "__ssp_canary_word";
// A faster local-[exec|dynamic] TLS access sequence (enabled with the
// -maix-small-local-[exec|dynamic]-tls option) can be produced for TLS
// variables; consistent with the IBM XL compiler, we apply a max size of
@ -18656,24 +18654,6 @@ bool PPCTargetLowering::useLoadStackGuardNode(const Module &M) const {
return TargetLowering::useLoadStackGuardNode(M);
}
// Override to disable global variable loading on Linux and insert AIX canary
// word declaration.
void PPCTargetLowering::insertSSPDeclarations(Module &M) const {
if (Subtarget.isAIXABI()) {
M.getOrInsertGlobal(AIXSSPCanaryWordName,
PointerType::getUnqual(M.getContext()));
return;
}
if (!Subtarget.isTargetLinux())
return TargetLowering::insertSSPDeclarations(M);
}
Value *PPCTargetLowering::getSDagStackGuard(const Module &M) const {
if (Subtarget.isAIXABI())
return M.getGlobalVariable(AIXSSPCanaryWordName);
return TargetLowering::getSDagStackGuard(M);
}
bool PPCTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
bool ForCodeSize) const {
if (!VT.isSimple() || !Subtarget.hasVSX())

View File

@ -1141,8 +1141,6 @@ namespace llvm {
/// Override to support customized stack guard loading.
bool useLoadStackGuardNode(const Module &M) const override;
void insertSSPDeclarations(Module &M) const override;
Value *getSDagStackGuard(const Module &M) const override;
bool isFPImmLegal(const APFloat &Imm, EVT VT,
bool ForCodeSize) const override;

View File

@ -3549,12 +3549,6 @@ bool SparcTargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
return Subtarget->isUA2007() && !Subtarget->useSoftFloat();
}
// Override to disable global variable loading on Linux.
void SparcTargetLowering::insertSSPDeclarations(Module &M) const {
if (!Subtarget->isTargetLinux())
return TargetLowering::insertSSPDeclarations(M);
}
void SparcTargetLowering::AdjustInstrPostInstrSelection(MachineInstr &MI,
SDNode *Node) const {
assert(MI.getOpcode() == SP::SUBCCrr || MI.getOpcode() == SP::SUBCCri);

View File

@ -79,7 +79,6 @@ namespace llvm {
/// Override to support customized stack guard loading.
bool useLoadStackGuardNode(const Module &M) const override;
void insertSSPDeclarations(Module &M) const override;
/// getSetCCResultType - Return the ISD::SETCC ValueType
EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context,

View File

@ -1591,7 +1591,6 @@ namespace llvm {
bool useLoadStackGuardNode(const Module &M) const override;
bool useStackGuardXorFP() const override;
void insertSSPDeclarations(Module &M) const override;
Value *getSDagStackGuard(const Module &M) const override;
Function *getSSPStackGuardCheck(const Module &M) const override;
SDValue emitStackGuardXorFP(SelectionDAG &DAG, SDValue Val,
const SDLoc &DL) const override;

View File

@ -632,15 +632,6 @@ void X86TargetLowering::insertSSPDeclarations(Module &M) const {
TargetLowering::insertSSPDeclarations(M);
}
Value *X86TargetLowering::getSDagStackGuard(const Module &M) const {
// MSVC CRT has a global variable holding security cookie.
if (Subtarget.getTargetTriple().isWindowsMSVCEnvironment() ||
Subtarget.getTargetTriple().isWindowsItaniumEnvironment()) {
return M.getGlobalVariable("__security_cookie");
}
return TargetLowering::getSDagStackGuard(M);
}
Function *X86TargetLowering::getSSPStackGuardCheck(const Module &M) const {
// MSVC CRT has a function to validate security cookie.
if (Subtarget.getTargetTriple().isWindowsMSVCEnvironment() ||

View File

@ -344,7 +344,7 @@ define amdgpu_ps void @fptrunc_f32_to_bf16(float %a, ptr %out) {
; GFX1250: ; %bb.0: ; %entry
; GFX1250-NEXT: v_dual_mov_b32 v3, v2 :: v_dual_mov_b32 v2, v1
; GFX1250-NEXT: v_cvt_pk_bf16_f32 v0, v0, s0
; GFX1250-NEXT: flat_store_b16 v[2:3], v0 scope:SCOPE_SE
; GFX1250-NEXT: flat_store_b16 v[2:3], v0
; GFX1250-NEXT: s_endpgm
entry:
%a.cvt = fptrunc float %a to bfloat
@ -380,7 +380,7 @@ define amdgpu_ps void @fptrunc_f32_to_bf16_abs(float %a, ptr %out) {
; GFX1250: ; %bb.0: ; %entry
; GFX1250-NEXT: v_dual_mov_b32 v3, v2 :: v_dual_mov_b32 v2, v1
; GFX1250-NEXT: v_cvt_pk_bf16_f32 v0, |v0|, s0
; GFX1250-NEXT: flat_store_b16 v[2:3], v0 scope:SCOPE_SE
; GFX1250-NEXT: flat_store_b16 v[2:3], v0
; GFX1250-NEXT: s_endpgm
entry:
%a.abs = call float @llvm.fabs.f32(float %a)
@ -417,7 +417,7 @@ define amdgpu_ps void @fptrunc_f32_to_bf16_neg(float %a, ptr %out) {
; GFX1250: ; %bb.0: ; %entry
; GFX1250-NEXT: v_dual_mov_b32 v3, v2 :: v_dual_mov_b32 v2, v1
; GFX1250-NEXT: v_cvt_pk_bf16_f32 v0, -v0, s0
; GFX1250-NEXT: flat_store_b16 v[2:3], v0 scope:SCOPE_SE
; GFX1250-NEXT: flat_store_b16 v[2:3], v0
; GFX1250-NEXT: s_endpgm
entry:
%a.neg = fneg float %a
@ -480,7 +480,7 @@ define amdgpu_ps void @fptrunc_f64_to_bf16(double %a, ptr %out) {
; GFX1250-NEXT: s_or_b32 vcc_lo, vcc_lo, s0
; GFX1250-NEXT: v_cndmask_b32_e32 v0, v0, v6, vcc_lo
; GFX1250-NEXT: v_cvt_pk_bf16_f32 v0, v0, s0
; GFX1250-NEXT: flat_store_b16 v[2:3], v0 scope:SCOPE_SE
; GFX1250-NEXT: flat_store_b16 v[2:3], v0
; GFX1250-NEXT: s_endpgm
entry:
%a.cvt = fptrunc double %a to bfloat
@ -543,7 +543,7 @@ define amdgpu_ps void @fptrunc_f64_to_bf16_neg(double %a, ptr %out) {
; GFX1250-NEXT: v_cndmask_b32_e32 v0, v0, v6, vcc_lo
; GFX1250-NEXT: s_delay_alu instid0(VALU_DEP_1)
; GFX1250-NEXT: v_cvt_pk_bf16_f32 v0, v0, s0
; GFX1250-NEXT: flat_store_b16 v[2:3], v0 scope:SCOPE_SE
; GFX1250-NEXT: flat_store_b16 v[2:3], v0
; GFX1250-NEXT: s_endpgm
entry:
%a.neg = fneg double %a
@ -607,7 +607,7 @@ define amdgpu_ps void @fptrunc_f64_to_bf16_abs(double %a, ptr %out) {
; GFX1250-NEXT: v_cndmask_b32_e32 v0, v0, v6, vcc_lo
; GFX1250-NEXT: s_delay_alu instid0(VALU_DEP_1)
; GFX1250-NEXT: v_cvt_pk_bf16_f32 v0, v0, s0
; GFX1250-NEXT: flat_store_b16 v[2:3], v0 scope:SCOPE_SE
; GFX1250-NEXT: flat_store_b16 v[2:3], v0
; GFX1250-NEXT: s_endpgm
entry:
%a.abs = call double @llvm.fabs.f64(double %a)

View File

@ -1582,22 +1582,28 @@ define amdgpu_kernel void @frem_f64(ptr addrspace(1) %out, ptr addrspace(1) %in1
; SI-NEXT: s_nop 1
; SI-NEXT: v_div_fmas_f64 v[4:5], v[12:13], v[6:7], v[10:11]
; SI-NEXT: v_div_fixup_f64 v[4:5], v[4:5], v[2:3], v[0:1]
; SI-NEXT: v_readfirstlane_b32 s0, v4
; SI-NEXT: v_readfirstlane_b32 s1, v5
; SI-NEXT: s_bfe_u32 s2, s1, 0xb0014
; SI-NEXT: s_add_i32 s8, s2, 0xfffffc01
; SI-NEXT: s_mov_b32 s3, 0xfffff
; SI-NEXT: s_mov_b32 s2, s6
; SI-NEXT: s_lshr_b64 s[2:3], s[2:3], s8
; SI-NEXT: s_andn2_b64 s[2:3], s[0:1], s[2:3]
; SI-NEXT: s_and_b32 s9, s1, 0x80000000
; SI-NEXT: s_cmp_lt_i32 s8, 0
; SI-NEXT: s_cselect_b32 s2, 0, s2
; SI-NEXT: s_cselect_b32 s3, s9, s3
; SI-NEXT: s_cmp_gt_i32 s8, 51
; SI-NEXT: s_cselect_b32 s1, s1, s3
; SI-NEXT: s_cselect_b32 s0, s0, s2
; SI-NEXT: v_fma_f64 v[0:1], -s[0:1], v[2:3], v[0:1]
; SI-NEXT: v_readfirstlane_b32 s2, v5
; SI-NEXT: s_bfe_u32 s0, s2, 0xb0014
; SI-NEXT: s_add_i32 s3, s0, 0xfffffc01
; SI-NEXT: s_mov_b32 s1, 0xfffff
; SI-NEXT: s_mov_b32 s0, s6
; SI-NEXT: s_lshr_b64 s[0:1], s[0:1], s3
; SI-NEXT: v_not_b32_e32 v6, s0
; SI-NEXT: v_and_b32_e32 v6, v4, v6
; SI-NEXT: v_not_b32_e32 v7, s1
; SI-NEXT: v_and_b32_e32 v5, v5, v7
; SI-NEXT: s_and_b32 s0, s2, 0x80000000
; SI-NEXT: s_cmp_lt_i32 s3, 0
; SI-NEXT: s_cselect_b64 vcc, -1, 0
; SI-NEXT: v_cndmask_b32_e64 v6, v6, 0, vcc
; SI-NEXT: v_mov_b32_e32 v7, s0
; SI-NEXT: v_cndmask_b32_e32 v5, v5, v7, vcc
; SI-NEXT: s_cmp_gt_i32 s3, 51
; SI-NEXT: s_cselect_b64 vcc, -1, 0
; SI-NEXT: v_mov_b32_e32 v7, s2
; SI-NEXT: v_cndmask_b32_e32 v5, v5, v7, vcc
; SI-NEXT: v_cndmask_b32_e32 v4, v6, v4, vcc
; SI-NEXT: v_fma_f64 v[0:1], -v[4:5], v[2:3], v[0:1]
; SI-NEXT: buffer_store_dwordx2 v[0:1], off, s[4:7], 0
; SI-NEXT: s_endpgm
;
@ -1853,22 +1859,28 @@ define amdgpu_kernel void @fast_frem_f64(ptr addrspace(1) %out, ptr addrspace(1)
; SI-NEXT: v_mul_f64 v[6:7], v[0:1], v[4:5]
; SI-NEXT: v_fma_f64 v[8:9], -v[2:3], v[6:7], v[0:1]
; SI-NEXT: v_fma_f64 v[4:5], v[8:9], v[4:5], v[6:7]
; SI-NEXT: v_readfirstlane_b32 s4, v4
; SI-NEXT: v_readfirstlane_b32 s5, v5
; SI-NEXT: s_bfe_u32 s6, s5, 0xb0014
; SI-NEXT: s_add_i32 s8, s6, 0xfffffc01
; SI-NEXT: s_mov_b32 s7, 0xfffff
; SI-NEXT: s_mov_b32 s6, s2
; SI-NEXT: s_lshr_b64 s[6:7], s[6:7], s8
; SI-NEXT: s_andn2_b64 s[6:7], s[4:5], s[6:7]
; SI-NEXT: s_and_b32 s9, s5, 0x80000000
; SI-NEXT: s_cmp_lt_i32 s8, 0
; SI-NEXT: s_cselect_b32 s6, 0, s6
; SI-NEXT: s_cselect_b32 s7, s9, s7
; SI-NEXT: s_cmp_gt_i32 s8, 51
; SI-NEXT: s_cselect_b32 s5, s5, s7
; SI-NEXT: s_cselect_b32 s4, s4, s6
; SI-NEXT: v_fma_f64 v[0:1], -s[4:5], v[2:3], v[0:1]
; SI-NEXT: v_readfirstlane_b32 s6, v5
; SI-NEXT: s_bfe_u32 s4, s6, 0xb0014
; SI-NEXT: s_add_i32 s7, s4, 0xfffffc01
; SI-NEXT: s_mov_b32 s5, 0xfffff
; SI-NEXT: s_mov_b32 s4, s2
; SI-NEXT: s_lshr_b64 s[4:5], s[4:5], s7
; SI-NEXT: v_not_b32_e32 v6, s4
; SI-NEXT: v_and_b32_e32 v6, v4, v6
; SI-NEXT: v_not_b32_e32 v7, s5
; SI-NEXT: v_and_b32_e32 v5, v5, v7
; SI-NEXT: s_and_b32 s4, s6, 0x80000000
; SI-NEXT: s_cmp_lt_i32 s7, 0
; SI-NEXT: s_cselect_b64 vcc, -1, 0
; SI-NEXT: v_cndmask_b32_e64 v6, v6, 0, vcc
; SI-NEXT: v_mov_b32_e32 v7, s4
; SI-NEXT: v_cndmask_b32_e32 v5, v5, v7, vcc
; SI-NEXT: s_cmp_gt_i32 s7, 51
; SI-NEXT: s_cselect_b64 vcc, -1, 0
; SI-NEXT: v_mov_b32_e32 v7, s6
; SI-NEXT: v_cndmask_b32_e32 v5, v5, v7, vcc
; SI-NEXT: v_cndmask_b32_e32 v4, v6, v4, vcc
; SI-NEXT: v_fma_f64 v[0:1], -v[4:5], v[2:3], v[0:1]
; SI-NEXT: buffer_store_dwordx2 v[0:1], off, s[0:3], 0
; SI-NEXT: s_endpgm
;
@ -2097,22 +2109,28 @@ define amdgpu_kernel void @unsafe_frem_f64(ptr addrspace(1) %out, ptr addrspace(
; SI-NEXT: v_mul_f64 v[6:7], v[0:1], v[4:5]
; SI-NEXT: v_fma_f64 v[8:9], -v[2:3], v[6:7], v[0:1]
; SI-NEXT: v_fma_f64 v[4:5], v[8:9], v[4:5], v[6:7]
; SI-NEXT: v_readfirstlane_b32 s4, v4
; SI-NEXT: v_readfirstlane_b32 s5, v5
; SI-NEXT: s_bfe_u32 s6, s5, 0xb0014
; SI-NEXT: s_add_i32 s8, s6, 0xfffffc01
; SI-NEXT: s_mov_b32 s7, 0xfffff
; SI-NEXT: s_mov_b32 s6, s2
; SI-NEXT: s_lshr_b64 s[6:7], s[6:7], s8
; SI-NEXT: s_andn2_b64 s[6:7], s[4:5], s[6:7]
; SI-NEXT: s_and_b32 s9, s5, 0x80000000
; SI-NEXT: s_cmp_lt_i32 s8, 0
; SI-NEXT: s_cselect_b32 s6, 0, s6
; SI-NEXT: s_cselect_b32 s7, s9, s7
; SI-NEXT: s_cmp_gt_i32 s8, 51
; SI-NEXT: s_cselect_b32 s5, s5, s7
; SI-NEXT: s_cselect_b32 s4, s4, s6
; SI-NEXT: v_fma_f64 v[0:1], -s[4:5], v[2:3], v[0:1]
; SI-NEXT: v_readfirstlane_b32 s6, v5
; SI-NEXT: s_bfe_u32 s4, s6, 0xb0014
; SI-NEXT: s_add_i32 s7, s4, 0xfffffc01
; SI-NEXT: s_mov_b32 s5, 0xfffff
; SI-NEXT: s_mov_b32 s4, s2
; SI-NEXT: s_lshr_b64 s[4:5], s[4:5], s7
; SI-NEXT: v_not_b32_e32 v6, s4
; SI-NEXT: v_and_b32_e32 v6, v4, v6
; SI-NEXT: v_not_b32_e32 v7, s5
; SI-NEXT: v_and_b32_e32 v5, v5, v7
; SI-NEXT: s_and_b32 s4, s6, 0x80000000
; SI-NEXT: s_cmp_lt_i32 s7, 0
; SI-NEXT: s_cselect_b64 vcc, -1, 0
; SI-NEXT: v_cndmask_b32_e64 v6, v6, 0, vcc
; SI-NEXT: v_mov_b32_e32 v7, s4
; SI-NEXT: v_cndmask_b32_e32 v5, v5, v7, vcc
; SI-NEXT: s_cmp_gt_i32 s7, 51
; SI-NEXT: s_cselect_b64 vcc, -1, 0
; SI-NEXT: v_mov_b32_e32 v7, s6
; SI-NEXT: v_cndmask_b32_e32 v5, v5, v7, vcc
; SI-NEXT: v_cndmask_b32_e32 v4, v6, v4, vcc
; SI-NEXT: v_fma_f64 v[0:1], -v[4:5], v[2:3], v[0:1]
; SI-NEXT: buffer_store_dwordx2 v[0:1], off, s[0:3], 0
; SI-NEXT: s_endpgm
;
@ -5233,22 +5251,27 @@ define amdgpu_kernel void @frem_v2f64(ptr addrspace(1) %out, ptr addrspace(1) %i
; SI-NEXT: s_nop 1
; SI-NEXT: v_div_fmas_f64 v[8:9], v[16:17], v[10:11], v[14:15]
; SI-NEXT: v_div_fixup_f64 v[8:9], v[8:9], v[6:7], v[2:3]
; SI-NEXT: v_readfirstlane_b32 s0, v8
; SI-NEXT: v_readfirstlane_b32 s1, v9
; SI-NEXT: s_bfe_u32 s2, s1, 0xb0014
; SI-NEXT: s_add_i32 s10, s2, 0xfffffc01
; SI-NEXT: v_readfirstlane_b32 s8, v9
; SI-NEXT: s_bfe_u32 s0, s8, 0xb0014
; SI-NEXT: s_add_i32 s9, s0, 0xfffffc01
; SI-NEXT: s_mov_b32 s3, 0xfffff
; SI-NEXT: s_mov_b32 s2, s6
; SI-NEXT: s_lshr_b64 s[8:9], s[2:3], s10
; SI-NEXT: s_andn2_b64 s[8:9], s[0:1], s[8:9]
; SI-NEXT: s_and_b32 s11, s1, 0x80000000
; SI-NEXT: s_cmp_lt_i32 s10, 0
; SI-NEXT: s_cselect_b32 s8, 0, s8
; SI-NEXT: s_cselect_b32 s9, s11, s9
; SI-NEXT: s_cmp_gt_i32 s10, 51
; SI-NEXT: s_cselect_b32 s1, s1, s9
; SI-NEXT: s_cselect_b32 s0, s0, s8
; SI-NEXT: v_fma_f64 v[2:3], -s[0:1], v[6:7], v[2:3]
; SI-NEXT: s_lshr_b64 s[0:1], s[2:3], s9
; SI-NEXT: v_not_b32_e32 v10, s0
; SI-NEXT: v_and_b32_e32 v10, v8, v10
; SI-NEXT: v_not_b32_e32 v11, s1
; SI-NEXT: v_and_b32_e32 v9, v9, v11
; SI-NEXT: s_and_b32 s0, s8, 0x80000000
; SI-NEXT: s_cmp_lt_i32 s9, 0
; SI-NEXT: s_cselect_b64 vcc, -1, 0
; SI-NEXT: v_cndmask_b32_e64 v10, v10, 0, vcc
; SI-NEXT: v_mov_b32_e32 v11, s0
; SI-NEXT: v_cndmask_b32_e32 v9, v9, v11, vcc
; SI-NEXT: s_cmp_gt_i32 s9, 51
; SI-NEXT: s_cselect_b64 vcc, -1, 0
; SI-NEXT: v_mov_b32_e32 v11, s8
; SI-NEXT: v_cndmask_b32_e32 v9, v9, v11, vcc
; SI-NEXT: v_cndmask_b32_e32 v8, v10, v8, vcc
; SI-NEXT: v_fma_f64 v[2:3], -v[8:9], v[6:7], v[2:3]
; SI-NEXT: v_div_scale_f64 v[6:7], s[0:1], v[4:5], v[4:5], v[0:1]
; SI-NEXT: v_rcp_f64_e32 v[8:9], v[6:7]
; SI-NEXT: v_fma_f64 v[10:11], -v[6:7], v[8:9], 1.0
@ -5264,20 +5287,26 @@ define amdgpu_kernel void @frem_v2f64(ptr addrspace(1) %out, ptr addrspace(1) %i
; SI-NEXT: s_nop 1
; SI-NEXT: v_div_fmas_f64 v[6:7], v[14:15], v[8:9], v[12:13]
; SI-NEXT: v_div_fixup_f64 v[6:7], v[6:7], v[4:5], v[0:1]
; SI-NEXT: v_readfirstlane_b32 s0, v6
; SI-NEXT: v_readfirstlane_b32 s1, v7
; SI-NEXT: s_bfe_u32 s8, s1, 0xb0014
; SI-NEXT: s_addk_i32 s8, 0xfc01
; SI-NEXT: s_lshr_b64 s[2:3], s[2:3], s8
; SI-NEXT: s_andn2_b64 s[2:3], s[0:1], s[2:3]
; SI-NEXT: s_and_b32 s9, s1, 0x80000000
; SI-NEXT: s_cmp_lt_i32 s8, 0
; SI-NEXT: s_cselect_b32 s2, 0, s2
; SI-NEXT: s_cselect_b32 s3, s9, s3
; SI-NEXT: s_cmp_gt_i32 s8, 51
; SI-NEXT: s_cselect_b32 s1, s1, s3
; SI-NEXT: s_cselect_b32 s0, s0, s2
; SI-NEXT: v_fma_f64 v[0:1], -s[0:1], v[4:5], v[0:1]
; SI-NEXT: v_readfirstlane_b32 s8, v7
; SI-NEXT: s_bfe_u32 s0, s8, 0xb0014
; SI-NEXT: s_add_i32 s9, s0, 0xfffffc01
; SI-NEXT: s_lshr_b64 s[0:1], s[2:3], s9
; SI-NEXT: v_not_b32_e32 v8, s0
; SI-NEXT: v_and_b32_e32 v8, v6, v8
; SI-NEXT: v_not_b32_e32 v9, s1
; SI-NEXT: v_and_b32_e32 v7, v7, v9
; SI-NEXT: s_and_b32 s0, s8, 0x80000000
; SI-NEXT: s_cmp_lt_i32 s9, 0
; SI-NEXT: s_cselect_b64 vcc, -1, 0
; SI-NEXT: v_cndmask_b32_e64 v8, v8, 0, vcc
; SI-NEXT: v_mov_b32_e32 v9, s0
; SI-NEXT: v_cndmask_b32_e32 v7, v7, v9, vcc
; SI-NEXT: s_cmp_gt_i32 s9, 51
; SI-NEXT: s_cselect_b64 vcc, -1, 0
; SI-NEXT: v_mov_b32_e32 v9, s8
; SI-NEXT: v_cndmask_b32_e32 v7, v7, v9, vcc
; SI-NEXT: v_cndmask_b32_e32 v6, v8, v6, vcc
; SI-NEXT: v_fma_f64 v[0:1], -v[6:7], v[4:5], v[0:1]
; SI-NEXT: buffer_store_dwordx4 v[0:3], off, s[4:7], 0
; SI-NEXT: s_endpgm
;

View File

@ -76,13 +76,12 @@ define amdgpu_kernel void @v_round_f64(ptr addrspace(1) %out, ptr addrspace(1) %
; SI-NEXT: s_waitcnt lgkmcnt(0)
; SI-NEXT: s_mov_b64 s[4:5], s[2:3]
; SI-NEXT: buffer_load_dwordx2 v[2:3], v[0:1], s[4:7], 0 addr64
; SI-NEXT: s_movk_i32 s4, 0xfc01
; SI-NEXT: s_mov_b32 s2, -1
; SI-NEXT: s_mov_b32 s3, 0xfffff
; SI-NEXT: v_mov_b32_e32 v8, 0x3ff00000
; SI-NEXT: s_waitcnt vmcnt(0)
; SI-NEXT: v_bfe_u32 v4, v3, 20, 11
; SI-NEXT: v_add_i32_e32 v6, vcc, s4, v4
; SI-NEXT: v_add_i32_e32 v6, vcc, 0xfffffc01, v4
; SI-NEXT: v_lshr_b64 v[4:5], s[2:3], v6
; SI-NEXT: v_and_b32_e32 v7, 0x80000000, v3
; SI-NEXT: v_not_b32_e32 v5, v5

View File

@ -65,8 +65,8 @@ define void @func() sspreq nounwind {
; LINUX32: # %bb.0:
; LINUX32-NEXT: mflr 0
; LINUX32-NEXT: stwu 1, -16(1)
; LINUX32-NEXT: stw 0, 20(1)
; LINUX32-NEXT: lwz 3, -28680(2)
; LINUX32-NEXT: stw 0, 20(1)
; LINUX32-NEXT: stw 3, 12(1)
; LINUX32-NEXT: addi 3, 1, 8
; LINUX32-NEXT: bl capture
@ -86,8 +86,8 @@ define void @func() sspreq nounwind {
; LINUX64: # %bb.0:
; LINUX64-NEXT: mflr 0
; LINUX64-NEXT: stdu 1, -128(1)
; LINUX64-NEXT: std 0, 144(1)
; LINUX64-NEXT: ld 3, -28688(13)
; LINUX64-NEXT: std 0, 144(1)
; LINUX64-NEXT: std 3, 120(1)
; LINUX64-NEXT: addi 3, 1, 116
; LINUX64-NEXT: bl capture

View File

@ -1,53 +1,20 @@
; RUN: llc < %s | FileCheck %s
; RUN: llc < %s | FileCheck %s --check-prefix=CHECK --check-prefix=SAFE
; RUN: llc < %s -enable-unsafe-fp-math | FileCheck %s --check-prefix=CHECK --check-prefix=UNSAFE
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--"
; CHECK-LABEL: double_rounding_safe:
; CHECK: callq __trunctfdf2
; CHECK-NEXT: cvtsd2ss %xmm0
define void @double_rounding_safe(ptr %x, ptr %f) {
entry:
%x.fp128 = load fp128, ptr %x, align 16
%x.double = fptrunc fp128 %x.fp128 to double
%x.float = fptrunc double %x.double to float
store float %x.float, ptr %f, align 4
ret void
}
; CHECK-LABEL: double_rounding_contract_fst:
; CHECK: callq __trunctfdf2
; CHECK-NEXT: cvtsd2ss %xmm0
define void @double_rounding_contract_fst(ptr %x, ptr %f) {
entry:
%x.fp128 = load fp128, ptr %x, align 16
%x.double = fptrunc contract fp128 %x.fp128 to double
%x.float = fptrunc double %x.double to float
store float %x.float, ptr %f, align 4
ret void
}
; CHECK-LABEL: double_rounding_contract_snd:
; CHECK: callq __trunctfdf2
; CHECK-NEXT: cvtsd2ss %xmm0
define void @double_rounding_contract_snd(ptr %x, ptr %f) {
entry:
%x.fp128 = load fp128, ptr %x, align 16
%x.double = fptrunc fp128 %x.fp128 to double
%x.float = fptrunc contract double %x.double to float
store float %x.float, ptr %f, align 4
ret void
}
; CHECK-LABEL: double_rounding:
; CHECK: callq __trunctfsf2
; CHECK-NOT: cvt
; SAFE: callq __trunctfdf2
; SAFE-NEXT: cvtsd2ss %xmm0
; UNSAFE: callq __trunctfsf2
; UNSAFE-NOT: cvt
define void @double_rounding(ptr %x, ptr %f) {
entry:
%x.fp128 = load fp128, ptr %x, align 16
%x.double = fptrunc contract fp128 %x.fp128 to double
%x.float = fptrunc contract double %x.double to float
store float %x.float, ptr %f, align 4
%0 = load fp128, ptr %x, align 16
%1 = fptrunc fp128 %0 to double
%2 = fptrunc double %1 to float
store float %2, ptr %f, align 4
ret void
}

View File

@ -157,7 +157,8 @@ void ExecuteRegionOp::print(OpAsmPrinter &p) {
p.printRegion(getRegion(),
/*printEntryBlockArgs=*/false,
/*printBlockTerminators=*/true);
p.printOptionalAttrDict((*this)->getAttrs(), /*elidedAttrs=*/{"no_inline"});
p.printOptionalAttrDict((*this)->getAttrs());
}
LogicalResult ExecuteRegionOp::verify() {

View File

@ -1479,7 +1479,7 @@ func.func @execute_region_no_inline() {
// CHECK-NEXT: scf.execute_region
// CHECK-NEXT: %[[VAL:.*]] = "test.val"() : () -> i64
// CHECK-NEXT: scf.yield %[[VAL]] : i64
// CHECK-NOT: no_inline
// CHECK-NEXT: }
// -----

View File

@ -369,7 +369,6 @@ There are following check-* make targets for tests.
- ``check-ompt`` (ompt tests under runtime/test/ompt)
- ``check-ompt-multiplex`` (ompt multiplex tests under tools/multiplex/tests)
- ``check-ompt-omptest`` (ompt omptest tests under tools/omptest/tests)
- ``check-libarcher`` (libarcher tests under tools/archer/tests)
- ``check-libomp`` (libomp tests under runtime/test. This includes check-ompt tests too)
- ``check-libomptarget-*`` (libomptarget tests for specific target under libomptarget/test)

View File

@ -15,21 +15,6 @@ if(LIBOMP_OMPT_SUPPORT AND LIBOMP_ARCHER_SUPPORT)
target_link_libraries(archer ${CMAKE_DL_LIBS})
add_library(archer_static STATIC ompt-tsan.cpp)
if(TARGET cxx-headers)
add_dependencies(archer cxx-headers)
add_dependencies(archer_static cxx-headers)
endif()
if(TARGET cxx_shared)
add_dependencies(archer cxx_shared)
add_dependencies(archer_static cxx_shared)
endif()
if(TARGET cxxabi_shared)
add_dependencies(archer cxxabi_shared)
add_dependencies(archer_static cxxabi_shared)
endif()
install(TARGETS archer archer_static
LIBRARY DESTINATION ${OPENMP_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${OPENMP_INSTALL_LIBDIR})

View File

@ -1,154 +0,0 @@
##===----------------------------------------------------------------------===##
#
# Build OMPT unit testing library: ompTest
#
##===----------------------------------------------------------------------===##
cmake_minimum_required(VERSION 3.20)
project(omptest LANGUAGES CXX)
option(LIBOMPTEST_BUILD_STANDALONE
"Build ompTest 'standalone', i.e. w/o GoogleTest."
${OPENMP_STANDALONE_BUILD})
option(LIBOMPTEST_BUILD_UNITTESTS
"Build ompTest's unit tests, requires GoogleTest." OFF)
# In absence of corresponding OMPT support: exit early
if(NOT ${LIBOMP_OMPT_SUPPORT})
return()
endif()
include(CMakePackageConfigHelpers)
set(OMPTEST_HEADERS
./include/AssertMacros.h
./include/InternalEvent.h
./include/InternalEventCommon.h
./include/Logging.h
./include/OmptAliases.h
./include/OmptAsserter.h
./include/OmptAssertEvent.h
./include/OmptCallbackHandler.h
./include/OmptTester.h
./include/OmptTesterGlobals.h
)
add_library(omptest
SHARED
${OMPTEST_HEADERS}
./src/InternalEvent.cpp
./src/InternalEventOperators.cpp
./src/Logging.cpp
./src/OmptAsserter.cpp
./src/OmptAssertEvent.cpp
./src/OmptCallbackHandler.cpp
./src/OmptTester.cpp
)
# Target: ompTest library
# On (implicit) request of GoogleTest, link against the one provided with LLVM.
if ((NOT LIBOMPTEST_BUILD_STANDALONE) OR LIBOMPTEST_BUILD_UNITTESTS)
# Check if standalone build was requested together with unittests
if (LIBOMPTEST_BUILD_STANDALONE)
# Emit warning: this build actually depends on LLVM's GoogleTest
message(WARNING "LIBOMPTEST_BUILD_STANDALONE and LIBOMPTEST_BUILD_UNITTESTS"
" requested simultaneously.\n"
"Linking against LLVM's GoogleTest library archives.\n"
"Disable LIBOMPTEST_BUILD_UNITTESTS to perform an actual"
" standalone build.")
# Explicitly disable LIBOMPTEST_BUILD_STANDALONE
set(LIBOMPTEST_BUILD_STANDALONE OFF)
endif()
# Make sure target llvm_gtest is available
if (NOT TARGET llvm_gtest)
message(FATAL_ERROR "Required target not found: llvm_gtest")
endif()
# Add llvm_gtest as dependency
add_dependencies(omptest llvm_gtest)
# Link llvm_gtest as whole-archive to expose required symbols
set(GTEST_LINK_CMD "-Wl,--whole-archive" llvm_gtest
"-Wl,--no-whole-archive" LLVMSupport)
# Add GoogleTest-based header
target_sources(omptest PRIVATE ./include/OmptTesterGoogleTest.h)
# Add LLVM-provided GoogleTest include directories.
target_include_directories(omptest PRIVATE
${LLVM_THIRD_PARTY_DIR}/unittest/googletest/include)
# TODO: Re-visit ABI breaking checks, disable for now.
target_compile_definitions(omptest PUBLIC
-DLLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING)
# Link against gtest and gtest_main
target_link_libraries(omptest PRIVATE ${GTEST_LINK_CMD})
else()
# Add 'standalone' compile definitions
target_compile_definitions(omptest PRIVATE
-DOPENMP_LIBOMPTEST_BUILD_STANDALONE)
# Add 'standalone' source files
target_sources(omptest PRIVATE
./include/OmptTesterStandalone.h
./src/OmptTesterStandalone.cpp)
endif()
if(TARGET cxx-headers)
add_dependencies(omptest cxx-headers)
endif()
if(TARGET cxx_shared)
add_dependencies(omptest cxx_shared)
endif()
if(TARGET cxxabi_shared)
add_dependencies(omptest cxxabi_shared)
endif()
# Add common include directories.
target_include_directories(omptest PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${LIBOMP_HEADERS_INSTALL_PATH}/omptest>
)
target_compile_features(omptest PRIVATE cxx_std_17)
# Create and install package configuration files.
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/omptest-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/cmake/omptest-config.cmake
INSTALL_DESTINATION "${OPENMP_INSTALL_LIBDIR}/cmake/openmp/omptest"
)
install(FILES ${omptest_BINARY_DIR}/cmake/omptest-config.cmake
DESTINATION "${OPENMP_INSTALL_LIBDIR}/cmake/openmp/omptest")
# Install libomptest header files: Copy header-files from include dir
install(DIRECTORY ./include/
DESTINATION "${LIBOMP_HEADERS_INSTALL_PATH}/omptest"
FILES_MATCHING PATTERN "*.h")
# Install library and export targets.
# Note: find_package(omptest) may require setting of PATH_SUFFIXES
# Example: "lib/cmake/openmp/omptest", this is due to the install location
install(TARGETS omptest
EXPORT OPENMPomptest
LIBRARY COMPONENT omptest
DESTINATION "${OPENMP_INSTALL_LIBDIR}"
INCLUDES DESTINATION "${LIBOMP_HEADERS_INSTALL_PATH}/omptest")
# Allow to link omptest by using: target_link_libraries( ... omptest::omptest)
# Additionally, it automatically propagates the include directory.
install(EXPORT OPENMPomptest
DESTINATION "${OPENMP_INSTALL_LIBDIR}/cmake/openmp/omptest"
NAMESPACE omptest::
FILE omptest-targets.cmake)
# Discover unit tests (added to check-openmp)
if(LIBOMPTEST_BUILD_UNITTESTS)
add_subdirectory(test)
endif()

View File

@ -1,279 +0,0 @@
README for the OpenMP Tooling Interface Testing Library (ompTest)
=================================================================
# Introduction
OpenMP Tooling Interface Testing Library (ompTest)
ompTest is a unit testing framework for testing OpenMP implementations.
It offers a simple-to-use framework that allows a tester to check for OMPT
events in addition to regular unit testing code, supported by linking against
GoogleTest by default. It also facilitates writing concise tests while bridging
the semantic gap between the unit under test and the OMPT-event testing.
# Testing macros
Corresponding macro definitions are located in: `./include/AssertMacros.h`
## OMPT_GENERATE_EVENTS(NumberOfCopies, EventMacro)
`TODO`
## OMPT_ASSERT_SET_EVENT(Name, Group, EventTy, ...)
`TODO`
## OMPT_ASSERT_SET(EventTy, ...)
`TODO`
## OMPT_ASSERT_SET_GROUPED(Group, EventTy, ...)
`TODO`
## OMPT_ASSERT_SET_NAMED(Name, EventTy, ...)
`TODO`
## OMPT_ASSERT_SET_EVENT_NOT(Name, Group, EventTy, ...)
`TODO`
## OMPT_ASSERT_SET_NOT(EventTy, ...)
`TODO`
## OMPT_ASSERT_SET_GROUPED_NOT(Group, EventTy, ...)
`TODO`
## OMPT_ASSERT_SET_NAMED_NOT(Name, EventTy, ...)
`TODO`
## OMPT_ASSERT_SEQUENCE_EVENT(Name, Group, EventTy, ...)
`TODO`
## OMPT_ASSERT_SEQUENCE(EventTy, ...)
This macro checks for the occurrence of the provided event, which also
entails the exact sequence of events. When only using this assertion macro one
has to provide every single event in the exact order of occurrence.
## OMPT_ASSERT_SEQUENCE_GROUPED(Group, EventTy, ...)
This macro acts like `OMPT_ASSERT_SEQUENCE` with the addition of grouping.
## OMPT_ASSERT_SEQUENCE_NAMED(Name, EventTy, ...)
`TODO`
## OMPT_ASSERT_SEQUENCE_EVENT_NOT(Name, Group, EventTy, ...)
`TODO`
## OMPT_ASSERT_SEQUENCE_NOT(EventTy, ...)
`TODO`
## OMPT_ASSERT_SEQUENCE_GROUPED_NOT(Group, EventTy, ...)
`TODO`
## OMPT_ASSERT_SEQUENCE_NAMED_NOT(Name, EventTy, ...)
`TODO`
## OMPT_ASSERT_SEQUENCE_SUSPEND()
`TODO`
## OMPT_ASSERT_SEQUENCE_ONLY(EventTy, ...)
This macro acts like `OMPT_ASSERT_SEQUENCE`, while actually being preceded
-AND- succeeded by commands to suspend sequenced assertion until the next match.
As a result, one may omit all other "unnecessary" events from the sequence.
## OMPT_ASSERT_SEQUENCE_GROUPED_ONLY(Group, EventTy, ...)
This macro acts like `OMPT_ASSERT_SEQUENCE_ONLY`, plus grouping.
## OMPT_ASSERT_SEQUENCE_NAMED_ONLY(Name, EventTy, ...)
`TODO`
## OMPT_ASSERTER_MODE_STRICT(Asserter)
`TODO`
## OMPT_ASSERTER_MODE_RELAXED(Asserter)
`TODO`
## OMPT_ASSERT_SEQUENCE_MODE_STRICT()
`TODO`
## OMPT_ASSERT_SEQUENCE_MODE_RELAXED()
`TODO`
## OMPT_ASSERT_SET_MODE_STRICT()
`TODO`
## OMPT_ASSERT_SET_MODE_RELAXED()
`TODO`
## OMPT_ASSERTER_DISABLE(Asserter)
`TODO`
## OMPT_ASSERTER_ENABLE(Asserter)
`TODO`
## OMPT_ASSERT_SET_DISABLE()
`TODO`
## OMPT_ASSERT_SET_ENABLE()
`TODO`
## OMPT_ASSERT_SEQUENCE_DISABLE()
`TODO`
## OMPT_ASSERT_SEQUENCE_ENABLE()
`TODO`
## OMPT_REPORT_EVENT_DISABLE()
`TODO`
## OMPT_REPORT_EVENT_ENABLE()
`TODO`
## OMPT_ASSERTER_PERMIT_EVENT(Asserter, EventTy)
`TODO`
## OMPT_ASSERTER_SUPPRESS_EVENT(Asserter, EventTy)
`TODO`
## OMPT_PERMIT_EVENT(EventTy)
`TODO`
## OMPT_SUPPRESS_EVENT(EventTy)
`TODO`
## OMPT_ASSERTER_LOG_LEVEL(Asserter, LogLevel)
`TODO`
## OMPT_ASSERTER_LOG_FORMATTED(Asserter, FormatLog)
`TODO`
## OMPT_ASSERT_SYNC_POINT(SyncPointName)
`TODO`
### Grouping Asserts
This allows to generate and verify data during runtime of a test.
Currently, we only use target region information which manifests into groups.
This allows to correlate multiple events to a certain target region without
manual interaction just by specifying a groupname for these events.
When a target region is encountered and we are about to enter it, we gather the
`target_id` (non-EMI) -OR- `target_data->value` (EMI). This value is stored
along the groupname for future reference. Upon target region end, the
corresponding group is erased. (Note: The groupname is available again.)
Other asserted callbacks which may occur within target regions query their
groupname: retrieving and comparing the value of the group against the observed
event's value.
### Suspending Sequenced Asserts
When a sequence of events is not of interest while testing, these additional
events may be ignored by suspending the assertion until the next match. This
can be done by using `OMPT_ASSERT_SEQUENCE_SUSPEND` manually or the `_ONLY`
macro variants, like `OMPT_ASSERT_GROUPED_SEQUENCE_ONLY`.
The former adds a special event to the queue of expected events and signal
that any non-matching event should be ignored rather than failing the test.
`_ONLY` macros embed their corresponding macro between two calls to
`OMPT_ASSERT_SEQUENCE_SUSPEND`. As a consequence, we enter passive assertion
until a match occurs, then enter passive assertion again. This enables us to
"only" assert a certain, single event in arbitrary circumstances.
### Asserter Modes
`TODO`
## Aliases (shorthands)
To allow for easier writing of tests and enhanced readability, the following set
of aliases is introduced. The left hand side represents the original value,
while the right hand side depicts the shorthand version.
| Type | Enum Value | Shorthand |
|---------------------------|---------------------------------------------|---------------------------|
| **ompt_scope_endpoint_t** | | |
| | ompt_scope_begin | BEGIN |
| | ompt_scope_end | END |
| | ompt_scope_beginend | BEGINEND |
| **ompt_target_t** | | |
| | ompt_target | TARGET |
| | ompt_target_enter_data | ENTER_DATA |
| | ompt_target_exit_data | EXIT_DATA |
| | ompt_target_update | UPDATE |
| | ompt_target_nowait | TARGET_NOWAIT |
| | ompt_target_enter_data_nowait | ENTER_DATA_NOWAIT |
| | ompt_target_exit_data_nowait | EXIT_DATA_NOWAIT |
| | ompt_target_update_nowait | UPDATE_NOWAIT |
| **ompt_target_data_op_t** | | |
| | ompt_target_data_alloc | ALLOC |
| | ompt_target_data_transfer_to_device | H2D |
| | ompt_target_data_transfer_from_device | D2H |
| | ompt_target_data_delete | DELETE |
| | ompt_target_data_associate | ASSOCIATE |
| | ompt_target_data_disassociate | DISASSOCIATE |
| | ompt_target_data_alloc_async | ALLOC_ASYNC |
| | ompt_target_data_transfer_to_device_async | H2D_ASYNC |
| | ompt_target_data_transfer_from_device_async | D2H_ASYNC |
| | ompt_target_data_delete_async | DELETE_ASYNC |
| **ompt_callbacks_t** | | |
| | ompt_callback_target | CB_TARGET |
| | ompt_callback_target_data_op | CB_DATAOP |
| | ompt_callback_target_submit | CB_KERNEL |
| **ompt_work_t** | | |
| | ompt_work_loop | WORK_LOOP |
| | ompt_work_sections | WORK_SECT |
| | ompt_work_single_executor | WORK_EXEC |
| | ompt_work_single_other | WORK_SINGLE |
| | ompt_work_workshare | WORK_SHARE |
| | ompt_work_distribute | WORK_DIST |
| | ompt_work_taskloop | WORK_TASK |
| | ompt_work_scope | WORK_SCOPE |
| | ompt_work_loop_static | WORK_LOOP_STA |
| | ompt_work_loop_dynamic | WORK_LOOP_DYN |
| | ompt_work_loop_guided | WORK_LOOP_GUI |
| | ompt_work_loop_other | WORK_LOOP_OTH |
| **ompt_sync_region_t** | | |
| | ompt_sync_region_barrier | SR_BARRIER |
| | ompt_sync_region_barrier_implicit | SR_BARRIER_IMPL |
| | ompt_sync_region_barrier_explicit | SR_BARRIER_EXPL |
| | ompt_sync_region_barrier_implementation | SR_BARRIER_IMPLEMENTATION |
| | ompt_sync_region_taskwait | SR_TASKWAIT |
| | ompt_sync_region_taskgroup | SR_TASKGROUP |
| | ompt_sync_region_reduction | SR_REDUCTION |
| | ompt_sync_region_barrier_implicit_workshare | SR_BARRIER_IMPL_WORKSHARE |
| | ompt_sync_region_barrier_implicit_parallel | SR_BARRIER_IMPL_PARALLEL |
| | ompt_sync_region_barrier_teams | SR_BARRIER_TEAMS |
Limitations
===========
Currently, there are some peculiarities which have to be kept in mind when using
this library:
## Callbacks
* It is not possible to e.g. test non-EMI -AND- EMI callbacks within the same
test file. Reason: all testsuites share the initialization and therefore the
registered callbacks.
* It is not possible to check for device initialization and/or load callbacks
more than once per test file. The first testcase being run, triggers these
callbacks and is therefore the only testcase that is able to check for them.
This is because, after that, the device remains initialized.
* It is not possible to check for device finalization callbacks, as libomptest
is un-loaded before this callback occurs. Same holds true for the final
ThreadEnd event(s).
Miscellaneous
=============
## Default values
To allow for easier writing of tests, many OMPT events may be created using less
parameters than actually requested by the spec -- by using default values. These
defaults are currently set to the corresponding data type's minimum as follows,
for example integers use: `std::numeric_limits<int>::min()`.
When an expected / user-specified event has certain values set to the
corresponding default, these values are ignored. That is, when compared to an
observed event, this property is considered as 'equal' regardless of their
actual equality relation.
References
==========
[0]: ompTest Unit Testing with OMPT
https://doi.org/10.1109/SCW63240.2024.00031
[1]: OMPTBench OpenMP Tool Interface Conformance Testing
https://doi.org/10.1109/SCW63240.2024.00036

View File

@ -1,32 +0,0 @@
################################################################################
##
## omptest cmake configuration file.
## Enable support for find_package(omptest).
##
################################################################################
# Initialize package.
@PACKAGE_INIT@
# Include exported targets.
include("${CMAKE_CURRENT_LIST_DIR}/omptest-targets.cmake")
# Provide information, if ompTest has been built 'standalone'.
set(LIBOMPTEST_BUILD_STANDALONE "@LIBOMPTEST_BUILD_STANDALONE@")
# Note: The following variables are meant as a fallback.
# But eventually we may remove them in favor of linking via namespace.
# Set LLVM installation root directory by using exported package information.
set(LLVM_ROOT "${PACKAGE_PREFIX_DIR}")
# Provide header and library paths.
set(LIBOMP_HEADERS_INSTALL_PATH "${LLVM_ROOT}/@LIBOMP_HEADERS_INSTALL_PATH@")
set(LIBOMP_LIBRARY_INSTALL_PATH "${LLVM_ROOT}/@OPENMP_INSTALL_LIBDIR@")
set(omptest_INCLUDE_DIR "${LIBOMP_HEADERS_INSTALL_PATH}/omptest")
set(omptest_LIBRARY_DIR "${LIBOMP_LIBRARY_INSTALL_PATH}")
# Provide compiler default values.
set(LLVM_BIN_INSTALL_DIR "${LLVM_ROOT}/bin")
set(omptest_C_COMPILER "${LLVM_BIN_INSTALL_DIR}/clang")
set(omptest_CXX_COMPILER "${LLVM_BIN_INSTALL_DIR}/clang++")

View File

@ -1,138 +0,0 @@
//===- AssertMacros.h - Macro aliases for ease-of-use -----------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Provides macros to be used in unit tests for OMPT events.
///
//===----------------------------------------------------------------------===//
#ifndef OPENMP_TOOLS_OMPTEST_INCLUDE_ASSERTMACROS_H
#define OPENMP_TOOLS_OMPTEST_INCLUDE_ASSERTMACROS_H
#define OMPTEST_EXCLUDED_EVENT omptest::ObserveState::Never
#define OMPTEST_REQUIRED_EVENT omptest::ObserveState::Always
/// ASSERT MACROS TO BE USED BY THE USER
#define OMPT_GENERATE_EVENTS(NumberOfCopies, EventMacro) \
for (size_t i = 0; i < NumberOfCopies; ++i) { \
EventMacro \
}
// Handle a minimum unordered set of events
// Required events
#define OMPT_ASSERT_SET_EVENT(Name, Group, EventTy, ...) \
SetAsserter->insert(OmptAssertEvent::EventTy( \
Name, Group, OMPTEST_REQUIRED_EVENT, __VA_ARGS__));
#define OMPT_ASSERT_SET(EventTy, ...) \
OMPT_ASSERT_SET_EVENT("", "", EventTy, __VA_ARGS__)
#define OMPT_ASSERT_SET_GROUPED(Group, EventTy, ...) \
OMPT_ASSERT_SET_EVENT("", Group, EventTy, __VA_ARGS__)
#define OMPT_ASSERT_SET_NAMED(Name, EventTy, ...) \
OMPT_ASSERT_SET_EVENT(Name, "", EventTy, __VA_ARGS__)
// Excluded ("NOT") events
#define OMPT_ASSERT_SET_EVENT_NOT(Name, Group, EventTy, ...) \
SetAsserter->insert(OmptAssertEvent::EventTy( \
Name, Group, OMPTEST_EXCLUDED_EVENT, __VA_ARGS__));
#define OMPT_ASSERT_SET_NOT(EventTy, ...) \
OMPT_ASSERT_SET_EVENT_NOT("", "", EventTy, __VA_ARGS__)
#define OMPT_ASSERT_SET_GROUPED_NOT(Group, EventTy, ...) \
OMPT_ASSERT_SET_EVENT_NOT("", Group, EventTy, __VA_ARGS__)
#define OMPT_ASSERT_SET_NAMED_NOT(Name, EventTy, ...) \
OMPT_ASSERT_SET_EVENT_NOT(Name, "", EventTy, __VA_ARGS__)
// Handle an exact sequence of events
// Required events
#define OMPT_ASSERT_SEQUENCE_EVENT(Name, Group, EventTy, ...) \
SequenceAsserter->insert(OmptAssertEvent::EventTy( \
Name, Group, OMPTEST_REQUIRED_EVENT, __VA_ARGS__));
#define OMPT_ASSERT_SEQUENCE(EventTy, ...) \
OMPT_ASSERT_SEQUENCE_EVENT("", "", EventTy, __VA_ARGS__)
#define OMPT_ASSERT_SEQUENCE_GROUPED(Group, EventTy, ...) \
OMPT_ASSERT_SEQUENCE_EVENT("", Group, EventTy, __VA_ARGS__)
#define OMPT_ASSERT_SEQUENCE_NAMED(Name, EventTy, ...) \
OMPT_ASSERT_SEQUENCE_EVENT(Name, "", EventTy, __VA_ARGS__)
// Excluded ("NOT") events
#define OMPT_ASSERT_SEQUENCE_EVENT_NOT(Name, Group, EventTy, ...) \
SequenceAsserter->insert(OmptAssertEvent::EventTy( \
Name, Group, OMPTEST_EXCLUDED_EVENT, __VA_ARGS__));
#define OMPT_ASSERT_SEQUENCE_NOT(EventTy, ...) \
OMPT_ASSERT_SEQUENCE_EVENT_NOT("", "", EventTy, __VA_ARGS__)
#define OMPT_ASSERT_SEQUENCE_GROUPED_NOT(Group, EventTy, ...) \
OMPT_ASSERT_SEQUENCE_EVENT_NOT("", Group, EventTy, __VA_ARGS__)
#define OMPT_ASSERT_SEQUENCE_NAMED_NOT(Name, EventTy, ...) \
OMPT_ASSERT_SEQUENCE_EVENT_NOT(Name, "", EventTy, __VA_ARGS__)
// Special command: suspend active assertion
// The created event is not correlated to any observed event
#define OMPT_ASSERT_SEQUENCE_SUSPEND() \
SequenceAsserter->insert( \
OmptAssertEvent::AssertionSuspend("", "", OMPTEST_EXCLUDED_EVENT));
#define OMPT_ASSERT_SEQUENCE_ONLY(EventTy, ...) \
OMPT_ASSERT_SEQUENCE_SUSPEND() \
OMPT_ASSERT_SEQUENCE_EVENT("", "", EventTy, __VA_ARGS__) \
OMPT_ASSERT_SEQUENCE_SUSPEND()
#define OMPT_ASSERT_SEQUENCE_GROUPED_ONLY(Group, EventTy, ...) \
OMPT_ASSERT_SEQUENCE_SUSPEND() \
OMPT_ASSERT_SEQUENCE_EVENT("", Group, EventTy, __VA_ARGS__) \
OMPT_ASSERT_SEQUENCE_SUSPEND()
#define OMPT_ASSERT_SEQUENCE_NAMED_ONLY(Name, EventTy, ...) \
OMPT_ASSERT_SEQUENCE_SUSPEND() \
OMPT_ASSERT_SEQUENCE_EVENT(Name, "", EventTy, __VA_ARGS__) \
OMPT_ASSERT_SEQUENCE_SUSPEND()
#define OMPT_ASSERTER_MODE_STRICT(Asserter) \
Asserter->setOperationMode(AssertMode::Strict);
#define OMPT_ASSERTER_MODE_RELAXED(Asserter) \
Asserter->setOperationMode(AssertMode::Relaxed);
#define OMPT_ASSERT_SEQUENCE_MODE_STRICT() \
OMPT_ASSERTER_MODE_STRICT(SequenceAsserter)
#define OMPT_ASSERT_SEQUENCE_MODE_RELAXED() \
OMPT_ASSERTER_MODE_RELAXED(SequenceAsserter)
#define OMPT_ASSERT_SET_MODE_STRICT() OMPT_ASSERTER_MODE_STRICT(SetAsserter)
#define OMPT_ASSERT_SET_MODE_RELAXED() OMPT_ASSERTER_MODE_RELAXED(SetAsserter)
// Enable / disable asserters entirely
#define OMPT_ASSERTER_DISABLE(Asserter) Asserter->setActive(false);
#define OMPT_ASSERTER_ENABLE(Asserter) Asserter->setActive(true);
#define OMPT_ASSERT_SET_DISABLE() OMPT_ASSERTER_DISABLE(SetAsserter)
#define OMPT_ASSERT_SET_ENABLE() OMPT_ASSERTER_ENABLE(SetAsserter)
#define OMPT_ASSERT_SEQUENCE_DISABLE() OMPT_ASSERTER_DISABLE(SequenceAsserter)
#define OMPT_ASSERT_SEQUENCE_ENABLE() OMPT_ASSERTER_ENABLE(SequenceAsserter)
#define OMPT_REPORT_EVENT_DISABLE() OMPT_ASSERTER_DISABLE(EventReporter)
#define OMPT_REPORT_EVENT_ENABLE() OMPT_ASSERTER_ENABLE(EventReporter)
// Enable / disable certain event types for asserters
#define OMPT_ASSERTER_PERMIT_EVENT(Asserter, EventTy) \
Asserter->permitEvent(EventTy);
#define OMPT_ASSERTER_SUPPRESS_EVENT(Asserter, EventTy) \
Asserter->suppressEvent(EventTy);
#define OMPT_PERMIT_EVENT(EventTy) \
OMPT_ASSERTER_PERMIT_EVENT(SetAsserter, EventTy); \
OMPT_ASSERTER_PERMIT_EVENT(EventReporter, EventTy); \
OMPT_ASSERTER_PERMIT_EVENT(SequenceAsserter, EventTy);
#define OMPT_SUPPRESS_EVENT(EventTy) \
OMPT_ASSERTER_SUPPRESS_EVENT(SetAsserter, EventTy); \
OMPT_ASSERTER_SUPPRESS_EVENT(EventReporter, EventTy); \
OMPT_ASSERTER_SUPPRESS_EVENT(SequenceAsserter, EventTy);
// Set logging level for asserters
// Note: Logger is a singleton, hence this will affect all asserter instances
#define OMPT_ASSERTER_LOG_LEVEL(Asserter, LogLevel) \
Asserter->getLog()->setLoggingLevel(LogLevel);
// Set log formatting (esp. coloring) for asserters
// Note: Logger is a singleton, hence this will affect all asserter instances
#define OMPT_ASSERTER_LOG_FORMATTED(Asserter, FormatLog) \
Asserter->getLog()->setFormatOutput(FormatLog);
// SyncPoint handling
#define OMPT_ASSERT_SYNC_POINT(SyncPointName) \
flush_traced_devices(); \
OmptCallbackHandler::get().handleAssertionSyncPoint(SyncPointName);
#endif

View File

@ -1,436 +0,0 @@
//===- InternalEvent.h - Internal event representation ----------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Declares internal event representations along the default CTOR definition.
///
//===----------------------------------------------------------------------===//
#ifndef OPENMP_TOOLS_OMPTEST_INCLUDE_INTERNALEVENT_H
#define OPENMP_TOOLS_OMPTEST_INCLUDE_INTERNALEVENT_H
#include "InternalEventCommon.h"
#include <cstring>
#include <limits>
#include <omp-tools.h>
#define expectedDefault(TypeName) std::numeric_limits<TypeName>::min()
namespace omptest {
namespace util {
/// String manipulation helper function. Takes up to 8 bytes of data and returns
/// their hexadecimal representation as string. The data can be expanded to the
/// given size in bytes and will by default be prefixed with '0x'.
std::string makeHexString(uint64_t Data, bool IsPointer = true,
size_t DataBytes = 0, bool ShowHexBase = true);
} // namespace util
namespace internal {
struct AssertionSyncPoint : public EventBase<AssertionSyncPoint> {
std::string toString() const override;
AssertionSyncPoint(const std::string &Name) : Name(Name) {}
const std::string Name;
};
struct AssertionSuspend : public EventBase<AssertionSuspend> {
AssertionSuspend() = default;
};
struct ThreadBegin : public EventBase<ThreadBegin> {
std::string toString() const override;
ThreadBegin(ompt_thread_t ThreadType) : ThreadType(ThreadType) {}
ompt_thread_t ThreadType;
};
struct ThreadEnd : public EventBase<ThreadEnd> {
std::string toString() const override;
ThreadEnd() = default;
};
struct ParallelBegin : public EventBase<ParallelBegin> {
std::string toString() const override;
ParallelBegin(int NumThreads) : NumThreads(NumThreads) {}
unsigned int NumThreads;
};
struct ParallelEnd : public EventBase<ParallelEnd> {
std::string toString() const override;
ParallelEnd(ompt_data_t *ParallelData, ompt_data_t *EncounteringTaskData,
int Flags, const void *CodeptrRA)
: ParallelData(ParallelData), EncounteringTaskData(EncounteringTaskData),
Flags(Flags), CodeptrRA(CodeptrRA) {}
ompt_data_t *ParallelData;
ompt_data_t *EncounteringTaskData;
int Flags;
const void *CodeptrRA;
};
struct Work : public EventBase<Work> {
std::string toString() const override;
Work(ompt_work_t WorkType, ompt_scope_endpoint_t Endpoint,
ompt_data_t *ParallelData, ompt_data_t *TaskData, uint64_t Count,
const void *CodeptrRA)
: WorkType(WorkType), Endpoint(Endpoint), ParallelData(ParallelData),
TaskData(TaskData), Count(Count), CodeptrRA(CodeptrRA) {}
ompt_work_t WorkType;
ompt_scope_endpoint_t Endpoint;
ompt_data_t *ParallelData;
ompt_data_t *TaskData;
uint64_t Count;
const void *CodeptrRA;
};
struct Dispatch : public EventBase<Dispatch> {
std::string toString() const override;
Dispatch(ompt_data_t *ParallelData, ompt_data_t *TaskData,
ompt_dispatch_t Kind, ompt_data_t Instance)
: ParallelData(ParallelData), TaskData(TaskData), Kind(Kind),
Instance(Instance) {}
ompt_data_t *ParallelData;
ompt_data_t *TaskData;
ompt_dispatch_t Kind;
ompt_data_t Instance;
};
struct TaskCreate : public EventBase<TaskCreate> {
std::string toString() const override;
TaskCreate(ompt_data_t *EncounteringTaskData,
const ompt_frame_t *EncounteringTaskFrame,
ompt_data_t *NewTaskData, int Flags, int HasDependences,
const void *CodeptrRA)
: EncounteringTaskData(EncounteringTaskData),
EncounteringTaskFrame(EncounteringTaskFrame), NewTaskData(NewTaskData),
Flags(Flags), HasDependences(HasDependences), CodeptrRA(CodeptrRA) {}
ompt_data_t *EncounteringTaskData;
const ompt_frame_t *EncounteringTaskFrame;
ompt_data_t *NewTaskData;
int Flags;
int HasDependences;
const void *CodeptrRA;
};
struct Dependences : public EventBase<Dependences> {
Dependences() = default;
};
struct TaskDependence : public EventBase<TaskDependence> {
TaskDependence() = default;
};
struct TaskSchedule : public EventBase<TaskSchedule> {
TaskSchedule() = default;
};
struct ImplicitTask : public EventBase<ImplicitTask> {
std::string toString() const override;
ImplicitTask(ompt_scope_endpoint_t Endpoint, ompt_data_t *ParallelData,
ompt_data_t *TaskData, unsigned int ActualParallelism,
unsigned int Index, int Flags)
: Endpoint(Endpoint), ParallelData(ParallelData), TaskData(TaskData),
ActualParallelism(ActualParallelism), Index(Index), Flags(Flags) {}
ompt_scope_endpoint_t Endpoint;
ompt_data_t *ParallelData;
ompt_data_t *TaskData;
unsigned int ActualParallelism;
unsigned int Index;
int Flags;
};
struct Masked : public EventBase<Masked> {
Masked() = default;
};
struct SyncRegion : public EventBase<SyncRegion> {
std::string toString() const override;
SyncRegion(ompt_sync_region_t Kind, ompt_scope_endpoint_t Endpoint,
ompt_data_t *ParallelData, ompt_data_t *TaskData,
const void *CodeptrRA)
: Kind(Kind), Endpoint(Endpoint), ParallelData(ParallelData),
TaskData(TaskData), CodeptrRA(CodeptrRA) {}
ompt_sync_region_t Kind;
ompt_scope_endpoint_t Endpoint;
ompt_data_t *ParallelData;
ompt_data_t *TaskData;
const void *CodeptrRA;
};
struct MutexAcquire : public EventBase<MutexAcquire> {
MutexAcquire() = default;
};
struct Mutex : public EventBase<Mutex> {
Mutex() = default;
};
struct NestLock : public EventBase<NestLock> {
NestLock() = default;
};
struct Flush : public EventBase<Flush> {
Flush() = default;
};
struct Cancel : public EventBase<Cancel> {
Cancel() = default;
};
struct Target : public EventBase<Target> {
std::string toString() const override;
Target(ompt_target_t Kind, ompt_scope_endpoint_t Endpoint, int DeviceNum,
ompt_data_t *TaskData, ompt_id_t TargetId, const void *CodeptrRA)
: Kind(Kind), Endpoint(Endpoint), DeviceNum(DeviceNum),
TaskData(TaskData), TargetId(TargetId), CodeptrRA(CodeptrRA) {}
ompt_target_t Kind;
ompt_scope_endpoint_t Endpoint;
int DeviceNum;
ompt_data_t *TaskData;
ompt_id_t TargetId;
const void *CodeptrRA;
};
struct TargetEmi : public EventBase<TargetEmi> {
std::string toString() const override;
TargetEmi(ompt_target_t Kind, ompt_scope_endpoint_t Endpoint, int DeviceNum,
ompt_data_t *TaskData, ompt_data_t *TargetTaskData,
ompt_data_t *TargetData, const void *CodeptrRA)
: Kind(Kind), Endpoint(Endpoint), DeviceNum(DeviceNum),
TaskData(TaskData), TargetTaskData(TargetTaskData),
TargetData(TargetData), CodeptrRA(CodeptrRA) {}
ompt_target_t Kind;
ompt_scope_endpoint_t Endpoint;
int DeviceNum;
ompt_data_t *TaskData;
ompt_data_t *TargetTaskData;
ompt_data_t *TargetData;
const void *CodeptrRA;
};
struct TargetDataOp : public EventBase<TargetDataOp> {
std::string toString() const override;
TargetDataOp(ompt_id_t TargetId, ompt_id_t HostOpId,
ompt_target_data_op_t OpType, void *SrcAddr, int SrcDeviceNum,
void *DstAddr, int DstDeviceNum, size_t Bytes,
const void *CodeptrRA)
: TargetId(TargetId), HostOpId(HostOpId), OpType(OpType),
SrcAddr(SrcAddr), SrcDeviceNum(SrcDeviceNum), DstAddr(DstAddr),
DstDeviceNum(DstDeviceNum), Bytes(Bytes), CodeptrRA(CodeptrRA) {}
ompt_id_t TargetId;
ompt_id_t HostOpId;
ompt_target_data_op_t OpType;
void *SrcAddr;
int SrcDeviceNum;
void *DstAddr;
int DstDeviceNum;
size_t Bytes;
const void *CodeptrRA;
};
struct TargetDataOpEmi : public EventBase<TargetDataOpEmi> {
std::string toString() const override;
TargetDataOpEmi(ompt_scope_endpoint_t Endpoint, ompt_data_t *TargetTaskData,
ompt_data_t *TargetData, ompt_id_t *HostOpId,
ompt_target_data_op_t OpType, void *SrcAddr, int SrcDeviceNum,
void *DstAddr, int DstDeviceNum, size_t Bytes,
const void *CodeptrRA)
: Endpoint(Endpoint), TargetTaskData(TargetTaskData),
TargetData(TargetData), HostOpId(HostOpId), OpType(OpType),
SrcAddr(SrcAddr), SrcDeviceNum(SrcDeviceNum), DstAddr(DstAddr),
DstDeviceNum(DstDeviceNum), Bytes(Bytes), CodeptrRA(CodeptrRA) {}
ompt_scope_endpoint_t Endpoint;
ompt_data_t *TargetTaskData;
ompt_data_t *TargetData;
ompt_id_t *HostOpId;
ompt_target_data_op_t OpType;
void *SrcAddr;
int SrcDeviceNum;
void *DstAddr;
int DstDeviceNum;
size_t Bytes;
const void *CodeptrRA;
};
struct TargetSubmit : public EventBase<TargetSubmit> {
std::string toString() const override;
TargetSubmit(ompt_id_t TargetId, ompt_id_t HostOpId,
unsigned int RequestedNumTeams)
: TargetId(TargetId), HostOpId(HostOpId),
RequestedNumTeams(RequestedNumTeams) {}
ompt_id_t TargetId;
ompt_id_t HostOpId;
unsigned int RequestedNumTeams;
};
struct TargetSubmitEmi : public EventBase<TargetSubmitEmi> {
std::string toString() const override;
TargetSubmitEmi(ompt_scope_endpoint_t Endpoint, ompt_data_t *TargetData,
ompt_id_t *HostOpId, unsigned int RequestedNumTeams)
: Endpoint(Endpoint), TargetData(TargetData), HostOpId(HostOpId),
RequestedNumTeams(RequestedNumTeams) {}
ompt_scope_endpoint_t Endpoint;
ompt_data_t *TargetData;
ompt_id_t *HostOpId;
unsigned int RequestedNumTeams;
};
struct ControlTool : public EventBase<ControlTool> {
ControlTool() = default;
};
struct DeviceInitialize : public EventBase<DeviceInitialize> {
std::string toString() const override;
DeviceInitialize(int DeviceNum, const char *Type, ompt_device_t *Device,
ompt_function_lookup_t LookupFn, const char *DocStr)
: DeviceNum(DeviceNum), Type(Type), Device(Device), LookupFn(LookupFn),
DocStr(DocStr) {}
int DeviceNum;
const char *Type;
ompt_device_t *Device;
ompt_function_lookup_t LookupFn;
const char *DocStr;
};
struct DeviceFinalize : public EventBase<DeviceFinalize> {
std::string toString() const override;
DeviceFinalize(int DeviceNum) : DeviceNum(DeviceNum) {}
int DeviceNum;
};
struct DeviceLoad : public EventBase<DeviceLoad> {
std::string toString() const override;
DeviceLoad(int DeviceNum, const char *Filename, int64_t OffsetInFile,
void *VmaInFile, size_t Bytes, void *HostAddr, void *DeviceAddr,
uint64_t ModuleId)
: DeviceNum(DeviceNum), Filename(Filename), OffsetInFile(OffsetInFile),
VmaInFile(VmaInFile), Bytes(Bytes), HostAddr(HostAddr),
DeviceAddr(DeviceAddr), ModuleId(ModuleId) {}
int DeviceNum;
const char *Filename;
int64_t OffsetInFile;
void *VmaInFile;
size_t Bytes;
void *HostAddr;
void *DeviceAddr;
uint64_t ModuleId;
};
struct DeviceUnload : public EventBase<DeviceUnload> {
DeviceUnload() = default;
};
struct BufferRequest : public EventBase<BufferRequest> {
std::string toString() const override;
BufferRequest(int DeviceNum, ompt_buffer_t **Buffer, size_t *Bytes)
: DeviceNum(DeviceNum), Buffer(Buffer), Bytes(Bytes) {}
int DeviceNum;
ompt_buffer_t **Buffer;
size_t *Bytes;
};
struct BufferComplete : public EventBase<BufferComplete> {
std::string toString() const override;
BufferComplete(int DeviceNum, ompt_buffer_t *Buffer, size_t Bytes,
ompt_buffer_cursor_t Begin, int BufferOwned)
: DeviceNum(DeviceNum), Buffer(Buffer), Bytes(Bytes), Begin(Begin),
BufferOwned(BufferOwned) {}
int DeviceNum;
ompt_buffer_t *Buffer;
size_t Bytes;
ompt_buffer_cursor_t Begin;
int BufferOwned;
};
struct BufferRecord : public EventBase<BufferRecord> {
std::string toString() const override;
BufferRecord(ompt_record_ompt_t *RecordPtr) : RecordPtr(RecordPtr) {
if (RecordPtr != nullptr)
Record = *RecordPtr;
else
memset(&Record, 0, sizeof(ompt_record_ompt_t));
}
ompt_record_ompt_t Record;
ompt_record_ompt_t *RecordPtr;
};
struct BufferRecordDeallocation : public EventBase<BufferRecordDeallocation> {
std::string toString() const override;
BufferRecordDeallocation(ompt_buffer_t *Buffer) : Buffer(Buffer) {}
ompt_buffer_t *Buffer;
};
// Add specialized event equality operators here.
// Note: Placement of these forward declarations is important as they need to
// take precedence over the following default equality operator definition.
bool operator==(const ParallelBegin &, const ParallelBegin &);
bool operator==(const Work &, const Work &);
bool operator==(const ImplicitTask &, const ImplicitTask &);
bool operator==(const SyncRegion &, const SyncRegion &);
bool operator==(const Target &, const Target &);
bool operator==(const TargetEmi &, const TargetEmi &);
bool operator==(const TargetDataOp &, const TargetDataOp &);
bool operator==(const TargetDataOpEmi &, const TargetDataOpEmi &);
bool operator==(const TargetSubmit &, const TargetSubmit &);
bool operator==(const TargetSubmitEmi &, const TargetSubmitEmi &);
bool operator==(const DeviceInitialize &, const DeviceInitialize &);
bool operator==(const DeviceFinalize &, const DeviceFinalize &);
bool operator==(const DeviceLoad &, const DeviceLoad &);
bool operator==(const BufferRequest &, const BufferRequest &);
bool operator==(const BufferComplete &, const BufferComplete &);
bool operator==(const BufferRecord &, const BufferRecord &);
/// Default (fallback) event equality operator definition.
template <typename Event> bool operator==(const Event &, const Event &) {
return true;
}
// clang-format off
event_type_trait(AssertionSyncPoint)
event_type_trait(AssertionSuspend)
event_type_trait(ThreadBegin)
event_type_trait(ThreadEnd)
event_type_trait(ParallelBegin)
event_type_trait(ParallelEnd)
event_type_trait(Work)
event_type_trait(Dispatch)
event_type_trait(TaskCreate)
event_type_trait(Dependences)
event_type_trait(TaskDependence)
event_type_trait(TaskSchedule)
event_type_trait(ImplicitTask)
event_type_trait(Masked)
event_type_trait(SyncRegion)
event_type_trait(MutexAcquire)
event_type_trait(Mutex)
event_type_trait(NestLock)
event_type_trait(Flush)
event_type_trait(Cancel)
event_type_trait(Target)
event_type_trait(TargetEmi)
event_type_trait(TargetDataOp)
event_type_trait(TargetDataOpEmi)
event_type_trait(TargetSubmit)
event_type_trait(TargetSubmitEmi)
event_type_trait(ControlTool)
event_type_trait(DeviceInitialize)
event_type_trait(DeviceFinalize)
event_type_trait(DeviceLoad)
event_type_trait(DeviceUnload)
event_type_trait(BufferRequest)
event_type_trait(BufferComplete)
event_type_trait(BufferRecord)
event_type_trait(BufferRecordDeallocation)
// clang-format on
} // namespace internal
} // namespace omptest
#endif

View File

@ -1,130 +0,0 @@
//===- InternalEventCommon.h - Common internal event basics -----*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Provides event types, and class/operator declaration macros.
///
//===----------------------------------------------------------------------===//
#ifndef OPENMP_TOOLS_OMPTEST_INCLUDE_INTERNALEVENTCOMMON_H
#define OPENMP_TOOLS_OMPTEST_INCLUDE_INTERNALEVENTCOMMON_H
#include "omp-tools.h"
#include <cassert>
#include <string>
namespace omptest {
namespace internal {
/// Enum values are used for comparison of observed and asserted events
/// List is based on OpenMP 5.2 specification, table 19.2 (page 447)
enum class EventTy {
None, // not part of OpenMP spec, used for implementation
AssertionSyncPoint, // not part of OpenMP spec, used for implementation
AssertionSuspend, // not part of OpenMP spec, used for implementation
BufferRecord, // not part of OpenMP spec, used for implementation
BufferRecordDeallocation, // not part of OpenMP spec, used for implementation
ThreadBegin,
ThreadEnd,
ParallelBegin,
ParallelEnd,
Work,
Dispatch,
TaskCreate, // TODO: Implement
Dependences, // TODO: Implement
TaskDependence, // TODO: Implement
TaskSchedule, // TODO: Implement
ImplicitTask, // TODO: Implement
Masked, // TODO: Implement
SyncRegion,
MutexAcquire, // TODO: Implement
Mutex, // TODO: Implement
NestLock, // TODO: Implement
Flush, // TODO: Implement
Cancel, // TODO: Implement
DeviceInitialize,
DeviceFinalize,
DeviceLoad,
DeviceUnload,
BufferRequest,
BufferComplete,
TargetDataOp,
TargetDataOpEmi,
Target,
TargetEmi,
TargetSubmit,
TargetSubmitEmi,
ControlTool
};
/// Base event class
/// Offers default CTOR, DTOR and CTOR which assigns the actual event type.
struct InternalEvent {
InternalEvent() : Type(EventTy::None) {}
InternalEvent(EventTy T) : Type(T) {}
virtual ~InternalEvent() = default;
virtual bool equals(const InternalEvent *o) const {
assert(false && "Base class implementation");
return false;
};
virtual std::string toString() const {
std::string S{"InternalEvent: Type="};
S.append(std::to_string((uint32_t)Type));
return S;
}
/// Identifying event type
EventTy Type;
};
/// Specialize EventType member for each derived internal event type.
/// Effectively selecting an event type as initialization value.
template <typename EventType> struct EventTypeOf;
/// Actual definition macro for EventTypeOf.
#define event_type_trait(EvTy) \
template <> struct EventTypeOf<EvTy> { \
static constexpr EventTy Value = EventTy::EvTy; \
};
/// CRTP (Curiously Recurring Template Pattern) intermediate class
/// Adding a new event type can be achieved by inheriting from an EventBase
/// template instantiation of the new class' name, like this:
/// struct NewEventType : public EventBase<NewEventType>
template <typename Derived> class EventBase : public InternalEvent {
public:
static constexpr EventTy EventType = EventTypeOf<Derived>::Value;
EventBase() : InternalEvent(EventType) {}
virtual ~EventBase() = default;
/// Equals method to cast and dispatch to the specific class operator==
virtual bool equals(const InternalEvent *o) const override {
// Note: When the if-condition evaluates to true, the event types are
// trivially identical. Otherwise, a cast to the Derived pointer would have
// been impossible.
if (const auto Other = dynamic_cast<const Derived *>(o))
return operator==(*static_cast<const Derived *>(this), *Other);
return false;
}
/// Basic toString method, which may be overridden with own implementations.
virtual std::string toString() const override {
std::string S{"EventBase: Type="};
S.append(std::to_string((uint32_t)Type));
return S;
}
};
} // namespace internal
} // namespace omptest
#endif

View File

@ -1,155 +0,0 @@
//===- Logging.h - General logging class ------------------------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Provides ompTest-tailored logging, with log-levels and formatting/coloring.
///
//===----------------------------------------------------------------------===//
#ifndef OPENMP_TOOLS_OMPTEST_INCLUDE_LOGGING_H
#define OPENMP_TOOLS_OMPTEST_INCLUDE_LOGGING_H
#include "OmptAssertEvent.h"
#include <iostream>
#include <map>
#include <mutex>
#include <set>
#include <sstream>
#include <string>
namespace omptest {
namespace logging {
enum class Level : uint32_t {
// Levels (Note: DEBUG may already be reserved)
Diagnostic = 10,
Info = 20,
Warning = 30,
Error = 40,
Critical = 50,
// Types used for formatting options
Default,
ExpectedEvent,
ObservedEvent,
OffendingEvent,
// Suppress all prints
Silent = 0xFFFFFFFF
};
enum class FormatOption : uint32_t {
// General options
// Note: Bold is actually "BRIGHT" -- But it will be perceived as 'bold' font
// It is implicitly switching colors to the 'Light' variant
// Thus, it has -NO EFFECT- when already using a Light* color
None = 0,
Bold = 1,
Dim = 2,
Underlined = 4,
Blink = 5,
Inverted = 7,
Hidden = 8,
// Foreground colors
ColorDefault = 39,
ColorBlack = 30,
ColorRed = 31,
ColorGreen = 32,
ColorYellow = 33,
ColorBlue = 34,
ColorMagenta = 35,
ColorCyan = 36,
ColorLightGray = 37,
ColorDarkGray = 90,
ColorLightRed = 91,
ColorLightGreen = 92,
ColorLightYellow = 93,
ColorLightBlue = 94,
ColorLightMagenta = 95,
ColorLightCyan = 96,
ColorWhite = 97,
// Background colors
ColorBackgroundDefault = 49,
ColorBackgroundBlack = 40,
ColorBackgroundRed = 41,
ColorBackgroundGreen = 42,
ColorBackgroundYellow = 43,
ColorBackgroundBlue = 44,
ColorBackgroundMagenta = 45,
ColorBackgroundCyan = 46,
ColorBackgroundLightGray = 47,
ColorBackgroundDarkGray = 100,
ColorBackgroundLightRed = 101,
ColorBackgroundLightGreen = 102,
ColorBackgroundLightYellow = 103,
ColorBackgroundLightBlue = 104,
ColorBackgroundLightMagenta = 105,
ColorBackgroundLightCyan = 106,
ColorBackgroundWhite = 107
};
/// Returns a string representation of the given logging level.
const char *to_string(Level LogLevel);
/// Returns the format options as escaped sequence, for the given logging level
std::string getFormatSequence(Level LogLevel = Level::Default);
/// Format the given message with the provided option(s) and return it.
/// Here formatting is only concerning control sequences using <Esc> character
/// which can be obtained using '\e' (on console), '\033' or '\x1B'.
std::string format(const std::string &Message, FormatOption Option);
std::string format(const std::string &Message, std::set<FormatOption> Options);
class Logger {
public:
Logger(Level LogLevel = Level::Warning, std::ostream &OutStream = std::cerr,
bool FormatOutput = true);
~Logger();
/// Log the given message to the output.
void log(const std::string &Message, Level LogLevel) const;
/// Log a single event mismatch.
void logEventMismatch(const std::string &Message,
const omptest::OmptAssertEvent &OffendingEvent,
Level LogLevel = Level::Error) const;
/// Log an event-pair mismatch.
void logEventMismatch(const std::string &Message,
const omptest::OmptAssertEvent &ExpectedEvent,
const omptest::OmptAssertEvent &ObservedEvent,
Level LogLevel = Level::Error) const;
/// Set if output is being formatted (e.g. colored).
void setFormatOutput(bool Enabled);
/// Return the current (minimum) Logging Level.
Level getLoggingLevel() const;
/// Set the (minimum) Logging Level.
void setLoggingLevel(Level LogLevel);
private:
/// The minimum logging level that is considered by the logger instance.
Level LoggingLevel;
/// The output stream used by the logger instance.
std::ostream &OutStream;
/// Determine if log messages are formatted using control sequences.
bool FormatOutput;
/// Mutex to ensure serialized logging
mutable std::mutex LogMutex;
};
} // namespace logging
} // namespace omptest
#endif

View File

@ -1,85 +0,0 @@
//===- OmptAliases.h - Shorthand aliases for OMPT enum values ---*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Defines shorthand aliases for OMPT enum values, providing improved
/// ease-of-use and readability.
///
//===----------------------------------------------------------------------===//
#ifndef OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTALIASES_H
#define OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTALIASES_H
#include <omp-tools.h>
/// Aliases for enum: ompt_scope_endpoint_t
constexpr ompt_scope_endpoint_t BEGIN = ompt_scope_begin;
constexpr ompt_scope_endpoint_t END = ompt_scope_end;
constexpr ompt_scope_endpoint_t BEGINEND = ompt_scope_beginend;
/// Aliases for enum: ompt_target_t
constexpr ompt_target_t TARGET = ompt_target;
constexpr ompt_target_t ENTER_DATA = ompt_target_enter_data;
constexpr ompt_target_t EXIT_DATA = ompt_target_exit_data;
constexpr ompt_target_t UPDATE = ompt_target_update;
constexpr ompt_target_t TARGET_NOWAIT = ompt_target_nowait;
constexpr ompt_target_t ENTER_DATA_NOWAIT = ompt_target_enter_data_nowait;
constexpr ompt_target_t EXIT_DATA_NOWAIT = ompt_target_exit_data_nowait;
constexpr ompt_target_t UPDATE_NOWAIT = ompt_target_update_nowait;
/// Aliases for enum: ompt_target_data_op_t
constexpr ompt_target_data_op_t ALLOC = ompt_target_data_alloc;
constexpr ompt_target_data_op_t H2D = ompt_target_data_transfer_to_device;
constexpr ompt_target_data_op_t D2H = ompt_target_data_transfer_from_device;
constexpr ompt_target_data_op_t DELETE = ompt_target_data_delete;
constexpr ompt_target_data_op_t ASSOCIATE = ompt_target_data_associate;
constexpr ompt_target_data_op_t DISASSOCIATE = ompt_target_data_disassociate;
constexpr ompt_target_data_op_t ALLOC_ASYNC = ompt_target_data_alloc_async;
constexpr ompt_target_data_op_t H2D_ASYNC =
ompt_target_data_transfer_to_device_async;
constexpr ompt_target_data_op_t D2H_ASYNC =
ompt_target_data_transfer_from_device_async;
constexpr ompt_target_data_op_t DELETE_ASYNC = ompt_target_data_delete_async;
/// Aliases for enum: ompt_callbacks_t (partial)
constexpr ompt_callbacks_t CB_TARGET = ompt_callback_target;
constexpr ompt_callbacks_t CB_DATAOP = ompt_callback_target_data_op;
constexpr ompt_callbacks_t CB_KERNEL = ompt_callback_target_submit;
/// Aliases for enum: ompt_work_t
constexpr ompt_work_t WORK_LOOP = ompt_work_loop;
constexpr ompt_work_t WORK_SECT = ompt_work_sections;
constexpr ompt_work_t WORK_EXEC = ompt_work_single_executor;
constexpr ompt_work_t WORK_SINGLE = ompt_work_single_other;
constexpr ompt_work_t WORK_SHARE = ompt_work_workshare;
constexpr ompt_work_t WORK_DIST = ompt_work_distribute;
constexpr ompt_work_t WORK_TASK = ompt_work_taskloop;
constexpr ompt_work_t WORK_SCOPE = ompt_work_scope;
constexpr ompt_work_t WORK_LOOP_STA = ompt_work_loop_static;
constexpr ompt_work_t WORK_LOOP_DYN = ompt_work_loop_dynamic;
constexpr ompt_work_t WORK_LOOP_GUI = ompt_work_loop_guided;
constexpr ompt_work_t WORK_LOOP_OTH = ompt_work_loop_other;
/// Aliases for enum: ompt_sync_region_t
constexpr ompt_sync_region_t SR_BARRIER = ompt_sync_region_barrier;
constexpr ompt_sync_region_t SR_BARRIER_IMPL =
ompt_sync_region_barrier_implicit;
constexpr ompt_sync_region_t SR_BARRIER_EXPL =
ompt_sync_region_barrier_explicit;
constexpr ompt_sync_region_t SR_BARRIER_IMPLEMENTATION =
ompt_sync_region_barrier_implementation;
constexpr ompt_sync_region_t SR_TASKWAIT = ompt_sync_region_taskwait;
constexpr ompt_sync_region_t SR_TASKGROUP = ompt_sync_region_taskgroup;
constexpr ompt_sync_region_t SR_REDUCTION = ompt_sync_region_reduction;
constexpr ompt_sync_region_t SR_BARRIER_IMPL_WORKSHARE =
ompt_sync_region_barrier_implicit_workshare;
constexpr ompt_sync_region_t SR_BARRIER_IMPL_PARALLEL =
ompt_sync_region_barrier_implicit_parallel;
constexpr ompt_sync_region_t SR_BARRIER_TEAMS = ompt_sync_region_barrier_teams;
#endif

View File

@ -1,377 +0,0 @@
//===- OmptAssertEvent.h - Assertion event declarations ---------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Contains assertion event constructors, for generally all observable events.
/// This includes user-generated events, like synchronization.
///
//===----------------------------------------------------------------------===//
#ifndef OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTASSERTEVENT_H
#define OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTASSERTEVENT_H
#include "InternalEvent.h"
#include "omp-tools.h"
#include <cassert>
#include <limits>
#include <memory>
#include <string>
namespace omptest {
enum class ObserveState { Generated, Always, Never };
/// Helper function, returning an ObserveState string representation
const char *to_string(ObserveState State);
/// Assertion event struct, provides statically callable CTORs.
struct OmptAssertEvent {
static OmptAssertEvent AssertionSyncPoint(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
const std::string &SyncPointName);
static OmptAssertEvent AssertionSuspend(const std::string &Name,
const std::string &Group,
const ObserveState &Expected);
static OmptAssertEvent ThreadBegin(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
ompt_thread_t ThreadType);
static OmptAssertEvent ThreadEnd(const std::string &Name,
const std::string &Group,
const ObserveState &Expected);
static OmptAssertEvent ParallelBegin(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
int NumThreads);
static OmptAssertEvent ParallelEnd(
const std::string &Name, const std::string &Group,
const ObserveState &Expected,
ompt_data_t *ParallelData = expectedDefault(ompt_data_t *),
ompt_data_t *EncounteringTaskData = expectedDefault(ompt_data_t *),
int Flags = expectedDefault(int),
const void *CodeptrRA = expectedDefault(const void *));
static OmptAssertEvent
Work(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_work_t WorkType,
ompt_scope_endpoint_t Endpoint,
ompt_data_t *ParallelData = expectedDefault(ompt_data_t *),
ompt_data_t *TaskData = expectedDefault(ompt_data_t *),
uint64_t Count = expectedDefault(uint64_t),
const void *CodeptrRA = expectedDefault(const void *));
static OmptAssertEvent
Dispatch(const std::string &Name, const std::string &Group,
const ObserveState &Expected,
ompt_data_t *ParallelData = expectedDefault(ompt_data_t *),
ompt_data_t *TaskData = expectedDefault(ompt_data_t *),
ompt_dispatch_t Kind = expectedDefault(ompt_dispatch_t),
ompt_data_t Instance = expectedDefault(ompt_data_t));
static OmptAssertEvent
TaskCreate(const std::string &Name, const std::string &Group,
const ObserveState &Expected,
ompt_data_t *EncounteringTaskData = expectedDefault(ompt_data_t *),
const ompt_frame_t *EncounteringTaskFrame =
expectedDefault(ompt_frame_t *),
ompt_data_t *NewTaskData = expectedDefault(ompt_data_t *),
int Flags = expectedDefault(int),
int HasDependences = expectedDefault(int),
const void *CodeptrRA = expectedDefault(const void *));
static OmptAssertEvent TaskSchedule(const std::string &Name,
const std::string &Group,
const ObserveState &Expected);
static OmptAssertEvent
ImplicitTask(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_scope_endpoint_t Endpoint,
ompt_data_t *ParallelData = expectedDefault(ompt_data_t *),
ompt_data_t *TaskData = expectedDefault(ompt_data_t *),
unsigned int ActualParallelism = expectedDefault(unsigned int),
unsigned int Index = expectedDefault(unsigned int),
int Flags = expectedDefault(int));
static OmptAssertEvent
SyncRegion(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_sync_region_t Kind,
ompt_scope_endpoint_t Endpoint,
ompt_data_t *ParallelData = expectedDefault(ompt_data_t *),
ompt_data_t *TaskData = expectedDefault(ompt_data_t *),
const void *CodeptrRA = expectedDefault(const void *));
static OmptAssertEvent
Target(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_target_t Kind,
ompt_scope_endpoint_t Endpoint, int DeviceNum = expectedDefault(int),
ompt_data_t *TaskData = expectedDefault(ompt_data_t *),
ompt_id_t TargetId = expectedDefault(ompt_id_t),
const void *CodeptrRA = expectedDefault(void *));
static OmptAssertEvent
TargetEmi(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_target_t Kind,
ompt_scope_endpoint_t Endpoint,
int DeviceNum = expectedDefault(int),
ompt_data_t *TaskData = expectedDefault(ompt_data_t *),
ompt_data_t *TargetTaskData = expectedDefault(ompt_data_t *),
ompt_data_t *TargetData = expectedDefault(ompt_data_t *),
const void *CodeptrRA = expectedDefault(void *));
static OmptAssertEvent
TargetDataOp(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_id_t TargetId,
ompt_id_t HostOpId, ompt_target_data_op_t OpType, void *SrcAddr,
int SrcDeviceNum, void *DstAddr, int DstDeviceNum, size_t Bytes,
const void *CodeptrRA);
static OmptAssertEvent
TargetDataOp(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_target_data_op_t OpType,
size_t Bytes = expectedDefault(size_t),
void *SrcAddr = expectedDefault(void *),
void *DstAddr = expectedDefault(void *),
int SrcDeviceNum = expectedDefault(int),
int DstDeviceNum = expectedDefault(int),
ompt_id_t TargetId = expectedDefault(ompt_id_t),
ompt_id_t HostOpId = expectedDefault(ompt_id_t),
const void *CodeptrRA = expectedDefault(void *));
static OmptAssertEvent
TargetDataOpEmi(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_scope_endpoint_t Endpoint,
ompt_data_t *TargetTaskData, ompt_data_t *TargetData,
ompt_id_t *HostOpId, ompt_target_data_op_t OpType,
void *SrcAddr, int SrcDeviceNum, void *DstAddr,
int DstDeviceNum, size_t Bytes, const void *CodeptrRA);
static OmptAssertEvent
TargetDataOpEmi(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_target_data_op_t OpType,
ompt_scope_endpoint_t Endpoint,
size_t Bytes = expectedDefault(size_t),
void *SrcAddr = expectedDefault(void *),
void *DstAddr = expectedDefault(void *),
int SrcDeviceNum = expectedDefault(int),
int DstDeviceNum = expectedDefault(int),
ompt_data_t *TargetTaskData = expectedDefault(ompt_data_t *),
ompt_data_t *TargetData = expectedDefault(ompt_data_t *),
ompt_id_t *HostOpId = expectedDefault(ompt_id_t *),
const void *CodeptrRA = expectedDefault(void *));
static OmptAssertEvent TargetSubmit(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
ompt_id_t TargetId, ompt_id_t HostOpId,
unsigned int RequestedNumTeams);
static OmptAssertEvent
TargetSubmit(const std::string &Name, const std::string &Group,
const ObserveState &Expected, unsigned int RequestedNumTeams,
ompt_id_t TargetId = expectedDefault(ompt_id_t),
ompt_id_t HostOpId = expectedDefault(ompt_id_t));
static OmptAssertEvent
TargetSubmitEmi(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_scope_endpoint_t Endpoint,
ompt_data_t *TargetData, ompt_id_t *HostOpId,
unsigned int RequestedNumTeams);
static OmptAssertEvent
TargetSubmitEmi(const std::string &Name, const std::string &Group,
const ObserveState &Expected, unsigned int RequestedNumTeams,
ompt_scope_endpoint_t Endpoint,
ompt_data_t *TargetData = expectedDefault(ompt_data_t *),
ompt_id_t *HostOpId = expectedDefault(ompt_id_t *));
static OmptAssertEvent ControlTool(const std::string &Name,
const std::string &Group,
const ObserveState &Expected);
static OmptAssertEvent DeviceInitialize(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, int DeviceNum,
const char *Type = expectedDefault(const char *),
ompt_device_t *Device = expectedDefault(ompt_device_t *),
ompt_function_lookup_t LookupFn = expectedDefault(ompt_function_lookup_t),
const char *DocumentationStr = expectedDefault(const char *));
static OmptAssertEvent DeviceFinalize(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
int DeviceNum);
static OmptAssertEvent
DeviceLoad(const std::string &Name, const std::string &Group,
const ObserveState &Expected, int DeviceNum,
const char *Filename = expectedDefault(const char *),
int64_t OffsetInFile = expectedDefault(int64_t),
void *VmaInFile = expectedDefault(void *),
size_t Bytes = expectedDefault(size_t),
void *HostAddr = expectedDefault(void *),
void *DeviceAddr = expectedDefault(void *),
uint64_t ModuleId = expectedDefault(int64_t));
static OmptAssertEvent DeviceUnload(const std::string &Name,
const std::string &Group,
const ObserveState &Expected);
static OmptAssertEvent BufferRequest(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
int DeviceNum, ompt_buffer_t **Buffer,
size_t *Bytes);
static OmptAssertEvent
BufferComplete(const std::string &Name, const std::string &Group,
const ObserveState &Expected, int DeviceNum,
ompt_buffer_t *Buffer, size_t Bytes,
ompt_buffer_cursor_t Begin, int BufferOwned);
static OmptAssertEvent BufferRecord(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
ompt_record_ompt_t *Record);
/// Handle type = ompt_record_target_t
static OmptAssertEvent
BufferRecord(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_callbacks_t Type,
ompt_target_t Kind, ompt_scope_endpoint_t Endpoint,
int DeviceNum = expectedDefault(int),
ompt_id_t TaskId = expectedDefault(ompt_id_t),
ompt_id_t TargetId = expectedDefault(ompt_id_t),
const void *CodeptrRA = expectedDefault(void *));
/// Handle type = ompt_callback_target_data_op
static OmptAssertEvent
BufferRecord(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_callbacks_t Type,
ompt_target_data_op_t OpType, size_t Bytes,
std::pair<ompt_device_time_t, ompt_device_time_t> Timeframe,
void *SrcAddr = expectedDefault(void *),
void *DstAddr = expectedDefault(void *),
int SrcDeviceNum = expectedDefault(int),
int DstDeviceNum = expectedDefault(int),
ompt_id_t TargetId = expectedDefault(ompt_id_t),
ompt_id_t HostOpId = expectedDefault(ompt_id_t),
const void *CodeptrRA = expectedDefault(void *));
/// Handle type = ompt_callback_target_data_op
static OmptAssertEvent BufferRecord(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_callbacks_t Type,
ompt_target_data_op_t OpType, size_t Bytes = expectedDefault(size_t),
ompt_device_time_t MinimumTimeDelta = expectedDefault(ompt_device_time_t),
void *SrcAddr = expectedDefault(void *),
void *DstAddr = expectedDefault(void *),
int SrcDeviceNum = expectedDefault(int),
int DstDeviceNum = expectedDefault(int),
ompt_id_t TargetId = expectedDefault(ompt_id_t),
ompt_id_t HostOpId = expectedDefault(ompt_id_t),
const void *CodeptrRA = expectedDefault(void *));
/// Handle type = ompt_callback_target_submit
static OmptAssertEvent
BufferRecord(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_callbacks_t Type,
std::pair<ompt_device_time_t, ompt_device_time_t> Timeframe,
unsigned int RequestedNumTeams = expectedDefault(unsigned int),
unsigned int GrantedNumTeams = expectedDefault(unsigned int),
ompt_id_t TargetId = expectedDefault(ompt_id_t),
ompt_id_t HostOpId = expectedDefault(ompt_id_t));
/// Handle type = ompt_callback_target_submit
/// Note: This will also act as the simplest default CTOR
static OmptAssertEvent BufferRecord(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_callbacks_t Type,
ompt_device_time_t MinimumTimeDelta = expectedDefault(ompt_device_time_t),
unsigned int RequestedNumTeams = expectedDefault(unsigned int),
unsigned int GrantedNumTeams = expectedDefault(unsigned int),
ompt_id_t TargetId = expectedDefault(ompt_id_t),
ompt_id_t HostOpId = expectedDefault(ompt_id_t));
static OmptAssertEvent BufferRecordDeallocation(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
ompt_buffer_t *Buffer);
/// Allow move construction (due to std::unique_ptr)
OmptAssertEvent(OmptAssertEvent &&o) = default;
OmptAssertEvent &operator=(OmptAssertEvent &&o) = default;
/// Get the event's name
std::string getEventName() const;
/// Get the event's group name
std::string getEventGroup() const;
/// Get the event's expected observation state
ObserveState getEventExpectedState() const;
/// Return the actual event type enum value
internal::EventTy getEventType() const;
/// Get a pointer to the internal event
internal::InternalEvent *getEvent() const;
/// Make events comparable
friend bool operator==(const OmptAssertEvent &A, const OmptAssertEvent &B);
/// Returns the string representation of the event
std::string toString(bool PrefixEventName = false) const;
private:
OmptAssertEvent(const std::string &Name, const std::string &Group,
const ObserveState &Expected, internal::InternalEvent *IE);
OmptAssertEvent(const OmptAssertEvent &o) = delete;
/// Determine the event name. Either it is provided directly or determined
/// from the calling function's name.
static std::string getName(const std::string &Name,
const char *Caller = __builtin_FUNCTION()) {
std::string EName = Name;
if (EName.empty())
EName.append(Caller).append(" (auto generated)");
return EName;
}
/// Determine the event name. Either it is provided directly or "default".
static std::string getGroup(const std::string &Group) {
if (Group.empty())
return "default";
return Group;
}
std::string Name;
std::string Group;
ObserveState ExpectedState;
std::unique_ptr<internal::InternalEvent> TheEvent;
};
/// POD type, which holds the target region id, corresponding to an event group.
struct AssertEventGroup {
AssertEventGroup(uint64_t TargetRegion) : TargetRegion(TargetRegion) {}
uint64_t TargetRegion;
};
bool operator==(const OmptAssertEvent &A, const OmptAssertEvent &B);
} // namespace omptest
#endif

View File

@ -1,291 +0,0 @@
//===- OmptAsserter.h - Asserter-related classes, enums, etc. ---*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Contains all asserter-related class declarations and important enums.
///
//===----------------------------------------------------------------------===//
#ifndef OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTASSERTER_H
#define OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTASSERTER_H
#include "Logging.h"
#include "OmptAssertEvent.h"
#include <cassert>
#include <iostream>
#include <map>
#include <mutex>
#include <set>
#include <vector>
namespace omptest {
// Forward declaration.
class OmptEventGroupInterface;
enum class AssertMode { Strict, Relaxed };
enum class AssertState { Pass, Fail };
/// General base class for the subscriber/notification pattern in
/// OmptCallbackHandler. Derived classes need to implement the notify method.
class OmptListener {
public:
virtual ~OmptListener() = default;
/// Called for each registered OMPT event of the OmptCallbackHandler
virtual void notify(omptest::OmptAssertEvent &&AE) = 0;
/// Control whether this asserter should be considered 'active'.
void setActive(bool Enabled);
/// Check if this asserter is considered 'active'.
bool isActive();
/// Check if the given event type is from the set of suppressed event types.
bool isSuppressedEventType(omptest::internal::EventTy EvTy);
/// Remove the given event type to the set of suppressed events.
void permitEvent(omptest::internal::EventTy EvTy);
/// Add the given event type to the set of suppressed events.
void suppressEvent(omptest::internal::EventTy EvTy);
private:
bool Active{true};
// Add event types to the set of suppressed events by default.
std::set<omptest::internal::EventTy> SuppressedEvents{
omptest::internal::EventTy::ThreadBegin,
omptest::internal::EventTy::ThreadEnd,
omptest::internal::EventTy::ParallelBegin,
omptest::internal::EventTy::ParallelEnd,
omptest::internal::EventTy::Work,
omptest::internal::EventTy::Dispatch,
omptest::internal::EventTy::TaskCreate,
omptest::internal::EventTy::Dependences,
omptest::internal::EventTy::TaskDependence,
omptest::internal::EventTy::TaskSchedule,
omptest::internal::EventTy::ImplicitTask,
omptest::internal::EventTy::Masked,
omptest::internal::EventTy::SyncRegion,
omptest::internal::EventTy::MutexAcquire,
omptest::internal::EventTy::Mutex,
omptest::internal::EventTy::NestLock,
omptest::internal::EventTy::Flush,
omptest::internal::EventTy::Cancel};
};
/// Base class for asserting on OMPT events
class OmptAsserter : public OmptListener {
public:
OmptAsserter();
virtual ~OmptAsserter() = default;
/// Add an event to the asserter's internal data structure.
virtual void insert(omptest::OmptAssertEvent &&AE);
/// Called from the CallbackHandler with a corresponding AssertEvent to which
/// callback was handled.
void notify(omptest::OmptAssertEvent &&AE) override;
/// Implemented in subclasses to implement what should actually be done with
/// the notification.
virtual void notifyImpl(omptest::OmptAssertEvent &&AE) = 0;
/// Get the number of currently remaining events, with: ObserveState::Always.
virtual size_t getRemainingEventCount() = 0;
/// Get the total number of received, effective notifications.
int getNotificationCount() { return NumNotifications; }
/// Get the total number of successful assertion checks.
int getSuccessfulAssertionCount() { return NumSuccessfulAsserts; }
/// Get the asserter's current operationmode: e.g.: Strict or Relaxed.
AssertMode getOperationMode() { return OperationMode; }
/// Return the asserter's current state.
omptest::AssertState getState() { return State; }
/// Determine and return the asserter's state.
virtual omptest::AssertState checkState();
/// Accessor for the event group interface.
std::shared_ptr<OmptEventGroupInterface> getEventGroups() const {
return EventGroups;
}
/// Accessor for the event group interface.
std::shared_ptr<logging::Logger> getLog() const { return Log; }
/// Check the observed events' group association. If the event indicates the
/// begin/end of an OpenMP target region, we will create/deprecate the
/// expected event's group. Return true if the expected event group exists
/// (and is active), otherwise: false. Note: BufferRecords may also match with
/// deprecated groups as they may be delivered asynchronously.
bool verifyEventGroups(const omptest::OmptAssertEvent &ExpectedEvent,
const omptest::OmptAssertEvent &ObservedEvent);
/// Set the asserter's mode of operation w.r.t. assertion.
void setOperationMode(AssertMode Mode);
protected:
/// The asserter's current state.
omptest::AssertState State{omptest::AssertState::Pass};
/// Mutex to avoid data races w.r.t. event notifications and/or insertions.
std::mutex AssertMutex;
/// Pointer to the OmptEventGroupInterface.
std::shared_ptr<OmptEventGroupInterface> EventGroups{nullptr};
/// Pointer to the logging instance.
std::shared_ptr<logging::Logger> Log{nullptr};
/// Operation mode during assertion / notification.
AssertMode OperationMode{AssertMode::Strict};
/// The total number of effective notifications. For example, if specific
/// notifications are to be ignored, they will not count towards this total.
int NumNotifications{0};
/// The number of successful assertion checks.
int NumSuccessfulAsserts{0};
private:
/// Mutex for creating/accessing the singleton members
static std::mutex StaticMemberAccessMutex;
/// Static member to manage the singleton event group interface instance
static std::weak_ptr<OmptEventGroupInterface> EventGroupInterfaceInstance;
/// Static member to manage the singleton logging instance
static std::weak_ptr<logging::Logger> LoggingInstance;
};
/// Class that can assert in a sequenced fashion, i.e., events have to occur in
/// the order they were registered
class OmptSequencedAsserter : public OmptAsserter {
public:
OmptSequencedAsserter() : OmptAsserter(), NextEvent(0) {}
/// Add the event to the in-sequence set of events that the asserter should
/// check for.
void insert(omptest::OmptAssertEvent &&AE) override;
/// Implements the asserter's actual logic
virtual void notifyImpl(omptest::OmptAssertEvent &&AE) override;
size_t getRemainingEventCount() override;
omptest::AssertState checkState() override;
bool AssertionSuspended{false};
protected:
/// Notification helper function, implementing SyncPoint logic. Returns true
/// in case of consumed event, indicating early exit of notification.
bool consumeSyncPoint(const omptest::OmptAssertEvent &AE);
/// Notification helper function, implementing excess event notification
/// logic. Returns true when no more events were expected, indicating early
/// exit of notification.
bool checkExcessNotify(const omptest::OmptAssertEvent &AE);
/// Notification helper function, implementing Suspend logic. Returns true
/// in case of consumed event, indicating early exit of notification.
bool consumeSuspend();
/// Notification helper function, implementing regular event notification
/// logic. Returns true when a matching event was encountered, indicating
/// early exit of notification.
bool consumeRegularEvent(const omptest::OmptAssertEvent &AE);
public:
/// Index of the next, expected event.
size_t NextEvent{0};
std::vector<omptest::OmptAssertEvent> Events{};
};
/// Class that asserts with set semantics, i.e., unordered
struct OmptEventAsserter : public OmptAsserter {
OmptEventAsserter() : OmptAsserter(), NumEvents(0), Events() {}
/// Add the event to the set of events that the asserter should check for.
void insert(omptest::OmptAssertEvent &&AE) override;
/// Implements the asserter's logic
virtual void notifyImpl(omptest::OmptAssertEvent &&AE) override;
size_t getRemainingEventCount() override;
omptest::AssertState checkState() override;
size_t NumEvents{0};
/// For now use vector (but do set semantics)
// TODO std::unordered_set?
std::vector<omptest::OmptAssertEvent> Events{};
};
/// Class that reports the occurred events
class OmptEventReporter : public OmptListener {
public:
OmptEventReporter(std::ostream &OutStream = std::cout)
: OutStream(OutStream) {}
/// Called from the CallbackHandler with a corresponding AssertEvent to which
/// callback was handled.
void notify(omptest::OmptAssertEvent &&AE) override;
private:
std::ostream &OutStream;
};
/// This class provides the members and methods to manage event groups and
/// SyncPoints in conjunction with asserters. Most importantly it maintains a
/// coherent view of active and past events or SyncPoints.
class OmptEventGroupInterface {
public:
OmptEventGroupInterface() = default;
~OmptEventGroupInterface() = default;
/// Non-copyable and non-movable
OmptEventGroupInterface(const OmptEventGroupInterface &) = delete;
OmptEventGroupInterface &operator=(const OmptEventGroupInterface &) = delete;
OmptEventGroupInterface(OmptEventGroupInterface &&) = delete;
OmptEventGroupInterface &operator=(OmptEventGroupInterface &&) = delete;
/// Add given group to the set of active event groups. Effectively connecting
/// the given groupname (expected) with a target region id (observed).
bool addActiveEventGroup(const std::string &GroupName,
omptest::AssertEventGroup Group);
/// Move given group from the set of active event groups to the set of
/// previously active event groups.
bool deprecateActiveEventGroup(const std::string &GroupName);
/// Check if given group is currently part of the active event groups.
bool checkActiveEventGroups(const std::string &GroupName,
omptest::AssertEventGroup Group);
/// Check if given group is currently part of the deprecated event groups.
bool checkDeprecatedEventGroups(const std::string &GroupName,
omptest::AssertEventGroup Group);
private:
mutable std::mutex GroupMutex;
std::map<std::string, omptest::AssertEventGroup> ActiveEventGroups{};
std::map<std::string, omptest::AssertEventGroup> DeprecatedEventGroups{};
std::set<std::string> EncounteredSyncPoints{};
};
} // namespace omptest
#endif

View File

@ -1,165 +0,0 @@
//===- OmptCallbackHandler.h - Callback reception and handling --*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file provides the OMPT callback handling declarations.
///
//===----------------------------------------------------------------------===//
#ifndef OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTCALLBACKHANDLER_H
#define OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTCALLBACKHANDLER_H
#include "OmptAssertEvent.h"
#include "OmptAsserter.h"
#include "omp-tools.h"
#include <vector>
namespace omptest {
/// Handler class to do whatever is needed to be done when a callback is invoked
/// by the OMP runtime
/// Supports a RecordAndReplay mechanism in which all OMPT events are recorded
/// and then replayed. This is so that a test can assert on, e.g., a device
/// initialize event, even though this would occur before a unit test is
/// actually executed.
class OmptCallbackHandler {
public:
~OmptCallbackHandler() = default;
/// Singleton handler
static OmptCallbackHandler &get();
/// Subscribe a listener to be notified for OMPT events
void subscribe(OmptListener *Listener);
/// Remove all subscribers
void clearSubscribers();
/// When the record and replay mechanism is enabled this replays all OMPT
/// events
void replay();
/// Special asserter callback which checks that upon encountering the
/// synchronization point, all expected events have been processed. That is:
/// there are currently no remaining expected events for any asserter.
void handleAssertionSyncPoint(const std::string &SyncPointName);
void handleThreadBegin(ompt_thread_t ThreadType, ompt_data_t *ThreadData);
void handleThreadEnd(ompt_data_t *ThreadData);
void handleTaskCreate(ompt_data_t *EncounteringTaskData,
const ompt_frame_t *EncounteringTaskFrame,
ompt_data_t *NewTaskData, int Flags, int HasDependences,
const void *CodeptrRA);
void handleTaskSchedule(ompt_data_t *PriorTaskData,
ompt_task_status_t PriorTaskStatus,
ompt_data_t *NextTaskData);
void handleImplicitTask(ompt_scope_endpoint_t Endpoint,
ompt_data_t *ParallelData, ompt_data_t *TaskData,
unsigned int ActualParallelism, unsigned int Index,
int Flags);
void handleParallelBegin(ompt_data_t *EncounteringTaskData,
const ompt_frame_t *EncounteringTaskFrame,
ompt_data_t *ParallelData,
unsigned int RequestedParallelism, int Flags,
const void *CodeptrRA);
void handleParallelEnd(ompt_data_t *ParallelData,
ompt_data_t *EncounteringTaskData, int Flags,
const void *CodeptrRA);
void handleDeviceInitialize(int DeviceNum, const char *Type,
ompt_device_t *Device,
ompt_function_lookup_t LookupFn,
const char *DocumentationStr);
void handleDeviceFinalize(int DeviceNum);
void handleTarget(ompt_target_t Kind, ompt_scope_endpoint_t Endpoint,
int DeviceNum, ompt_data_t *TaskData, ompt_id_t TargetId,
const void *CodeptrRA);
void handleTargetEmi(ompt_target_t Kind, ompt_scope_endpoint_t Endpoint,
int DeviceNum, ompt_data_t *TaskData,
ompt_data_t *TargetTaskData, ompt_data_t *TargetData,
const void *CodeptrRA);
void handleTargetSubmit(ompt_id_t TargetId, ompt_id_t HostOpId,
unsigned int RequestedNumTeams);
void handleTargetSubmitEmi(ompt_scope_endpoint_t Endpoint,
ompt_data_t *TargetData, ompt_id_t *HostOpId,
unsigned int RequestedNumTeams);
void handleTargetDataOp(ompt_id_t TargetId, ompt_id_t HostOpId,
ompt_target_data_op_t OpType, void *SrcAddr,
int SrcDeviceNum, void *DstAddr, int DstDeviceNum,
size_t Bytes, const void *CodeptrRA);
void handleTargetDataOpEmi(ompt_scope_endpoint_t Endpoint,
ompt_data_t *TargetTaskData,
ompt_data_t *TargetData, ompt_id_t *HostOpId,
ompt_target_data_op_t OpType, void *SrcAddr,
int SrcDeviceNum, void *DstAddr, int DstDeviceNum,
size_t Bytes, const void *CodeptrRA);
void handleDeviceLoad(int DeviceNum, const char *Filename,
int64_t OffsetInFile, void *VmaInFile, size_t Bytes,
void *HostAddr, void *DeviceAddr, uint64_t ModuleId);
void handleDeviceUnload(int DeviceNum, uint64_t ModuleId);
void handleBufferRequest(int DeviceNum, ompt_buffer_t **Buffer,
size_t *Bytes);
void handleBufferComplete(int DeviceNum, ompt_buffer_t *Buffer, size_t Bytes,
ompt_buffer_cursor_t Begin, int BufferOwned);
void handleBufferRecord(ompt_record_ompt_t *Record);
void handleBufferRecordDeallocation(ompt_buffer_t *Buffer);
/// Not needed for a conforming minimal OMPT implementation
void handleWork(ompt_work_t WorkType, ompt_scope_endpoint_t Endpoint,
ompt_data_t *ParallelData, ompt_data_t *TaskData,
uint64_t Count, const void *CodeptrRA);
void handleDispatch(ompt_data_t *ParallelData, ompt_data_t *TaskData,
ompt_dispatch_t Kind, ompt_data_t Instance);
void handleSyncRegion(ompt_sync_region_t Kind, ompt_scope_endpoint_t Endpoint,
ompt_data_t *ParallelData, ompt_data_t *TaskData,
const void *CodeptrRA);
private:
/// Wrapper around emplace_back for potential additional logging / checking or
/// so
void recordEvent(OmptAssertEvent &&Event);
/// Listeners to be notified
std::vector<OmptListener *> Subscribers;
/// Toggle if OMPT events should notify subscribers immediately or not
bool RecordAndReplay{false};
/// Recorded events in Record and Replay mode
std::vector<OmptAssertEvent> RecordedEvents;
};
} // namespace omptest
// Pointer to global callback handler
extern omptest::OmptCallbackHandler *Handler;
#endif

View File

@ -1,60 +0,0 @@
//===- OmptTester.h - Main header for ompTest usage -------------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file represents the main header file for usage of the ompTest library.
/// Depending on the build either 'standalone' or GoogleTest headers are
/// included and corresponding main-function macros are defined.
///
//===----------------------------------------------------------------------===//
#ifndef OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTTESTER_H
#define OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTTESTER_H
#include "AssertMacros.h"
#include "Logging.h"
#include "OmptAliases.h"
#include "OmptAssertEvent.h"
#include "OmptAsserter.h"
#include "OmptCallbackHandler.h"
#include <cassert>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <unordered_set>
#include <vector>
// Standalone header section
#ifdef OPENMP_LIBOMPTEST_BUILD_STANDALONE
#include "OmptTesterStandalone.h"
// Define standalone main function (place once at the bottom of a testsuite)
#define OMPTEST_TESTSUITE_MAIN() \
int main(int argc, char **argv) { \
Runner R; \
return R.run(); \
}
// GoogleTest header section
#else
#include "OmptTesterGoogleTest.h"
// Define GoogleTest main function (place once at the bottom of a testsuite)
#define OMPTEST_TESTSUITE_MAIN() \
int main(int argc, char **argv) { \
testing::InitGoogleTest(&argc, argv); \
return RUN_ALL_TESTS(); \
}
#endif
#endif

View File

@ -1,36 +0,0 @@
//===- OmptTesterGlobals.h - Global function declarations -------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Contains global function declarations, esp. for OMPT symbols.
///
//===----------------------------------------------------------------------===//
#ifndef OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTTESTERGLOBALS_H
#define OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTTESTERGLOBALS_H
#include <omp-tools.h>
#ifdef __cplusplus
extern "C" {
#endif
ompt_start_tool_result_t *ompt_start_tool(unsigned int omp_version,
const char *runtime_version);
int start_trace(ompt_device_t *Device);
int flush_trace(ompt_device_t *Device);
// Function which calls flush_trace(ompt_device_t *) on all traced devices.
int flush_traced_devices();
int stop_trace(ompt_device_t *Device);
// Function which calls stop_trace(ompt_device_t *) on all traced devices.
int stop_trace_devices();
void libomptest_global_eventreporter_set_active(bool State);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,86 +0,0 @@
//===- OmptTesterGoogleTest.h - GoogleTest header variant -------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file represents the GoogleTest-based header variant, defining the
/// actual test classes and their behavior.
///
//===----------------------------------------------------------------------===//
#ifndef OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTTESTERGOOGLETEST_H
#define OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTTESTERGOOGLETEST_H
#include "AssertMacros.h"
#include "OmptAliases.h"
#include "OmptAssertEvent.h"
#include "OmptAsserter.h"
#include "OmptCallbackHandler.h"
#include "OmptTesterGlobals.h"
// This will allow us to override the "TEST" macro of gtest
#define GTEST_DONT_DEFINE_TEST 1
#include "gtest/gtest.h"
namespace testing {
class GTEST_API_ OmptTestCase : public testing::Test,
public omptest::OmptEventGroupInterface {
public:
std::unique_ptr<omptest::OmptSequencedAsserter> SequenceAsserter =
std::make_unique<omptest::OmptSequencedAsserter>();
std::unique_ptr<omptest::OmptEventAsserter> SetAsserter =
std::make_unique<omptest::OmptEventAsserter>();
std::unique_ptr<omptest::OmptEventReporter> EventReporter =
std::make_unique<omptest::OmptEventReporter>();
protected:
void SetUp() override {
omptest::OmptCallbackHandler::get().subscribe(SequenceAsserter.get());
omptest::OmptCallbackHandler::get().subscribe(SetAsserter.get());
omptest::OmptCallbackHandler::get().subscribe(EventReporter.get());
}
void TearDown() override {
// Actively flush potential in-flight trace records
flush_traced_devices();
// Remove subscribers to not be notified of events after test execution.
omptest::OmptCallbackHandler::get().clearSubscribers();
// This common testcase must not encounter any failures.
if (SequenceAsserter->checkState() == omptest::AssertState::Fail ||
SetAsserter->checkState() == omptest::AssertState::Fail)
ADD_FAILURE();
}
};
class GTEST_API_ OmptTestCaseXFail : public testing::OmptTestCase {
protected:
void TearDown() override {
// Actively flush potential in-flight trace records
flush_traced_devices();
// Remove subscribers to not be notified of events after test execution.
omptest::OmptCallbackHandler::get().clearSubscribers();
// This eXpectedly failing testcase has to encounter at least one failure.
if (SequenceAsserter->checkState() == omptest::AssertState::Pass &&
SetAsserter->checkState() == omptest::AssertState::Pass)
ADD_FAILURE();
}
};
} // namespace testing
#define TEST(test_suite_name, test_name) \
GTEST_TEST_(test_suite_name, test_name, ::testing::OmptTestCase, \
::testing::internal::GetTypeId<::testing::OmptTestCase>())
#define TEST_XFAIL(test_suite_name, test_name) \
GTEST_TEST_(test_suite_name, test_name, ::testing::OmptTestCaseXFail, \
::testing::internal::GetTypeId<::testing::OmptTestCaseXFail>())
#endif // include guard

View File

@ -1,123 +0,0 @@
//===- OmptTesterStandalone.h - Standalone header variant -------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file represents the 'standalone' header variant, defining the actual
/// test classes and their behavior (it does not have external dependencies).
///
//===----------------------------------------------------------------------===//
#ifndef OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTTESTERSTANDALONE_H
#define OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTTESTERSTANDALONE_H
#include "OmptAssertEvent.h"
#include "OmptAsserter.h"
#include "OmptTesterGlobals.h"
#include <map>
#include <vector>
// Forward declarations.
namespace omptest {
struct OmptEventAsserter;
class OmptEventReporter;
class OmptSequencedAsserter;
} // namespace omptest
struct Error {
operator bool() { return Fail; }
bool Fail;
};
/// A pretty crude test case abstraction
struct TestCase {
TestCase(const std::string &name)
: IsDisabled(name.rfind("DISABLED_", 0) == 0), Name(name) {}
TestCase(const std::string &name, const omptest::AssertState &expected)
: IsDisabled(name.rfind("DISABLED_", 0) == 0), Name(name),
ExpectedState(expected) {}
virtual ~TestCase() = default;
Error exec();
virtual void execImpl() { assert(false && "Allocating base class"); }
bool IsDisabled{false};
std::string Name;
omptest::AssertState ExpectedState{omptest::AssertState::Pass};
omptest::AssertState ResultState{omptest::AssertState::Pass};
std::unique_ptr<omptest::OmptSequencedAsserter> SequenceAsserter =
std::make_unique<omptest::OmptSequencedAsserter>();
std::unique_ptr<omptest::OmptEventAsserter> SetAsserter =
std::make_unique<omptest::OmptEventAsserter>();
std::unique_ptr<omptest::OmptEventReporter> EventReporter =
std::make_unique<omptest::OmptEventReporter>();
};
/// A pretty crude test suite abstraction
struct TestSuite {
using TestCaseVec = std::vector<std::unique_ptr<TestCase>>;
std::string Name;
TestSuite() = default;
TestSuite(const TestSuite &O) = delete;
TestSuite(TestSuite &&O);
void setup();
void teardown();
TestCaseVec::iterator begin();
TestCaseVec::iterator end();
TestCaseVec TestCases;
};
/// Static class used to register all test cases and provide them to the driver
class TestRegistrar {
public:
static TestRegistrar &get();
static std::vector<TestSuite> getTestSuites();
static void addCaseToSuite(TestCase *TC, std::string TSName);
private:
TestRegistrar() = default;
TestRegistrar(const TestRegistrar &o) = delete;
TestRegistrar operator=(const TestRegistrar &o) = delete;
// Keep tests in order 'of appearance' (top -> bottom), avoid unordered_map
static std::map<std::string, TestSuite> Tests;
};
/// Hack to register test cases
struct Registerer {
Registerer(TestCase *TC, const std::string SuiteName);
};
/// Eventually executes all test suites and cases, should contain logic to skip
/// stuff if needed
struct Runner {
Runner() : TestSuites(TestRegistrar::get().getTestSuites()) {}
int run();
void reportError(const Error &Err);
void abortOrKeepGoing();
// Print an execution summary of all testsuites and their corresponding
// testcases.
void printSummary();
std::vector<TestSuite> TestSuites;
};
/// MACROS TO DEFINE A TESTSUITE + TESTCASE (like GoogleTest does)
#define XQUOTE(str) QUOTE(str)
#define QUOTE(str) #str
#define TEST_TEMPLATE(SuiteName, CaseName, ExpectedState) \
struct SuiteName##_##CaseName : public TestCase { \
SuiteName##_##CaseName() \
: TestCase(XQUOTE(CaseName), omptest::AssertState::ExpectedState) {} \
virtual void execImpl() override; \
}; \
static Registerer R_##SuiteName##CaseName(new SuiteName##_##CaseName(), \
#SuiteName); \
void SuiteName##_##CaseName::execImpl()
#define TEST(SuiteName, CaseName) \
TEST_TEMPLATE(SuiteName, CaseName, /*ExpectedState=*/Pass)
#define TEST_XFAIL(SuiteName, CaseName) \
TEST_TEMPLATE(SuiteName, CaseName, /*ExpectedState=*/Fail)
#endif

View File

@ -1,367 +0,0 @@
//===- InternalEvent.cpp - Internal event implementation --------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Implements internal event representation methods and helper functions.
///
//===----------------------------------------------------------------------===//
#include "InternalEvent.h"
#include <iomanip>
#include <sstream>
using namespace omptest;
using namespace util;
std::string util::makeHexString(uint64_t Data, bool IsPointer, size_t MinBytes,
bool ShowHexBase) {
if (Data == 0 && IsPointer)
return "(nil)";
thread_local std::ostringstream os;
// Clear the content of the stream
os.str(std::string());
// Manually prefixing "0x" will make the use of std::setfill more easy
if (ShowHexBase)
os << "0x";
// Default to 32bit (8 hex digits) width, if exceeding 64bit or zero value
size_t NumDigits = (MinBytes > 0 && MinBytes < 9) ? (MinBytes << 1) : 8;
if (MinBytes > 0)
os << std::setfill('0') << std::setw(NumDigits);
os << std::hex << Data;
return os.str();
}
std::string internal::AssertionSyncPoint::toString() const {
std::string S{"Assertion SyncPoint: '"};
S.append(Name).append(1, '\'');
return S;
}
std::string internal::ThreadBegin::toString() const {
std::string S{"OMPT Callback ThreadBegin: "};
S.append("ThreadType=").append(std::to_string(ThreadType));
return S;
}
std::string internal::ThreadEnd::toString() const {
std::string S{"OMPT Callback ThreadEnd"};
return S;
}
std::string internal::ParallelBegin::toString() const {
std::string S{"OMPT Callback ParallelBegin: "};
S.append("NumThreads=").append(std::to_string(NumThreads));
return S;
}
std::string internal::ParallelEnd::toString() const {
// TODO: Should we expose more detailed info here?
std::string S{"OMPT Callback ParallelEnd"};
return S;
}
std::string internal::Work::toString() const {
std::string S{"OMPT Callback Work: "};
S.append("work_type=").append(std::to_string(WorkType));
S.append(" endpoint=").append(std::to_string(Endpoint));
S.append(" parallel_data=").append(makeHexString((uint64_t)ParallelData));
S.append(" task_data=").append(makeHexString((uint64_t)TaskData));
S.append(" count=").append(std::to_string(Count));
S.append(" codeptr=").append(makeHexString((uint64_t)CodeptrRA));
return S;
}
std::string internal::Dispatch::toString() const {
std::string S{"OMPT Callback Dispatch: "};
S.append("parallel_data=").append(makeHexString((uint64_t)ParallelData));
S.append(" task_data=").append(makeHexString((uint64_t)TaskData));
S.append(" kind=").append(std::to_string(Kind));
// TODO Check what to print for instance in all different cases
if (Kind == ompt_dispatch_iteration) {
S.append(" instance=[it=")
.append(std::to_string(Instance.value))
.append(1, ']');
} else if (Kind == ompt_dispatch_section) {
S.append(" instance=[ptr=")
.append(makeHexString((uint64_t)Instance.ptr))
.append(1, ']');
} else if ((Kind == ompt_dispatch_ws_loop_chunk ||
Kind == ompt_dispatch_taskloop_chunk ||
Kind == ompt_dispatch_distribute_chunk) &&
Instance.ptr != nullptr) {
auto Chunk = static_cast<ompt_dispatch_chunk_t *>(Instance.ptr);
S.append(" instance=[chunk=(start=")
.append(std::to_string(Chunk->start))
.append(", iterations=")
.append(std::to_string(Chunk->iterations))
.append(")]");
}
return S;
}
std::string internal::TaskCreate::toString() const {
std::string S{"OMPT Callback TaskCreate: "};
S.append("encountering_task_data=")
.append(makeHexString((uint64_t)EncounteringTaskData));
S.append(" encountering_task_frame=")
.append(makeHexString((uint64_t)EncounteringTaskFrame));
S.append(" new_task_data=").append(makeHexString((uint64_t)NewTaskData));
S.append(" flags=").append(std::to_string(Flags));
S.append(" has_dependences=").append(std::to_string(HasDependences));
S.append(" codeptr=").append(makeHexString((uint64_t)CodeptrRA));
return S;
}
std::string internal::ImplicitTask::toString() const {
std::string S{"OMPT Callback ImplicitTask: "};
S.append("endpoint=").append(std::to_string(Endpoint));
S.append(" parallel_data=").append(makeHexString((uint64_t)ParallelData));
S.append(" task_data=").append(makeHexString((uint64_t)TaskData));
S.append(" actual_parallelism=").append(std::to_string(ActualParallelism));
S.append(" index=").append(std::to_string(Index));
S.append(" flags=").append(std::to_string(Flags));
return S;
}
std::string internal::SyncRegion::toString() const {
std::string S{"OMPT Callback SyncRegion: "};
S.append("kind=").append(std::to_string(Kind));
S.append(" endpoint=").append(std::to_string(Endpoint));
S.append(" parallel_data=").append(makeHexString((uint64_t)ParallelData));
S.append(" task_data=").append(makeHexString((uint64_t)TaskData));
S.append(" codeptr=").append(makeHexString((uint64_t)CodeptrRA));
return S;
}
std::string internal::Target::toString() const {
// TODO Should we canonicalize the string prefix (use "OMPT ..." everywhere)?
std::string S{"Callback Target: target_id="};
S.append(std::to_string(TargetId));
S.append(" kind=").append(std::to_string(Kind));
S.append(" endpoint=").append(std::to_string(Endpoint));
S.append(" device_num=").append(std::to_string(DeviceNum));
S.append(" code=").append(makeHexString((uint64_t)CodeptrRA));
return S;
}
std::string internal::TargetEmi::toString() const {
// TODO Should we canonicalize the string prefix (use "OMPT ..." everywhere)?
std::string S{"Callback Target EMI: kind="};
S.append(std::to_string(Kind));
S.append(" endpoint=").append(std::to_string(Endpoint));
S.append(" device_num=").append(std::to_string(DeviceNum));
S.append(" task_data=").append(makeHexString((uint64_t)TaskData));
S.append(" (")
.append(makeHexString((uint64_t)(TaskData) ? TaskData->value : 0,
/*IsPointer=*/false))
.append(1, ')');
S.append(" target_task_data=")
.append(makeHexString((uint64_t)TargetTaskData));
S.append(" (")
.append(
makeHexString((uint64_t)(TargetTaskData) ? TargetTaskData->value : 0,
/*IsPointer=*/false))
.append(1, ')');
S.append(" target_data=").append(makeHexString((uint64_t)TargetData));
S.append(" (")
.append(makeHexString((uint64_t)(TargetData) ? TargetData->value : 0,
/*IsPointer=*/false))
.append(1, ')');
S.append(" code=").append(makeHexString((uint64_t)CodeptrRA));
return S;
}
std::string internal::TargetDataOp::toString() const {
std::string S{" Callback DataOp: target_id="};
S.append(std::to_string(TargetId));
S.append(" host_op_id=").append(std::to_string(HostOpId));
S.append(" optype=").append(std::to_string(OpType));
S.append(" src=").append(makeHexString((uint64_t)SrcAddr));
S.append(" src_device_num=").append(std::to_string(SrcDeviceNum));
S.append(" dest=").append(makeHexString((uint64_t)DstAddr));
S.append(" dest_device_num=").append(std::to_string(DstDeviceNum));
S.append(" bytes=").append(std::to_string(Bytes));
S.append(" code=").append(makeHexString((uint64_t)CodeptrRA));
return S;
}
std::string internal::TargetDataOpEmi::toString() const {
std::string S{" Callback DataOp EMI: endpoint="};
S.append(std::to_string(Endpoint));
S.append(" optype=").append(std::to_string(OpType));
S.append(" target_task_data=")
.append(makeHexString((uint64_t)TargetTaskData));
S.append(" (")
.append(
makeHexString((uint64_t)(TargetTaskData) ? TargetTaskData->value : 0,
/*IsPointer=*/false))
.append(1, ')');
S.append(" target_data=").append(makeHexString((uint64_t)TargetData));
S.append(" (")
.append(makeHexString((uint64_t)(TargetData) ? TargetData->value : 0,
/*IsPointer=*/false))
.append(1, ')');
S.append(" host_op_id=").append(makeHexString((uint64_t)HostOpId));
S.append(" (")
.append(makeHexString((uint64_t)(HostOpId) ? (*HostOpId) : 0,
/*IsPointer=*/false))
.append(1, ')');
S.append(" src=").append(makeHexString((uint64_t)SrcAddr));
S.append(" src_device_num=").append(std::to_string(SrcDeviceNum));
S.append(" dest=").append(makeHexString((uint64_t)DstAddr));
S.append(" dest_device_num=").append(std::to_string(DstDeviceNum));
S.append(" bytes=").append(std::to_string(Bytes));
S.append(" code=").append(makeHexString((uint64_t)CodeptrRA));
return S;
}
std::string internal::TargetSubmit::toString() const {
std::string S{" Callback Submit: target_id="};
S.append(std::to_string(TargetId));
S.append(" host_op_id=").append(std::to_string(HostOpId));
S.append(" req_num_teams=").append(std::to_string(RequestedNumTeams));
return S;
}
std::string internal::TargetSubmitEmi::toString() const {
std::string S{" Callback Submit EMI: endpoint="};
S.append(std::to_string(Endpoint));
S.append(" req_num_teams=").append(std::to_string(RequestedNumTeams));
S.append(" target_data=").append(makeHexString((uint64_t)TargetData));
S.append(" (")
.append(makeHexString((uint64_t)(TargetData) ? TargetData->value : 0,
/*IsPointer=*/false))
.append(1, ')');
S.append(" host_op_id=").append(makeHexString((uint64_t)HostOpId));
S.append(" (")
.append(makeHexString((uint64_t)(HostOpId) ? (*HostOpId) : 0,
/*IsPointer=*/false))
.append(1, ')');
return S;
}
std::string internal::DeviceInitialize::toString() const {
std::string S{"Callback Init: device_num="};
S.append(std::to_string(DeviceNum));
S.append(" type=").append((Type) ? Type : "(null)");
S.append(" device=").append(makeHexString((uint64_t)Device));
S.append(" lookup=").append(makeHexString((uint64_t)LookupFn));
S.append(" doc=").append(makeHexString((uint64_t)DocStr));
return S;
}
std::string internal::DeviceFinalize::toString() const {
std::string S{"Callback Fini: device_num="};
S.append(std::to_string(DeviceNum));
return S;
}
std::string internal::DeviceLoad::toString() const {
std::string S{"Callback Load: device_num:"};
S.append(std::to_string(DeviceNum));
S.append(" module_id:").append(std::to_string(ModuleId));
S.append(" filename:").append((Filename == nullptr) ? "(null)" : Filename);
S.append(" host_addr:").append(makeHexString((uint64_t)HostAddr));
S.append(" device_addr:").append(makeHexString((uint64_t)DeviceAddr));
S.append(" bytes:").append(std::to_string(Bytes));
return S;
}
std::string internal::BufferRequest::toString() const {
std::string S{"Allocated "};
S.append(std::to_string((Bytes != nullptr) ? *Bytes : 0))
.append(" bytes at ");
S.append(makeHexString((Buffer != nullptr) ? (uint64_t)*Buffer : 0));
S.append(" in buffer request callback");
return S;
}
std::string internal::BufferComplete::toString() const {
std::string S{"Executing buffer complete callback: "};
S.append(std::to_string(DeviceNum)).append(1, ' ');
S.append(makeHexString((uint64_t)Buffer)).append(1, ' ');
S.append(std::to_string(Bytes)).append(1, ' ');
S.append(makeHexString((uint64_t)Begin)).append(1, ' ');
S.append(std::to_string(BufferOwned));
return S;
}
std::string internal::BufferRecord::toString() const {
std::string S{""};
std::string T{""};
S.append("rec=").append(makeHexString((uint64_t)RecordPtr));
S.append(" type=").append(std::to_string(Record.type));
T.append("time=").append(std::to_string(Record.time));
T.append(" thread_id=").append(std::to_string(Record.thread_id));
T.append(" target_id=").append(std::to_string(Record.target_id));
switch (Record.type) {
case ompt_callback_target:
case ompt_callback_target_emi: {
// Handle Target Record
ompt_record_target_t TR = Record.record.target;
S.append(" (Target task) ").append(T);
S.append(" kind=").append(std::to_string(TR.kind));
S.append(" endpoint=").append(std::to_string(TR.endpoint));
S.append(" device=").append(std::to_string(TR.device_num));
S.append(" task_id=").append(std::to_string(TR.task_id));
S.append(" codeptr=").append(makeHexString((uint64_t)TR.codeptr_ra));
break;
}
case ompt_callback_target_data_op:
case ompt_callback_target_data_op_emi: {
// Handle Target DataOp Record
ompt_record_target_data_op_t TDR = Record.record.target_data_op;
S.append(" (Target data op) ").append(T);
S.append(" host_op_id=").append(std::to_string(TDR.host_op_id));
S.append(" optype=").append(std::to_string(TDR.optype));
S.append(" src_addr=").append(makeHexString((uint64_t)TDR.src_addr));
S.append(" src_device=").append(std::to_string(TDR.src_device_num));
S.append(" dest_addr=").append(makeHexString((uint64_t)TDR.dest_addr));
S.append(" dest_device=").append(std::to_string(TDR.dest_device_num));
S.append(" bytes=").append(std::to_string(TDR.bytes));
S.append(" end_time=").append(std::to_string(TDR.end_time));
S.append(" duration=").append(std::to_string(TDR.end_time - Record.time));
S.append(" ns codeptr=").append(makeHexString((uint64_t)TDR.codeptr_ra));
break;
}
case ompt_callback_target_submit:
case ompt_callback_target_submit_emi: {
// Handle Target Kernel Record
ompt_record_target_kernel_t TKR = Record.record.target_kernel;
S.append(" (Target kernel) ").append(T);
S.append(" host_op_id=").append(std::to_string(TKR.host_op_id));
S.append(" requested_num_teams=")
.append(std::to_string(TKR.requested_num_teams));
S.append(" granted_num_teams=")
.append(std::to_string(TKR.granted_num_teams));
S.append(" end_time=").append(std::to_string(TKR.end_time));
S.append(" duration=").append(std::to_string(TKR.end_time - Record.time));
S.append(" ns");
break;
}
default:
S.append(" (unsupported record type)");
break;
}
return S;
}
std::string internal::BufferRecordDeallocation::toString() const {
std::string S{"Deallocated "};
S.append(makeHexString((uint64_t)Buffer));
return S;
}

View File

@ -1,281 +0,0 @@
//===- InternalEventOperators.cpp - Operator implementations ----*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Defines the internal event operators, like comparators.
///
//===----------------------------------------------------------------------===//
#include "InternalEvent.h"
namespace omptest {
namespace internal {
bool operator==(const ParallelBegin &Expected, const ParallelBegin &Observed) {
return Expected.NumThreads == Observed.NumThreads;
}
bool operator==(const Work &Expected, const Work &Observed) {
bool isSameWorkType = (Expected.WorkType == Observed.WorkType);
bool isSameEndpoint = (Expected.Endpoint == Observed.Endpoint);
bool isSameParallelData =
(Expected.ParallelData == std::numeric_limits<ompt_data_t *>::min()) ||
(Expected.ParallelData == Observed.ParallelData);
bool isSameTaskData =
(Expected.TaskData == std::numeric_limits<ompt_data_t *>::min()) ||
(Expected.TaskData == Observed.TaskData);
bool isSameCount = (Expected.Count == std::numeric_limits<uint64_t>::min()) ||
(Expected.Count == Observed.Count);
return isSameWorkType && isSameEndpoint && isSameParallelData &&
isSameTaskData && isSameCount;
}
bool operator==(const ImplicitTask &Expected, const ImplicitTask &Observed) {
bool isSameEndpoint = (Expected.Endpoint == Observed.Endpoint);
bool isSameActualParallelism =
(Expected.ActualParallelism ==
std::numeric_limits<unsigned int>::min()) ||
(Expected.ActualParallelism == Observed.ActualParallelism);
bool isSameIndex =
(Expected.Index == std::numeric_limits<unsigned int>::min()) ||
(Expected.Index == Observed.Index);
return isSameEndpoint && isSameActualParallelism && isSameIndex;
}
bool operator==(const SyncRegion &Expected, const SyncRegion &Observed) {
bool isSameKind = (Expected.Kind == Observed.Kind);
bool isSameEndpoint = (Expected.Endpoint == Observed.Endpoint);
bool isSameParallelData =
(Expected.ParallelData == std::numeric_limits<ompt_data_t *>::min()) ||
(Expected.ParallelData == Observed.ParallelData);
bool isSameTaskData =
(Expected.TaskData == std::numeric_limits<ompt_data_t *>::min()) ||
(Expected.TaskData == Observed.TaskData);
return isSameKind && isSameEndpoint && isSameParallelData && isSameTaskData;
}
bool operator==(const Target &Expected, const Target &Observed) {
bool isSameKind = (Expected.Kind == Observed.Kind);
bool isSameEndpoint = (Expected.Endpoint == Observed.Endpoint);
bool isSameDeviceNum =
(Expected.DeviceNum == std::numeric_limits<int>::min()) ||
(Expected.DeviceNum == Observed.DeviceNum);
return isSameKind && isSameEndpoint && isSameDeviceNum;
}
bool operator==(const TargetEmi &Expected, const TargetEmi &Observed) {
bool isSameKind = (Expected.Kind == Observed.Kind);
bool isSameEndpoint = (Expected.Endpoint == Observed.Endpoint);
bool isSameDeviceNum =
(Expected.DeviceNum == std::numeric_limits<int>::min()) ||
(Expected.DeviceNum == Observed.DeviceNum);
return isSameKind && isSameEndpoint && isSameDeviceNum;
}
bool operator==(const TargetDataOp &Expected, const TargetDataOp &Observed) {
bool isSameOpType = (Expected.OpType == Observed.OpType);
bool isSameSize = (Expected.Bytes == std::numeric_limits<size_t>::min()) ||
(Expected.Bytes == Observed.Bytes);
bool isSameSrcAddr =
(Expected.SrcAddr == std::numeric_limits<void *>::min()) ||
(Expected.SrcAddr == Observed.SrcAddr);
bool isSameDstAddr =
(Expected.DstAddr == std::numeric_limits<void *>::min()) ||
(Expected.DstAddr == Observed.DstAddr);
bool isSameSrcDeviceNum =
(Expected.SrcDeviceNum == std::numeric_limits<int>::min()) ||
(Expected.SrcDeviceNum == Observed.SrcDeviceNum);
bool isSameDstDeviceNum =
(Expected.DstDeviceNum == std::numeric_limits<int>::min()) ||
(Expected.DstDeviceNum == Observed.DstDeviceNum);
return isSameOpType && isSameSize && isSameSrcAddr && isSameDstAddr &&
isSameSrcDeviceNum && isSameDstDeviceNum;
}
bool operator==(const TargetDataOpEmi &Expected,
const TargetDataOpEmi &Observed) {
bool isSameOpType = (Expected.OpType == Observed.OpType);
bool isSameEndpoint = (Expected.Endpoint == Observed.Endpoint);
bool isSameSize = (Expected.Bytes == std::numeric_limits<size_t>::min()) ||
(Expected.Bytes == Observed.Bytes);
bool isSameSrcAddr =
(Expected.SrcAddr == std::numeric_limits<void *>::min()) ||
(Expected.SrcAddr == Observed.SrcAddr);
bool isSameDstAddr =
(Expected.DstAddr == std::numeric_limits<void *>::min()) ||
(Expected.DstAddr == Observed.DstAddr);
bool isSameSrcDeviceNum =
(Expected.SrcDeviceNum == std::numeric_limits<int>::min()) ||
(Expected.SrcDeviceNum == Observed.SrcDeviceNum);
bool isSameDstDeviceNum =
(Expected.DstDeviceNum == std::numeric_limits<int>::min()) ||
(Expected.DstDeviceNum == Observed.DstDeviceNum);
return isSameOpType && isSameEndpoint && isSameSize && isSameSrcAddr &&
isSameDstAddr && isSameSrcDeviceNum && isSameDstDeviceNum;
}
bool operator==(const TargetSubmit &Expected, const TargetSubmit &Observed) {
bool isSameReqNumTeams =
(Expected.RequestedNumTeams == Observed.RequestedNumTeams);
return isSameReqNumTeams;
}
bool operator==(const TargetSubmitEmi &Expected,
const TargetSubmitEmi &Observed) {
bool isSameReqNumTeams =
(Expected.RequestedNumTeams == Observed.RequestedNumTeams);
bool isSameEndpoint = (Expected.Endpoint == Observed.Endpoint);
return isSameReqNumTeams && isSameEndpoint;
}
bool operator==(const DeviceInitialize &Expected,
const DeviceInitialize &Observed) {
bool isSameDeviceNum = (Expected.DeviceNum == Observed.DeviceNum);
bool isSameType =
(Expected.Type == std::numeric_limits<const char *>::min()) ||
((Expected.Type == Observed.Type) ||
(strcmp(Expected.Type, Observed.Type) == 0));
bool isSameDevice =
(Expected.Device == std::numeric_limits<ompt_device_t *>::min()) ||
(Expected.Device == Observed.Device);
return isSameDeviceNum && isSameType && isSameDevice;
}
bool operator==(const DeviceFinalize &Expected,
const DeviceFinalize &Observed) {
bool isSameDeviceNum =
(Expected.DeviceNum == std::numeric_limits<int>::min()) ||
(Expected.DeviceNum == Observed.DeviceNum);
return isSameDeviceNum;
}
bool operator==(const DeviceLoad &Expected, const DeviceLoad &Observed) {
bool isSameDeviceNum =
(Expected.DeviceNum == std::numeric_limits<int>::min()) ||
(Expected.DeviceNum == Observed.DeviceNum);
bool isSameSize = (Expected.Bytes == std::numeric_limits<size_t>::min()) ||
(Expected.Bytes == Observed.Bytes);
return isSameDeviceNum && isSameSize;
}
bool operator==(const BufferRequest &Expected, const BufferRequest &Observed) {
bool isSameDeviceNum =
(Expected.DeviceNum == std::numeric_limits<int>::min()) ||
(Expected.DeviceNum == Observed.DeviceNum);
bool isSameSize = (Expected.Bytes == std::numeric_limits<size_t *>::min()) ||
(Expected.Bytes == Observed.Bytes);
return isSameDeviceNum && isSameSize;
}
bool operator==(const BufferComplete &Expected,
const BufferComplete &Observed) {
bool isSameDeviceNum =
(Expected.DeviceNum == std::numeric_limits<int>::min()) ||
(Expected.DeviceNum == Observed.DeviceNum);
bool isSameSize = (Expected.Bytes == std::numeric_limits<size_t>::min()) ||
(Expected.Bytes == Observed.Bytes);
return isSameDeviceNum && isSameSize;
}
bool operator==(const BufferRecord &Expected, const BufferRecord &Observed) {
bool isSameType = (Expected.Record.type == Observed.Record.type);
bool isSameTargetId =
(Expected.Record.target_id == std::numeric_limits<ompt_id_t>::min()) ||
(Expected.Record.target_id == Observed.Record.target_id);
if (!(isSameType && isSameTargetId))
return false;
bool isEqual = true;
ompt_device_time_t ObservedDurationNs =
Observed.Record.record.target_data_op.end_time - Observed.Record.time;
switch (Expected.Record.type) {
case ompt_callback_target:
isEqual &= (Expected.Record.record.target.kind ==
std::numeric_limits<ompt_target_t>::min()) ||
(Expected.Record.record.target.kind ==
Observed.Record.record.target.kind);
isEqual &= (Expected.Record.record.target.endpoint ==
std::numeric_limits<ompt_scope_endpoint_t>::min()) ||
(Expected.Record.record.target.endpoint ==
Observed.Record.record.target.endpoint);
isEqual &= (Expected.Record.record.target.device_num ==
std::numeric_limits<int>::min()) ||
(Expected.Record.record.target.device_num ==
Observed.Record.record.target.device_num);
break;
case ompt_callback_target_data_op:
isEqual &= (Expected.Record.record.target_data_op.optype ==
std::numeric_limits<ompt_target_data_op_t>::min()) ||
(Expected.Record.record.target_data_op.optype ==
Observed.Record.record.target_data_op.optype);
isEqual &= (Expected.Record.record.target_data_op.bytes ==
std::numeric_limits<size_t>::min()) ||
(Expected.Record.record.target_data_op.bytes ==
Observed.Record.record.target_data_op.bytes);
isEqual &= (Expected.Record.record.target_data_op.src_addr ==
std::numeric_limits<void *>::min()) ||
(Expected.Record.record.target_data_op.src_addr ==
Observed.Record.record.target_data_op.src_addr);
isEqual &= (Expected.Record.record.target_data_op.dest_addr ==
std::numeric_limits<void *>::min()) ||
(Expected.Record.record.target_data_op.dest_addr ==
Observed.Record.record.target_data_op.dest_addr);
isEqual &= (Expected.Record.record.target_data_op.src_device_num ==
std::numeric_limits<int>::min()) ||
(Expected.Record.record.target_data_op.src_device_num ==
Observed.Record.record.target_data_op.src_device_num);
isEqual &= (Expected.Record.record.target_data_op.dest_device_num ==
std::numeric_limits<int>::min()) ||
(Expected.Record.record.target_data_op.dest_device_num ==
Observed.Record.record.target_data_op.dest_device_num);
isEqual &= (Expected.Record.record.target_data_op.host_op_id ==
std::numeric_limits<ompt_id_t>::min()) ||
(Expected.Record.record.target_data_op.host_op_id ==
Observed.Record.record.target_data_op.host_op_id);
isEqual &= (Expected.Record.record.target_data_op.codeptr_ra ==
std::numeric_limits<void *>::min()) ||
(Expected.Record.record.target_data_op.codeptr_ra ==
Observed.Record.record.target_data_op.codeptr_ra);
if (Expected.Record.record.target_data_op.end_time !=
std::numeric_limits<ompt_device_time_t>::min()) {
isEqual &=
ObservedDurationNs <= Expected.Record.record.target_data_op.end_time;
}
isEqual &= ObservedDurationNs >= Expected.Record.time;
break;
case ompt_callback_target_submit:
ObservedDurationNs =
Observed.Record.record.target_kernel.end_time - Observed.Record.time;
isEqual &= (Expected.Record.record.target_kernel.requested_num_teams ==
std::numeric_limits<unsigned int>::min()) ||
(Expected.Record.record.target_kernel.requested_num_teams ==
Observed.Record.record.target_kernel.requested_num_teams);
isEqual &= (Expected.Record.record.target_kernel.granted_num_teams ==
std::numeric_limits<unsigned int>::min()) ||
(Expected.Record.record.target_kernel.granted_num_teams ==
Observed.Record.record.target_kernel.granted_num_teams);
isEqual &= (Expected.Record.record.target_kernel.host_op_id ==
std::numeric_limits<ompt_id_t>::min()) ||
(Expected.Record.record.target_kernel.host_op_id ==
Observed.Record.record.target_kernel.host_op_id);
if (Expected.Record.record.target_kernel.end_time !=
std::numeric_limits<ompt_device_time_t>::min()) {
isEqual &=
ObservedDurationNs <= Expected.Record.record.target_kernel.end_time;
}
isEqual &= ObservedDurationNs >= Expected.Record.time;
break;
default:
assert(false && "Encountered invalid record type");
}
return isEqual;
}
} // namespace internal
} // namespace omptest

View File

@ -1,181 +0,0 @@
//===- Logging.cpp - General logging class implementation -------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Implements ompTest-tailored logging.
///
//===----------------------------------------------------------------------===//
#include "Logging.h"
using namespace omptest;
using namespace logging;
Logger::Logger(Level LogLevel, std::ostream &OutStream, bool FormatOutput)
: LoggingLevel(LogLevel), OutStream(OutStream), FormatOutput(FormatOutput) {
// Flush any buffered output
OutStream << std::flush;
}
Logger::~Logger() {
// Flush any buffered output
OutStream << std::flush;
}
std::map<Level, std::set<FormatOption>> AggregatedFormatOptions{
{Level::Diagnostic, {FormatOption::ColorLightBlue}},
{Level::Info, {FormatOption::ColorLightGray}},
{Level::Warning, {FormatOption::ColorLightYellow}},
{Level::Error, {FormatOption::ColorRed}},
{Level::Critical, {FormatOption::ColorLightRed}},
{Level::Default, {FormatOption::None}},
{Level::ExpectedEvent, {FormatOption::Bold, FormatOption::ColorCyan}},
{Level::ObservedEvent, {FormatOption::ColorCyan}},
{Level::OffendingEvent, {FormatOption::ColorYellow}}};
const char *logging::to_string(Level LogLevel) {
switch (LogLevel) {
case Level::Diagnostic:
return "Diagnostic";
case Level::Info:
return "Info";
case Level::Warning:
return "Warning";
case Level::Error:
return "Error";
case Level::Critical:
return "Critical";
case Level::Silent:
return "Silent";
default:
assert(false && "Requested string representation for unknown LogLevel");
return "UNKNOWN";
}
}
std::string logging::getFormatSequence(Level LogLevel) {
auto Options = AggregatedFormatOptions[LogLevel];
std::stringstream SS{"\033["};
SS << "\033[";
if (!Options.empty()) {
for (auto &Option : AggregatedFormatOptions[LogLevel])
SS << int(Option) << ';';
SS.seekp(-1, SS.cur);
SS << 'm';
} else {
// Fallback to None / reset formatting
SS << "0m";
}
return SS.str();
}
std::string logging::format(const std::string &Message, FormatOption Option) {
std::stringstream SS{"\033["};
SS << "\033[";
SS << int(Option) << 'm' << Message << "\033[0m";
return SS.str();
}
std::string logging::format(const std::string &Message,
std::set<FormatOption> Options) {
std::stringstream SS{"\033["};
SS << "\033[";
for (auto &Option : Options)
SS << int(Option) << ';';
SS.seekp(-1, SS.cur);
SS << 'm' << Message << "\033[0m";
return SS.str();
}
void Logger::log(const std::string &Message, Level LogLevel) const {
// Serialize logging
std::lock_guard<std::mutex> Lock(LogMutex);
if (LoggingLevel > LogLevel)
return;
if (FormatOutput) {
OutStream << getFormatSequence(LogLevel) << '[' << to_string(LogLevel)
<< "] " << Message << getFormatSequence() << std::endl;
} else {
OutStream << '[' << to_string(LogLevel) << "] " << Message << std::endl;
}
}
void Logger::logEventMismatch(const std::string &Message,
const omptest::OmptAssertEvent &OffendingEvent,
Level LogLevel) const {
// Serialize logging
std::lock_guard<std::mutex> Lock(LogMutex);
if (LoggingLevel > LogLevel)
return;
if (FormatOutput) {
OutStream << getFormatSequence(LogLevel) << '[' << to_string(LogLevel)
<< "] " << getFormatSequence()
<< format(Message, AggregatedFormatOptions[LogLevel])
<< "\n\tOffending event name='"
<< format(OffendingEvent.getEventName(),
AggregatedFormatOptions[Level::OffendingEvent])
<< "'\n\tOffending='"
<< format(OffendingEvent.toString(),
AggregatedFormatOptions[Level::OffendingEvent])
<< '\'' << std::endl;
} else {
OutStream << '[' << to_string(LogLevel) << "] " << Message
<< "\n\tOffending event name='" << OffendingEvent.getEventName()
<< "'\n\tOffending='" << OffendingEvent.toString() << '\''
<< std::endl;
}
}
void Logger::logEventMismatch(const std::string &Message,
const omptest::OmptAssertEvent &ExpectedEvent,
const omptest::OmptAssertEvent &ObservedEvent,
Level LogLevel) const {
// Serialize logging
std::lock_guard<std::mutex> Lock(LogMutex);
if (LoggingLevel > LogLevel)
return;
if (FormatOutput) {
OutStream << getFormatSequence(LogLevel) << '[' << to_string(LogLevel)
<< "] " << Message << getFormatSequence()
<< "\n\tExpected event name='"
<< format(ExpectedEvent.getEventName(),
AggregatedFormatOptions[Level::ExpectedEvent])
<< "' observe='"
<< format(to_string(ExpectedEvent.getEventExpectedState()),
AggregatedFormatOptions[Level::ExpectedEvent])
<< "'\n\tObserved event name='"
<< format(ObservedEvent.getEventName(),
AggregatedFormatOptions[Level::ObservedEvent])
<< "'\n\tExpected='"
<< format(ExpectedEvent.toString(),
AggregatedFormatOptions[Level::ExpectedEvent])
<< "'\n\tObserved='"
<< format(ObservedEvent.toString(),
AggregatedFormatOptions[Level::ObservedEvent])
<< '\'' << std::endl;
} else {
OutStream << '[' << to_string(LogLevel) << "] " << Message
<< "\n\tExpected event name='" << ExpectedEvent.getEventName()
<< "' observe='"
<< to_string(ExpectedEvent.getEventExpectedState())
<< "'\n\tObserved event name='" << ObservedEvent.getEventName()
<< "'\n\tExpected='" << ExpectedEvent.toString()
<< "'\n\tObserved='" << ObservedEvent.toString() << '\''
<< std::endl;
}
}
void Logger::setFormatOutput(bool Enabled) { FormatOutput = Enabled; }
Level Logger::getLoggingLevel() const { return LoggingLevel; }
void Logger::setLoggingLevel(Level LogLevel) { LoggingLevel = LogLevel; }

View File

@ -1,587 +0,0 @@
//===- OmptAssertEvent.cpp - Assertion event implementations ----*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Implements assertion event CTORs, for generally all observable events.
///
//===----------------------------------------------------------------------===//
#include "OmptAssertEvent.h"
#include <omp-tools.h>
using namespace omptest;
const char *omptest::to_string(ObserveState State) {
switch (State) {
case ObserveState::Generated:
return "Generated";
case ObserveState::Always:
return "Always";
case ObserveState::Never:
return "Never";
default:
assert(false && "Requested string representation for unknown ObserveState");
return "UNKNOWN";
}
}
OmptAssertEvent::OmptAssertEvent(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
internal::InternalEvent *IE)
: Name(Name), Group(Group), ExpectedState(Expected), TheEvent(IE) {}
OmptAssertEvent OmptAssertEvent::AssertionSyncPoint(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, const std::string &SyncPointName) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::AssertionSyncPoint(SyncPointName));
}
OmptAssertEvent
OmptAssertEvent::AssertionSuspend(const std::string &Name,
const std::string &Group,
const ObserveState &Expected) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::AssertionSuspend());
}
OmptAssertEvent OmptAssertEvent::ThreadBegin(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
ompt_thread_t ThreadType) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::ThreadBegin(ThreadType));
}
OmptAssertEvent OmptAssertEvent::ThreadEnd(const std::string &Name,
const std::string &Group,
const ObserveState &Expected) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected, new internal::ThreadEnd());
}
OmptAssertEvent OmptAssertEvent::ParallelBegin(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
int NumThreads) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::ParallelBegin(NumThreads));
}
OmptAssertEvent OmptAssertEvent::ParallelEnd(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
ompt_data_t *ParallelData,
ompt_data_t *EncounteringTaskData,
int Flags, const void *CodeptrRA) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::ParallelEnd(ParallelData,
EncounteringTaskData, Flags,
CodeptrRA));
}
OmptAssertEvent
OmptAssertEvent::Work(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_work_t WorkType,
ompt_scope_endpoint_t Endpoint, ompt_data_t *ParallelData,
ompt_data_t *TaskData, uint64_t Count,
const void *CodeptrRA) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::Work(WorkType, Endpoint, ParallelData,
TaskData, Count, CodeptrRA));
}
OmptAssertEvent
OmptAssertEvent::Dispatch(const std::string &Name, const std::string &Group,
const ObserveState &Expected,
ompt_data_t *ParallelData, ompt_data_t *TaskData,
ompt_dispatch_t Kind, ompt_data_t Instance) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(
EName, EGroup, Expected,
new internal::Dispatch(ParallelData, TaskData, Kind, Instance));
}
OmptAssertEvent OmptAssertEvent::TaskCreate(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_data_t *EncounteringTaskData,
const ompt_frame_t *EncounteringTaskFrame, ompt_data_t *NewTaskData,
int Flags, int HasDependences, const void *CodeptrRA) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(
EName, EGroup, Expected,
new internal::TaskCreate(EncounteringTaskData, EncounteringTaskFrame,
NewTaskData, Flags, HasDependences, CodeptrRA));
}
OmptAssertEvent OmptAssertEvent::TaskSchedule(const std::string &Name,
const std::string &Group,
const ObserveState &Expected) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected, new internal::TaskSchedule());
}
OmptAssertEvent OmptAssertEvent::ImplicitTask(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_scope_endpoint_t Endpoint,
ompt_data_t *ParallelData, ompt_data_t *TaskData,
unsigned int ActualParallelism, unsigned int Index, int Flags) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::ImplicitTask(Endpoint, ParallelData,
TaskData, ActualParallelism,
Index, Flags));
}
OmptAssertEvent OmptAssertEvent::SyncRegion(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_sync_region_t Kind,
ompt_scope_endpoint_t Endpoint, ompt_data_t *ParallelData,
ompt_data_t *TaskData, const void *CodeptrRA) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::SyncRegion(Kind, Endpoint, ParallelData,
TaskData, CodeptrRA));
}
OmptAssertEvent
OmptAssertEvent::Target(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_target_t Kind,
ompt_scope_endpoint_t Endpoint, int DeviceNum,
ompt_data_t *TaskData, ompt_id_t TargetId,
const void *CodeptrRA) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::Target(Kind, Endpoint, DeviceNum,
TaskData, TargetId, CodeptrRA));
}
OmptAssertEvent
OmptAssertEvent::TargetEmi(const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_target_t Kind,
ompt_scope_endpoint_t Endpoint, int DeviceNum,
ompt_data_t *TaskData, ompt_data_t *TargetTaskData,
ompt_data_t *TargetData, const void *CodeptrRA) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::TargetEmi(Kind, Endpoint, DeviceNum,
TaskData, TargetTaskData,
TargetData, CodeptrRA));
}
OmptAssertEvent OmptAssertEvent::TargetDataOp(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_id_t TargetId, ompt_id_t HostOpId,
ompt_target_data_op_t OpType, void *SrcAddr, int SrcDeviceNum,
void *DstAddr, int DstDeviceNum, size_t Bytes, const void *CodeptrRA) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::TargetDataOp(
TargetId, HostOpId, OpType, SrcAddr, SrcDeviceNum,
DstAddr, DstDeviceNum, Bytes, CodeptrRA));
}
OmptAssertEvent OmptAssertEvent::TargetDataOp(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_target_data_op_t OpType, size_t Bytes,
void *SrcAddr, void *DstAddr, int SrcDeviceNum, int DstDeviceNum,
ompt_id_t TargetId, ompt_id_t HostOpId, const void *CodeptrRA) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::TargetDataOp(
TargetId, HostOpId, OpType, SrcAddr, SrcDeviceNum,
DstAddr, DstDeviceNum, Bytes, CodeptrRA));
}
OmptAssertEvent OmptAssertEvent::TargetDataOpEmi(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_scope_endpoint_t Endpoint,
ompt_data_t *TargetTaskData, ompt_data_t *TargetData, ompt_id_t *HostOpId,
ompt_target_data_op_t OpType, void *SrcAddr, int SrcDeviceNum,
void *DstAddr, int DstDeviceNum, size_t Bytes, const void *CodeptrRA) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(
EName, EGroup, Expected,
new internal::TargetDataOpEmi(Endpoint, TargetTaskData, TargetData,
HostOpId, OpType, SrcAddr, SrcDeviceNum,
DstAddr, DstDeviceNum, Bytes, CodeptrRA));
}
OmptAssertEvent OmptAssertEvent::TargetDataOpEmi(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_target_data_op_t OpType,
ompt_scope_endpoint_t Endpoint, size_t Bytes, void *SrcAddr, void *DstAddr,
int SrcDeviceNum, int DstDeviceNum, ompt_data_t *TargetTaskData,
ompt_data_t *TargetData, ompt_id_t *HostOpId, const void *CodeptrRA) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(
EName, EGroup, Expected,
new internal::TargetDataOpEmi(Endpoint, TargetTaskData, TargetData,
HostOpId, OpType, SrcAddr, SrcDeviceNum,
DstAddr, DstDeviceNum, Bytes, CodeptrRA));
}
OmptAssertEvent OmptAssertEvent::TargetSubmit(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
ompt_id_t TargetId,
ompt_id_t HostOpId,
unsigned int RequestedNumTeams) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(
EName, EGroup, Expected,
new internal::TargetSubmit(TargetId, HostOpId, RequestedNumTeams));
}
OmptAssertEvent OmptAssertEvent::TargetSubmit(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
unsigned int RequestedNumTeams,
ompt_id_t TargetId,
ompt_id_t HostOpId) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(
EName, EGroup, Expected,
new internal::TargetSubmit(TargetId, HostOpId, RequestedNumTeams));
}
OmptAssertEvent OmptAssertEvent::TargetSubmitEmi(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_scope_endpoint_t Endpoint,
ompt_data_t *TargetData, ompt_id_t *HostOpId,
unsigned int RequestedNumTeams) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::TargetSubmitEmi(Endpoint, TargetData,
HostOpId,
RequestedNumTeams));
}
OmptAssertEvent OmptAssertEvent::TargetSubmitEmi(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
unsigned int RequestedNumTeams,
ompt_scope_endpoint_t Endpoint,
ompt_data_t *TargetData,
ompt_id_t *HostOpId) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::TargetSubmitEmi(Endpoint, TargetData,
HostOpId,
RequestedNumTeams));
}
OmptAssertEvent OmptAssertEvent::ControlTool(const std::string &Name,
const std::string &Group,
const ObserveState &Expected) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected, new internal::ControlTool());
}
OmptAssertEvent OmptAssertEvent::DeviceInitialize(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, int DeviceNum, const char *Type,
ompt_device_t *Device, ompt_function_lookup_t LookupFn,
const char *DocumentationStr) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::DeviceInitialize(DeviceNum, Type, Device,
LookupFn,
DocumentationStr));
}
OmptAssertEvent OmptAssertEvent::DeviceFinalize(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
int DeviceNum) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::DeviceFinalize(DeviceNum));
}
OmptAssertEvent
OmptAssertEvent::DeviceLoad(const std::string &Name, const std::string &Group,
const ObserveState &Expected, int DeviceNum,
const char *Filename, int64_t OffsetInFile,
void *VmaInFile, size_t Bytes, void *HostAddr,
void *DeviceAddr, uint64_t ModuleId) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(
EName, EGroup, Expected,
new internal::DeviceLoad(DeviceNum, Filename, OffsetInFile, VmaInFile,
Bytes, HostAddr, DeviceAddr, ModuleId));
}
OmptAssertEvent OmptAssertEvent::DeviceUnload(const std::string &Name,
const std::string &Group,
const ObserveState &Expected) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected, new internal::DeviceUnload());
}
OmptAssertEvent OmptAssertEvent::BufferRequest(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
int DeviceNum,
ompt_buffer_t **Buffer,
size_t *Bytes) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::BufferRequest(DeviceNum, Buffer, Bytes));
}
OmptAssertEvent OmptAssertEvent::BufferComplete(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, int DeviceNum, ompt_buffer_t *Buffer,
size_t Bytes, ompt_buffer_cursor_t Begin, int BufferOwned) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::BufferComplete(DeviceNum, Buffer, Bytes,
Begin, BufferOwned));
}
OmptAssertEvent OmptAssertEvent::BufferRecord(const std::string &Name,
const std::string &Group,
const ObserveState &Expected,
ompt_record_ompt_t *Record) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::BufferRecord(Record));
}
OmptAssertEvent OmptAssertEvent::BufferRecord(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_callbacks_t Type, ompt_target_t Kind,
ompt_scope_endpoint_t Endpoint, int DeviceNum, ompt_id_t TaskId,
ompt_id_t TargetId, const void *CodeptrRA) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
if (Type != ompt_callback_target)
assert(false && "CTOR only suited for type: 'ompt_callback_target'");
ompt_record_target_t Subrecord{Kind, Endpoint, DeviceNum,
TaskId, TargetId, CodeptrRA};
ompt_record_ompt_t *RecordPtr =
(ompt_record_ompt_t *)malloc(sizeof(ompt_record_ompt_t));
memset(RecordPtr, 0, sizeof(ompt_record_ompt_t));
RecordPtr->type = Type;
RecordPtr->time = expectedDefault(ompt_device_time_t);
RecordPtr->thread_id = expectedDefault(ompt_id_t);
RecordPtr->target_id = TargetId;
RecordPtr->record.target = Subrecord;
return OmptAssertEvent(EName, EGroup, Expected,
new internal::BufferRecord(RecordPtr));
}
OmptAssertEvent OmptAssertEvent::BufferRecord(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_callbacks_t Type,
ompt_target_data_op_t OpType, size_t Bytes,
std::pair<ompt_device_time_t, ompt_device_time_t> Timeframe, void *SrcAddr,
void *DstAddr, int SrcDeviceNum, int DstDeviceNum, ompt_id_t TargetId,
ompt_id_t HostOpId, const void *CodeptrRA) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
if (Type != ompt_callback_target_data_op)
assert(false &&
"CTOR only suited for type: 'ompt_callback_target_data_op'");
ompt_record_target_data_op_t Subrecord{
HostOpId, OpType, SrcAddr, SrcDeviceNum, DstAddr,
DstDeviceNum, Bytes, Timeframe.second, CodeptrRA};
ompt_record_ompt_t *RecordPtr =
(ompt_record_ompt_t *)malloc(sizeof(ompt_record_ompt_t));
memset(RecordPtr, 0, sizeof(ompt_record_ompt_t));
RecordPtr->type = Type;
RecordPtr->time = Timeframe.first;
RecordPtr->thread_id = expectedDefault(ompt_id_t);
RecordPtr->target_id = TargetId;
RecordPtr->record.target_data_op = Subrecord;
return OmptAssertEvent(EName, EGroup, Expected,
new internal::BufferRecord(RecordPtr));
}
OmptAssertEvent OmptAssertEvent::BufferRecord(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_callbacks_t Type,
ompt_target_data_op_t OpType, size_t Bytes,
ompt_device_time_t MinimumTimeDelta, void *SrcAddr, void *DstAddr,
int SrcDeviceNum, int DstDeviceNum, ompt_id_t TargetId, ompt_id_t HostOpId,
const void *CodeptrRA) {
return BufferRecord(Name, Group, Expected, Type, OpType, Bytes,
{MinimumTimeDelta, expectedDefault(ompt_device_time_t)},
SrcAddr, DstAddr, SrcDeviceNum, DstDeviceNum, TargetId,
HostOpId, CodeptrRA);
}
OmptAssertEvent OmptAssertEvent::BufferRecord(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_callbacks_t Type,
std::pair<ompt_device_time_t, ompt_device_time_t> Timeframe,
unsigned int RequestedNumTeams, unsigned int GrantedNumTeams,
ompt_id_t TargetId, ompt_id_t HostOpId) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
bool isDefault = (Timeframe.first == expectedDefault(ompt_device_time_t));
isDefault &= (Timeframe.second == expectedDefault(ompt_device_time_t));
isDefault &= (RequestedNumTeams == expectedDefault(unsigned int));
isDefault &= (GrantedNumTeams == expectedDefault(unsigned int));
isDefault &= (TargetId == expectedDefault(ompt_id_t));
isDefault &= (HostOpId == expectedDefault(ompt_id_t));
ompt_record_ompt_t *RecordPtr =
(ompt_record_ompt_t *)malloc(sizeof(ompt_record_ompt_t));
memset(RecordPtr, 0, sizeof(ompt_record_ompt_t));
RecordPtr->type = Type;
// This handles the simplest occurrence of a device tracing record
// We can only check for Type -- since all other properties are set to default
if (isDefault) {
RecordPtr->time = expectedDefault(ompt_device_time_t);
RecordPtr->thread_id = expectedDefault(ompt_id_t);
RecordPtr->target_id = expectedDefault(ompt_id_t);
if (Type == ompt_callback_target) {
ompt_record_target_t Subrecord{expectedDefault(ompt_target_t),
expectedDefault(ompt_scope_endpoint_t),
expectedDefault(int),
expectedDefault(ompt_id_t),
expectedDefault(ompt_id_t),
expectedDefault(void *)};
RecordPtr->record.target = Subrecord;
}
if (Type == ompt_callback_target_data_op) {
ompt_record_target_data_op_t Subrecord{
expectedDefault(ompt_id_t), expectedDefault(ompt_target_data_op_t),
expectedDefault(void *), expectedDefault(int),
expectedDefault(void *), expectedDefault(int),
expectedDefault(size_t), expectedDefault(ompt_device_time_t),
expectedDefault(void *)};
RecordPtr->record.target_data_op = Subrecord;
}
if (Type == ompt_callback_target_submit) {
ompt_record_target_kernel_t Subrecord{
expectedDefault(ompt_id_t), expectedDefault(unsigned int),
expectedDefault(unsigned int), expectedDefault(ompt_device_time_t)};
RecordPtr->record.target_kernel = Subrecord;
}
return OmptAssertEvent(EName, EGroup, Expected,
new internal::BufferRecord(RecordPtr));
}
if (Type != ompt_callback_target_submit)
assert(false && "CTOR only suited for type: 'ompt_callback_target_submit'");
ompt_record_target_kernel_t Subrecord{HostOpId, RequestedNumTeams,
GrantedNumTeams, Timeframe.second};
RecordPtr->time = Timeframe.first;
RecordPtr->thread_id = expectedDefault(ompt_id_t);
RecordPtr->target_id = TargetId;
RecordPtr->record.target_kernel = Subrecord;
return OmptAssertEvent(EName, EGroup, Expected,
new internal::BufferRecord(RecordPtr));
}
OmptAssertEvent OmptAssertEvent::BufferRecord(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_callbacks_t Type,
ompt_device_time_t MinimumTimeDelta, unsigned int RequestedNumTeams,
unsigned int GrantedNumTeams, ompt_id_t TargetId, ompt_id_t HostOpId) {
return BufferRecord(Name, Group, Expected, Type,
{MinimumTimeDelta, expectedDefault(ompt_device_time_t)},
RequestedNumTeams, GrantedNumTeams, TargetId, HostOpId);
}
OmptAssertEvent OmptAssertEvent::BufferRecordDeallocation(
const std::string &Name, const std::string &Group,
const ObserveState &Expected, ompt_buffer_t *Buffer) {
auto EName = getName(Name);
auto EGroup = getGroup(Group);
return OmptAssertEvent(EName, EGroup, Expected,
new internal::BufferRecordDeallocation(Buffer));
}
std::string OmptAssertEvent::getEventName() const { return Name; }
std::string OmptAssertEvent::getEventGroup() const { return Group; }
ObserveState OmptAssertEvent::getEventExpectedState() const {
return ExpectedState;
}
internal::EventTy OmptAssertEvent::getEventType() const {
return TheEvent->Type;
}
internal::InternalEvent *OmptAssertEvent::getEvent() const {
return TheEvent.get();
}
std::string OmptAssertEvent::toString(bool PrefixEventName) const {
std::string S;
if (PrefixEventName)
S.append(getEventName()).append(": ");
S.append((TheEvent == nullptr) ? "OmptAssertEvent" : TheEvent->toString());
return S;
}
bool omptest::operator==(const OmptAssertEvent &A, const OmptAssertEvent &B) {
assert(A.TheEvent.get() != nullptr && "A is valid");
assert(B.TheEvent.get() != nullptr && "B is valid");
return A.TheEvent->Type == B.TheEvent->Type &&
A.TheEvent->equals(B.TheEvent.get());
}

View File

@ -1,484 +0,0 @@
//===- OmptAsserter.cpp - Asserter-related implementations ------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Implements all asserter-related class methods, like: notifications, handling
/// of groups or determination of the testcase state.
///
//===----------------------------------------------------------------------===//
#include "OmptAsserter.h"
#include "Logging.h"
#include <algorithm>
using namespace omptest;
using namespace internal;
// Initialize static members
std::mutex OmptAsserter::StaticMemberAccessMutex;
std::weak_ptr<OmptEventGroupInterface>
OmptAsserter::EventGroupInterfaceInstance;
std::weak_ptr<logging::Logger> OmptAsserter::LoggingInstance;
OmptAsserter::OmptAsserter() {
// Protect static members access
std::lock_guard<std::mutex> Lock(StaticMemberAccessMutex);
// Upgrade OmptEventGroupInterface weak_ptr to shared_ptr
{
EventGroups = EventGroupInterfaceInstance.lock();
if (!EventGroups) {
// Coordinator doesn't exist or was previously destroyed, create a new
// one.
EventGroups = std::make_shared<OmptEventGroupInterface>();
// Store a weak reference to it
EventGroupInterfaceInstance = EventGroups;
}
// EventGroups is now a valid shared_ptr, either to a new or existing
// instance.
}
// Upgrade logging::Logger weak_ptr to shared_ptr
{
Log = LoggingInstance.lock();
if (!Log) {
// Coordinator doesn't exist or was previously destroyed, create a new
// one.
Log = std::make_shared<logging::Logger>();
// Store a weak reference to it
LoggingInstance = Log;
}
// Log is now a valid shared_ptr, either to a new or existing instance.
}
}
void OmptListener::setActive(bool Enabled) { Active = Enabled; }
bool OmptListener::isActive() { return Active; }
bool OmptListener::isSuppressedEventType(EventTy EvTy) {
return SuppressedEvents.find(EvTy) != SuppressedEvents.end();
}
void OmptListener::permitEvent(EventTy EvTy) { SuppressedEvents.erase(EvTy); }
void OmptListener::suppressEvent(EventTy EvTy) {
SuppressedEvents.insert(EvTy);
}
void OmptAsserter::insert(OmptAssertEvent &&AE) {
assert(false && "Base class 'insert' has undefined semantics.");
}
void OmptAsserter::notify(OmptAssertEvent &&AE) {
// Ignore notifications while inactive
if (!isActive() || isSuppressedEventType(AE.getEventType()))
return;
this->notifyImpl(std::move(AE));
}
AssertState OmptAsserter::checkState() { return State; }
bool OmptAsserter::verifyEventGroups(const OmptAssertEvent &ExpectedEvent,
const OmptAssertEvent &ObservedEvent) {
assert(ExpectedEvent.getEventType() == ObservedEvent.getEventType() &&
"Type mismatch: Expected != Observed event type");
assert(EventGroups && "Missing EventGroups interface");
// Ignore all events within "default" group
auto GroupName = ExpectedEvent.getEventGroup();
if (GroupName == "default")
return true;
// Get a pointer to the observed internal event
auto Event = ObservedEvent.getEvent();
switch (Event->Type) {
case EventTy::Target:
if (auto E = static_cast<const internal::Target *>(Event)) {
if (E->Endpoint == ompt_scope_begin) {
// Add new group since we entered a Target Region
EventGroups->addActiveEventGroup(GroupName,
AssertEventGroup{E->TargetId});
} else if (E->Endpoint == ompt_scope_end) {
// Deprecate group since we return from a Target Region
EventGroups->deprecateActiveEventGroup(GroupName);
}
return true;
}
return false;
case EventTy::TargetEmi:
if (auto E = static_cast<const internal::TargetEmi *>(Event)) {
if (E->Endpoint == ompt_scope_begin) {
// Add new group since we entered a Target Region
EventGroups->addActiveEventGroup(
GroupName, AssertEventGroup{E->TargetData->value});
} else if (E->Endpoint == ompt_scope_end) {
// Deprecate group since we return from a Target Region
EventGroups->deprecateActiveEventGroup(GroupName);
}
return true;
}
return false;
case EventTy::TargetDataOp:
if (auto E = static_cast<const internal::TargetDataOp *>(Event))
return EventGroups->checkActiveEventGroups(GroupName,
AssertEventGroup{E->TargetId});
return false;
case EventTy::TargetDataOpEmi:
if (auto E = static_cast<const internal::TargetDataOpEmi *>(Event))
return EventGroups->checkActiveEventGroups(
GroupName, AssertEventGroup{E->TargetData->value});
return false;
case EventTy::TargetSubmit:
if (auto E = static_cast<const internal::TargetSubmit *>(Event))
return EventGroups->checkActiveEventGroups(GroupName,
AssertEventGroup{E->TargetId});
return false;
case EventTy::TargetSubmitEmi:
if (auto E = static_cast<const internal::TargetSubmitEmi *>(Event))
return EventGroups->checkActiveEventGroups(
GroupName, AssertEventGroup{E->TargetData->value});
return false;
case EventTy::BufferRecord:
// BufferRecords are delivered asynchronously: also check deprecated groups.
if (auto E = static_cast<const internal::BufferRecord *>(Event))
return (EventGroups->checkActiveEventGroups(
GroupName, AssertEventGroup{E->Record.target_id}) ||
EventGroups->checkDeprecatedEventGroups(
GroupName, AssertEventGroup{E->Record.target_id}));
return false;
// Some event types do not need any handling
case EventTy::ThreadBegin:
case EventTy::ThreadEnd:
case EventTy::ParallelBegin:
case EventTy::ParallelEnd:
case EventTy::Work:
case EventTy::Dispatch:
case EventTy::TaskCreate:
case EventTy::Dependences:
case EventTy::TaskDependence:
case EventTy::TaskSchedule:
case EventTy::ImplicitTask:
case EventTy::Masked:
case EventTy::SyncRegion:
case EventTy::MutexAcquire:
case EventTy::Mutex:
case EventTy::NestLock:
case EventTy::Flush:
case EventTy::Cancel:
case EventTy::DeviceInitialize:
case EventTy::DeviceFinalize:
case EventTy::DeviceLoad:
case EventTy::DeviceUnload:
case EventTy::BufferRequest:
case EventTy::BufferComplete:
case EventTy::BufferRecordDeallocation:
return true;
// Some event types must not be encountered
case EventTy::None:
case EventTy::AssertionSyncPoint:
case EventTy::AssertionSuspend:
default:
Log->log("Observed invalid event type: " + Event->toString(),
logging::Level::Critical);
__builtin_unreachable();
}
return true;
}
void OmptAsserter::setOperationMode(AssertMode Mode) { OperationMode = Mode; }
void OmptSequencedAsserter::insert(OmptAssertEvent &&AE) {
std::lock_guard<std::mutex> Lock(AssertMutex);
Events.emplace_back(std::move(AE));
}
void OmptSequencedAsserter::notifyImpl(OmptAssertEvent &&AE) {
std::lock_guard<std::mutex> Lock(AssertMutex);
// Ignore notifications while inactive, or for suppressed events
if (Events.empty() || !isActive() || isSuppressedEventType(AE.getEventType()))
return;
++NumNotifications;
// Note: Order of these checks has semantic meaning.
// (1) Synchronization points should fail if there are remaining events,
// otherwise pass. (2) Regular notification while no further events are
// expected: fail. (3) Assertion suspension relies on a next expected event
// being available. (4) All other cases are considered 'regular' and match the
// next expected against the observed event. (5+6) Depending on the state /
// mode we signal failure if no other check has done already, or signaled pass
// by early-exit.
if (consumeSyncPoint(AE) || // Handle observed SyncPoint event
checkExcessNotify(AE) || // Check for remaining expected
consumeSuspend() || // Handle requested suspend
consumeRegularEvent(AE) || // Handle regular event
AssertionSuspended || // Ignore fail, if suspended
OperationMode == AssertMode::Relaxed) // Ignore fail, if Relaxed op-mode
return;
Log->logEventMismatch("[OmptSequencedAsserter] The events are not equal",
Events[NextEvent], AE);
State = AssertState::Fail;
}
bool OmptSequencedAsserter::consumeSyncPoint(
const omptest::OmptAssertEvent &AE) {
if (AE.getEventType() == EventTy::AssertionSyncPoint) {
auto NumRemainingEvents = getRemainingEventCount();
// Upon encountering a SyncPoint, all events should have been processed
if (NumRemainingEvents == 0)
return true;
Log->logEventMismatch(
"[OmptSequencedAsserter] Encountered SyncPoint while still awaiting " +
std::to_string(NumRemainingEvents) + " events. Asserted " +
std::to_string(NumSuccessfulAsserts) + "/" +
std::to_string(Events.size()) + " events successfully.",
AE);
State = AssertState::Fail;
return true;
}
// Nothing to process: continue.
return false;
}
bool OmptSequencedAsserter::checkExcessNotify(
const omptest::OmptAssertEvent &AE) {
if (NextEvent >= Events.size()) {
// If we are not expecting any more events and passively asserting: return
if (AssertionSuspended)
return true;
Log->logEventMismatch(
"[OmptSequencedAsserter] Too many events to check (" +
std::to_string(NumNotifications) + "). Asserted " +
std::to_string(NumSuccessfulAsserts) + "/" +
std::to_string(Events.size()) + " events successfully.",
AE);
State = AssertState::Fail;
return true;
}
// Remaining expected events present: continue.
return false;
}
bool OmptSequencedAsserter::consumeSuspend() {
// On AssertionSuspend -- enter 'passive' assertion.
// Since we may encounter multiple, successive AssertionSuspend events, loop
// until we hit the next non-AssertionSuspend event.
while (Events[NextEvent].getEventType() == EventTy::AssertionSuspend) {
AssertionSuspended = true;
// We just hit the very last event: indicate early exit.
if (++NextEvent >= Events.size())
return true;
}
// Continue with remaining notification logic.
return false;
}
bool OmptSequencedAsserter::consumeRegularEvent(
const omptest::OmptAssertEvent &AE) {
// If we are actively asserting, increment the event counter.
// Otherwise: If passively asserting, we will keep waiting for a match.
auto &E = Events[NextEvent];
if (E == AE && verifyEventGroups(E, AE)) {
if (E.getEventExpectedState() == ObserveState::Always) {
++NumSuccessfulAsserts;
} else if (E.getEventExpectedState() == ObserveState::Never) {
Log->logEventMismatch(
"[OmptSequencedAsserter] Encountered forbidden event", E, AE);
State = AssertState::Fail;
}
// Return to active assertion
if (AssertionSuspended)
AssertionSuspended = false;
// Match found, increment index and indicate early exit (success).
++NextEvent;
return true;
}
// Continue with remaining notification logic.
return false;
}
size_t OmptSequencedAsserter::getRemainingEventCount() {
return std::count_if(Events.begin(), Events.end(),
[](const omptest::OmptAssertEvent &E) {
return E.getEventExpectedState() ==
ObserveState::Always;
}) -
NumSuccessfulAsserts;
}
AssertState OmptSequencedAsserter::checkState() {
// This is called after the testcase executed.
// Once reached the number of successful notifications should be equal to the
// number of expected events. However, there may still be excluded as well as
// special asserter events remaining in the sequence.
for (size_t i = NextEvent; i < Events.size(); ++i) {
auto &E = Events[i];
if (E.getEventExpectedState() == ObserveState::Always) {
State = AssertState::Fail;
Log->logEventMismatch("[OmptSequencedAsserter] Expected event was not "
"encountered (Remaining events: " +
std::to_string(getRemainingEventCount()) + ")",
E);
break;
}
}
return State;
}
void OmptEventAsserter::insert(OmptAssertEvent &&AE) {
std::lock_guard<std::mutex> Lock(AssertMutex);
Events.emplace_back(std::move(AE));
}
void OmptEventAsserter::notifyImpl(OmptAssertEvent &&AE) {
std::lock_guard<std::mutex> Lock(AssertMutex);
if (Events.empty() || !isActive() || isSuppressedEventType(AE.getEventType()))
return;
if (NumEvents == 0)
NumEvents = Events.size();
++NumNotifications;
if (AE.getEventType() == EventTy::AssertionSyncPoint) {
auto NumRemainingEvents = getRemainingEventCount();
// Upon encountering a SyncPoint, all events should have been processed
if (NumRemainingEvents == 0)
return;
Log->logEventMismatch(
"[OmptEventAsserter] Encountered SyncPoint while still awaiting " +
std::to_string(NumRemainingEvents) + " events. Asserted " +
std::to_string(NumSuccessfulAsserts) + " events successfully.",
AE);
State = AssertState::Fail;
return;
}
for (size_t i = 0; i < Events.size(); ++i) {
auto &E = Events[i];
if (E == AE && verifyEventGroups(E, AE)) {
if (E.getEventExpectedState() == ObserveState::Always) {
Events.erase(Events.begin() + i);
++NumSuccessfulAsserts;
} else if (E.getEventExpectedState() == ObserveState::Never) {
Log->logEventMismatch("[OmptEventAsserter] Encountered forbidden event",
E, AE);
State = AssertState::Fail;
}
return;
}
}
if (OperationMode == AssertMode::Strict) {
Log->logEventMismatch("[OmptEventAsserter] Too many events to check (" +
std::to_string(NumNotifications) +
"). Asserted " +
std::to_string(NumSuccessfulAsserts) +
" events successfully. (Remaining events: " +
std::to_string(getRemainingEventCount()) + ")",
AE);
State = AssertState::Fail;
return;
}
}
size_t OmptEventAsserter::getRemainingEventCount() {
return std::count_if(
Events.begin(), Events.end(), [](const omptest::OmptAssertEvent &E) {
return E.getEventExpectedState() == ObserveState::Always;
});
}
AssertState OmptEventAsserter::checkState() {
// This is called after the testcase executed.
// Once reached no more expected events should be in the queue
for (const auto &E : Events) {
// Check if any of the remaining events were expected to be observed
if (E.getEventExpectedState() == ObserveState::Always) {
State = AssertState::Fail;
Log->logEventMismatch("[OmptEventAsserter] Expected event was not "
"encountered (Remaining events: " +
std::to_string(getRemainingEventCount()) + ")",
E);
break;
}
}
return State;
}
void OmptEventReporter::notify(OmptAssertEvent &&AE) {
if (!isActive() || isSuppressedEventType(AE.getEventType()))
return;
// Prepare notification, containing the newline to avoid stream interleaving.
auto Notification{AE.toString()};
Notification.push_back('\n');
OutStream << Notification;
}
bool OmptEventGroupInterface::addActiveEventGroup(
const std::string &GroupName, omptest::AssertEventGroup Group) {
std::lock_guard<std::mutex> Lock(GroupMutex);
auto EventGroup = ActiveEventGroups.find(GroupName);
if (EventGroup != ActiveEventGroups.end() &&
EventGroup->second.TargetRegion == Group.TargetRegion)
return false;
ActiveEventGroups.emplace(GroupName, Group);
return true;
}
bool OmptEventGroupInterface::deprecateActiveEventGroup(
const std::string &GroupName) {
std::lock_guard<std::mutex> Lock(GroupMutex);
auto EventGroup = ActiveEventGroups.find(GroupName);
auto DeprecatedEventGroup = DeprecatedEventGroups.find(GroupName);
if (EventGroup == ActiveEventGroups.end() &&
DeprecatedEventGroup != DeprecatedEventGroups.end())
return false;
DeprecatedEventGroups.emplace(GroupName, EventGroup->second);
ActiveEventGroups.erase(GroupName);
return true;
}
bool OmptEventGroupInterface::checkActiveEventGroups(
const std::string &GroupName, omptest::AssertEventGroup Group) {
std::lock_guard<std::mutex> Lock(GroupMutex);
auto EventGroup = ActiveEventGroups.find(GroupName);
return (EventGroup != ActiveEventGroups.end() &&
EventGroup->second.TargetRegion == Group.TargetRegion);
}
bool OmptEventGroupInterface::checkDeprecatedEventGroups(
const std::string &GroupName, omptest::AssertEventGroup Group) {
std::lock_guard<std::mutex> Lock(GroupMutex);
auto EventGroup = DeprecatedEventGroups.find(GroupName);
return (EventGroup != DeprecatedEventGroups.end() &&
EventGroup->second.TargetRegion == Group.TargetRegion);
}

View File

@ -1,445 +0,0 @@
//===- OmptCallbackHandler.cpp - OMPT Callback handling impl. ---*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains the OMPT callback handling implementations.
///
//===----------------------------------------------------------------------===//
#include "OmptCallbackHandler.h"
using namespace omptest;
OmptCallbackHandler *Handler = nullptr;
OmptCallbackHandler &OmptCallbackHandler::get() {
if (Handler == nullptr)
Handler = new OmptCallbackHandler();
return *Handler;
}
void OmptCallbackHandler::subscribe(OmptListener *Listener) {
Subscribers.push_back(Listener);
}
void OmptCallbackHandler::clearSubscribers() {
replay();
Subscribers.clear();
}
void OmptCallbackHandler::replay() {
if (!RecordAndReplay)
return;
for (auto &E : RecordedEvents)
for (const auto &S : Subscribers)
S->notify(std::move(E));
}
void OmptCallbackHandler::handleThreadBegin(ompt_thread_t ThreadType,
ompt_data_t *ThreadData) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::ThreadBegin(
"Thread Begin", "", ObserveState::Generated, ThreadType));
return;
}
// Initial thread event likely to preceed assertion registration, so skip
if (ThreadType == ompt_thread_initial)
return;
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::ThreadBegin(
"Thread Begin", "", ObserveState::Generated, ThreadType));
}
void OmptCallbackHandler::handleThreadEnd(ompt_data_t *ThreadData) {
if (RecordAndReplay) {
recordEvent(
OmptAssertEvent::ThreadEnd("Thread End", "", ObserveState::Generated));
return;
}
for (const auto &S : Subscribers)
S->notify(
OmptAssertEvent::ThreadEnd("Thread End", "", ObserveState::Generated));
}
void OmptCallbackHandler::handleTaskCreate(
ompt_data_t *EncounteringTaskData,
const ompt_frame_t *EncounteringTaskFrame, ompt_data_t *NewTaskData,
int Flags, int HasDependences, const void *CodeptrRA) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::TaskCreate(
"Task Create", "", ObserveState::Generated, EncounteringTaskData,
EncounteringTaskFrame, NewTaskData, Flags, HasDependences, CodeptrRA));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::TaskCreate(
"Task Create", "", ObserveState::Generated, EncounteringTaskData,
EncounteringTaskFrame, NewTaskData, Flags, HasDependences, CodeptrRA));
}
void OmptCallbackHandler::handleTaskSchedule(ompt_data_t *PriorTaskData,
ompt_task_status_t PriorTaskStatus,
ompt_data_t *NextTaskData) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::TaskSchedule("Task Schedule", "",
ObserveState::Generated));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::TaskSchedule("Task Schedule", "",
ObserveState::Generated));
}
void OmptCallbackHandler::handleImplicitTask(ompt_scope_endpoint_t Endpoint,
ompt_data_t *ParallelData,
ompt_data_t *TaskData,
unsigned int ActualParallelism,
unsigned int Index, int Flags) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::ImplicitTask(
"Implicit Task", "", ObserveState::Generated, Endpoint, ParallelData,
TaskData, ActualParallelism, Index, Flags));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::ImplicitTask(
"Implicit Task", "", ObserveState::Generated, Endpoint, ParallelData,
TaskData, ActualParallelism, Index, Flags));
}
void OmptCallbackHandler::handleParallelBegin(
ompt_data_t *EncounteringTaskData,
const ompt_frame_t *EncounteringTaskFrame, ompt_data_t *ParallelData,
unsigned int RequestedParallelism, int Flags, const void *CodeptrRA) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::ParallelBegin(
"Parallel Begin", "", ObserveState::Generated, RequestedParallelism));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::ParallelBegin(
"Parallel Begin", "", ObserveState::Generated, RequestedParallelism));
}
void OmptCallbackHandler::handleParallelEnd(ompt_data_t *ParallelData,
ompt_data_t *EncounteringTaskData,
int Flags, const void *CodeptrRA) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::ParallelEnd("Parallel End", "",
ObserveState::Generated));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::ParallelEnd("Parallel End", "",
ObserveState::Generated));
}
void OmptCallbackHandler::handleDeviceInitialize(
int DeviceNum, const char *Type, ompt_device_t *Device,
ompt_function_lookup_t LookupFn, const char *DocumentationStr) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::DeviceInitialize(
"Device Inititalize", "", ObserveState::Generated, DeviceNum, Type,
Device, LookupFn, DocumentationStr));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::DeviceInitialize(
"Device Inititalize", "", ObserveState::Generated, DeviceNum, Type,
Device, LookupFn, DocumentationStr));
}
void OmptCallbackHandler::handleDeviceFinalize(int DeviceNum) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::DeviceFinalize(
"Device Finalize", "", ObserveState::Generated, DeviceNum));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::DeviceFinalize(
"Device Finalize", "", ObserveState::Generated, DeviceNum));
}
void OmptCallbackHandler::handleTarget(ompt_target_t Kind,
ompt_scope_endpoint_t Endpoint,
int DeviceNum, ompt_data_t *TaskData,
ompt_id_t TargetId,
const void *CodeptrRA) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::Target("Target", "", ObserveState::Generated,
Kind, Endpoint, DeviceNum, TaskData,
TargetId, CodeptrRA));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::Target("Target", "", ObserveState::Generated,
Kind, Endpoint, DeviceNum, TaskData,
TargetId, CodeptrRA));
}
void OmptCallbackHandler::handleTargetEmi(ompt_target_t Kind,
ompt_scope_endpoint_t Endpoint,
int DeviceNum, ompt_data_t *TaskData,
ompt_data_t *TargetTaskData,
ompt_data_t *TargetData,
const void *CodeptrRA) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::TargetEmi(
"Target EMI", "", ObserveState::Generated, Kind, Endpoint, DeviceNum,
TaskData, TargetTaskData, TargetData, CodeptrRA));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::TargetEmi(
"Target EMI", "", ObserveState::Generated, Kind, Endpoint, DeviceNum,
TaskData, TargetTaskData, TargetData, CodeptrRA));
}
void OmptCallbackHandler::handleTargetSubmit(ompt_id_t TargetId,
ompt_id_t HostOpId,
unsigned int RequestedNumTeams) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::TargetSubmit("Target Submit", "",
ObserveState::Generated, TargetId,
HostOpId, RequestedNumTeams));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::TargetSubmit("Target Submit", "",
ObserveState::Generated, TargetId,
HostOpId, RequestedNumTeams));
}
void OmptCallbackHandler::handleTargetSubmitEmi(
ompt_scope_endpoint_t Endpoint, ompt_data_t *TargetData,
ompt_id_t *HostOpId, unsigned int RequestedNumTeams) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::TargetSubmitEmi(
"Target Submit EMI", "", ObserveState::Generated, Endpoint, TargetData,
HostOpId, RequestedNumTeams));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::TargetSubmitEmi(
"Target Submit EMI", "", ObserveState::Generated, Endpoint, TargetData,
HostOpId, RequestedNumTeams));
}
void OmptCallbackHandler::handleTargetDataOp(
ompt_id_t TargetId, ompt_id_t HostOpId, ompt_target_data_op_t OpType,
void *SrcAddr, int SrcDeviceNum, void *DstAddr, int DstDeviceNum,
size_t Bytes, const void *CodeptrRA) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::TargetDataOp(
"Target Data Op", "", ObserveState::Generated, TargetId, HostOpId,
OpType, SrcAddr, SrcDeviceNum, DstAddr, DstDeviceNum, Bytes,
CodeptrRA));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::TargetDataOp(
"Target Data Op", "", ObserveState::Generated, TargetId, HostOpId,
OpType, SrcAddr, SrcDeviceNum, DstAddr, DstDeviceNum, Bytes,
CodeptrRA));
}
void OmptCallbackHandler::handleTargetDataOpEmi(
ompt_scope_endpoint_t Endpoint, ompt_data_t *TargetTaskData,
ompt_data_t *TargetData, ompt_id_t *HostOpId, ompt_target_data_op_t OpType,
void *SrcAddr, int SrcDeviceNum, void *DstAddr, int DstDeviceNum,
size_t Bytes, const void *CodeptrRA) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::TargetDataOpEmi(
"Target Data Op EMI", "", ObserveState::Generated, Endpoint,
TargetTaskData, TargetData, HostOpId, OpType, SrcAddr, SrcDeviceNum,
DstAddr, DstDeviceNum, Bytes, CodeptrRA));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::TargetDataOpEmi(
"Target Data Op EMI", "", ObserveState::Generated, Endpoint,
TargetTaskData, TargetData, HostOpId, OpType, SrcAddr, SrcDeviceNum,
DstAddr, DstDeviceNum, Bytes, CodeptrRA));
}
void OmptCallbackHandler::handleDeviceLoad(int DeviceNum, const char *Filename,
int64_t OffsetInFile,
void *VmaInFile, size_t Bytes,
void *HostAddr, void *DeviceAddr,
uint64_t ModuleId) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::DeviceLoad(
"Device Load", "", ObserveState::Generated, DeviceNum, Filename,
OffsetInFile, VmaInFile, Bytes, HostAddr, DeviceAddr, ModuleId));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::DeviceLoad(
"Device Load", "", ObserveState::Generated, DeviceNum, Filename,
OffsetInFile, VmaInFile, Bytes, HostAddr, DeviceAddr, ModuleId));
}
void OmptCallbackHandler::handleDeviceUnload(int DeviceNum, uint64_t ModuleId) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::DeviceUnload("Device Unload", "",
ObserveState::Generated));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::DeviceUnload("Device Unload", "",
ObserveState::Generated));
}
void OmptCallbackHandler::handleBufferRequest(int DeviceNum,
ompt_buffer_t **Buffer,
size_t *Bytes) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::BufferRequest("Buffer Request", "",
ObserveState::Generated,
DeviceNum, Buffer, Bytes));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::BufferRequest("Buffer Request", "",
ObserveState::Generated, DeviceNum,
Buffer, Bytes));
}
void OmptCallbackHandler::handleBufferComplete(int DeviceNum,
ompt_buffer_t *Buffer,
size_t Bytes,
ompt_buffer_cursor_t Begin,
int BufferOwned) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::BufferComplete(
"Buffer Complete", "", ObserveState::Generated, DeviceNum, Buffer,
Bytes, Begin, BufferOwned));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::BufferComplete(
"Buffer Complete", "", ObserveState::Generated, DeviceNum, Buffer,
Bytes, Begin, BufferOwned));
}
void OmptCallbackHandler::handleBufferRecord(ompt_record_ompt_t *Record) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::BufferRecord("Buffer Record", "",
ObserveState::Generated, Record));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::BufferRecord("Buffer Record", "",
ObserveState::Generated, Record));
}
void OmptCallbackHandler::handleBufferRecordDeallocation(
ompt_buffer_t *Buffer) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::BufferRecordDeallocation(
"Buffer Deallocation", "", ObserveState::Generated, Buffer));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::BufferRecordDeallocation(
"Buffer Deallocation", "", ObserveState::Generated, Buffer));
}
void OmptCallbackHandler::handleWork(ompt_work_t WorkType,
ompt_scope_endpoint_t Endpoint,
ompt_data_t *ParallelData,
ompt_data_t *TaskData, uint64_t Count,
const void *CodeptrRA) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::Work("Work", "", ObserveState::Generated,
WorkType, Endpoint, ParallelData,
TaskData, Count, CodeptrRA));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::Work("Work", "", ObserveState::Generated,
WorkType, Endpoint, ParallelData, TaskData,
Count, CodeptrRA));
}
void OmptCallbackHandler::handleSyncRegion(ompt_sync_region_t Kind,
ompt_scope_endpoint_t Endpoint,
ompt_data_t *ParallelData,
ompt_data_t *TaskData,
const void *CodeptrRA) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::SyncRegion(
"SyncRegion", "", ObserveState::Generated, Kind, Endpoint, ParallelData,
TaskData, CodeptrRA));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::SyncRegion(
"SyncRegion", "", ObserveState::Generated, Kind, Endpoint, ParallelData,
TaskData, CodeptrRA));
}
void OmptCallbackHandler::handleDispatch(ompt_data_t *ParallelData,
ompt_data_t *TaskData,
ompt_dispatch_t Kind,
ompt_data_t Instance) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::Dispatch("Dispatch", "",
ObserveState::Generated, ParallelData,
TaskData, Kind, Instance));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::Dispatch("Dispatch", "", ObserveState::Generated,
ParallelData, TaskData, Kind,
Instance));
}
void OmptCallbackHandler::handleAssertionSyncPoint(
const std::string &SyncPointName) {
if (RecordAndReplay) {
recordEvent(OmptAssertEvent::AssertionSyncPoint(
"Assertion SyncPoint", "", ObserveState::Generated, SyncPointName));
return;
}
for (const auto &S : Subscribers)
S->notify(OmptAssertEvent::AssertionSyncPoint(
"Assertion SyncPoint", "", ObserveState::Generated, SyncPointName));
}
void OmptCallbackHandler::recordEvent(OmptAssertEvent &&Event) {
RecordedEvents.emplace_back(std::forward<OmptAssertEvent>(Event));
}

View File

@ -1,504 +0,0 @@
//===- OmptTester.cpp - ompTest OMPT tool implementation --------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file represents the core implementation file for the ompTest library.
/// It provides the actual OMPT tool implementation: registers callbacks, etc.
/// OMPT callbacks are passed to their corresponding handler, which in turn
/// notifies all registered asserters.
///
//===----------------------------------------------------------------------===//
#include "OmptTester.h"
#include <atomic>
#include <cassert>
#include <cstdlib>
#include <cstring>
using namespace omptest;
// Callback handler, which receives and relays OMPT callbacks
extern OmptCallbackHandler *Handler;
// EventListener, which actually prints the OMPT events
static OmptEventReporter *EventReporter;
// From openmp/runtime/test/ompt/callback.h
#define register_ompt_callback_t(name, type) \
do { \
type f_##name = &on_##name; \
if (ompt_set_callback(name, (ompt_callback_t)f_##name) == ompt_set_never) \
printf("0: Could not register callback '" #name "'\n"); \
} while (0)
#define register_ompt_callback(name) register_ompt_callback_t(name, name##_t)
#define OMPT_BUFFER_REQUEST_SIZE 256
#ifdef OPENMP_LIBOMPTEST_BUILD_STANDALONE
std::map<std::string, TestSuite> TestRegistrar::Tests;
#endif
static std::atomic<ompt_id_t> NextOpId{0x8000000000000001};
static bool UseEMICallbacks = false;
static bool UseTracing = false;
static bool RunAsTestSuite = false;
static bool ColoredLog = false;
// OMPT entry point handles
static ompt_set_trace_ompt_t ompt_set_trace_ompt = 0;
static ompt_start_trace_t ompt_start_trace = 0;
static ompt_flush_trace_t ompt_flush_trace = 0;
static ompt_stop_trace_t ompt_stop_trace = 0;
static ompt_get_record_ompt_t ompt_get_record_ompt = 0;
static ompt_advance_buffer_cursor_t ompt_advance_buffer_cursor = 0;
static ompt_get_record_type_t ompt_get_record_type_fn = 0;
// OMPT device side tracing: Currently traced devices
typedef std::unordered_set<ompt_device_t *> OmptDeviceSetTy;
typedef std::unique_ptr<OmptDeviceSetTy> OmptDeviceSetPtrTy;
static OmptDeviceSetPtrTy TracedDevices;
// OMPT callbacks
// Trace record callbacks
static void on_ompt_callback_buffer_request(int device_num,
ompt_buffer_t **buffer,
size_t *bytes) {
*bytes = OMPT_BUFFER_REQUEST_SIZE;
*buffer = malloc(*bytes);
OmptCallbackHandler::get().handleBufferRequest(device_num, buffer, bytes);
}
// Note: This callback must handle a null begin cursor. Currently,
// ompt_get_record_ompt, print_record_ompt, and
// ompt_advance_buffer_cursor handle a null cursor.
static void on_ompt_callback_buffer_complete(
int device_num, ompt_buffer_t *buffer,
size_t bytes, /* bytes returned in this callback */
ompt_buffer_cursor_t begin, int buffer_owned) {
OmptCallbackHandler::get().handleBufferComplete(device_num, buffer, bytes,
begin, buffer_owned);
int Status = 1;
ompt_buffer_cursor_t CurrentPos = begin;
while (Status) {
ompt_record_ompt_t *Record = ompt_get_record_ompt(buffer, CurrentPos);
if (ompt_get_record_type_fn(buffer, CurrentPos) != ompt_record_ompt) {
printf("Warning: received non-ompt type buffer object\n");
}
// TODO: Sometimes it may happen that the retrieved record may be null?!
// Only handle non-null records
if (Record != nullptr)
OmptCallbackHandler::get().handleBufferRecord(Record);
Status = ompt_advance_buffer_cursor(/*device=*/NULL, buffer, bytes,
CurrentPos, &CurrentPos);
}
if (buffer_owned) {
OmptCallbackHandler::get().handleBufferRecordDeallocation(buffer);
free(buffer);
}
}
static ompt_set_result_t set_trace_ompt(ompt_device_t *Device) {
if (!ompt_set_trace_ompt)
return ompt_set_error;
if (UseEMICallbacks) {
ompt_set_trace_ompt(Device, /*enable=*/1,
/*etype=*/ompt_callback_target_emi);
ompt_set_trace_ompt(Device, /*enable=*/1,
/*etype=*/ompt_callback_target_data_op_emi);
ompt_set_trace_ompt(Device, /*enable=*/1,
/*etype=*/ompt_callback_target_submit_emi);
} else {
ompt_set_trace_ompt(Device, /*enable=*/1, /*etype=*/ompt_callback_target);
ompt_set_trace_ompt(Device, /*enable=*/1,
/*etype=*/ompt_callback_target_data_op);
ompt_set_trace_ompt(Device, /*enable=*/1,
/*etype=*/ompt_callback_target_submit);
}
return ompt_set_always;
}
/////// HOST-RELATED //////
static void on_ompt_callback_thread_begin(ompt_thread_t thread_type,
ompt_data_t *thread_data) {
OmptCallbackHandler::get().handleThreadBegin(thread_type, thread_data);
}
static void on_ompt_callback_thread_end(ompt_data_t *thread_data) {
OmptCallbackHandler::get().handleThreadEnd(thread_data);
}
static void on_ompt_callback_parallel_begin(
ompt_data_t *encountering_task_data,
const ompt_frame_t *encountering_task_frame, ompt_data_t *parallel_data,
unsigned int requested_parallelism, int flags, const void *codeptr_ra) {
OmptCallbackHandler::get().handleParallelBegin(
encountering_task_data, encountering_task_frame, parallel_data,
requested_parallelism, flags, codeptr_ra);
}
static void on_ompt_callback_parallel_end(ompt_data_t *parallel_data,
ompt_data_t *encountering_task_data,
int flags, const void *codeptr_ra) {
OmptCallbackHandler::get().handleParallelEnd(
parallel_data, encountering_task_data, flags, codeptr_ra);
}
static void
on_ompt_callback_task_create(ompt_data_t *encountering_task_data,
const ompt_frame_t *encountering_task_frame,
ompt_data_t *new_task_data, int flags,
int has_dependences, const void *codeptr_ra) {
OmptCallbackHandler::get().handleTaskCreate(
encountering_task_data, encountering_task_frame, new_task_data, flags,
has_dependences, codeptr_ra);
}
static void on_ompt_callback_task_schedule(ompt_data_t *prior_task_data,
ompt_task_status_t prior_task_status,
ompt_data_t *next_task_data) {
OmptCallbackHandler::get().handleTaskSchedule(
prior_task_data, prior_task_status, next_task_data);
}
static void on_ompt_callback_implicit_task(ompt_scope_endpoint_t endpoint,
ompt_data_t *parallel_data,
ompt_data_t *task_data,
unsigned int actual_parallelism,
unsigned int index, int flags) {
OmptCallbackHandler::get().handleImplicitTask(
endpoint, parallel_data, task_data, actual_parallelism, index, flags);
}
// Callbacks as of Table 19.4, which are not considered required for a minimal
// conforming OMPT implementation.
static void on_ompt_callback_work(ompt_work_t work_type,
ompt_scope_endpoint_t endpoint,
ompt_data_t *parallel_data,
ompt_data_t *task_data, uint64_t count,
const void *codeptr_ra) {
OmptCallbackHandler::get().handleWork(work_type, endpoint, parallel_data,
task_data, count, codeptr_ra);
}
static void on_ompt_callback_dispatch(ompt_data_t *parallel_data,
ompt_data_t *task_data,
ompt_dispatch_t kind,
ompt_data_t instance) {
OmptCallbackHandler::get().handleDispatch(parallel_data, task_data, kind,
instance);
}
static void on_ompt_callback_sync_region(ompt_sync_region_t kind,
ompt_scope_endpoint_t endpoint,
ompt_data_t *parallel_data,
ompt_data_t *task_data,
const void *codeptr_ra) {
OmptCallbackHandler::get().handleSyncRegion(kind, endpoint, parallel_data,
task_data, codeptr_ra);
}
/////// DEVICE-RELATED //////
// Synchronous callbacks
static void on_ompt_callback_device_initialize(int device_num, const char *type,
ompt_device_t *device,
ompt_function_lookup_t lookup,
const char *documentation) {
OmptCallbackHandler::get().handleDeviceInitialize(device_num, type, device,
lookup, documentation);
if (!UseTracing)
return;
if (!lookup) {
printf("Trace collection disabled on device %d\n", device_num);
return;
}
ompt_set_trace_ompt = (ompt_set_trace_ompt_t)lookup("ompt_set_trace_ompt");
ompt_start_trace = (ompt_start_trace_t)lookup("ompt_start_trace");
ompt_flush_trace = (ompt_flush_trace_t)lookup("ompt_flush_trace");
ompt_stop_trace = (ompt_stop_trace_t)lookup("ompt_stop_trace");
ompt_get_record_ompt = (ompt_get_record_ompt_t)lookup("ompt_get_record_ompt");
ompt_advance_buffer_cursor =
(ompt_advance_buffer_cursor_t)lookup("ompt_advance_buffer_cursor");
ompt_get_record_type_fn =
(ompt_get_record_type_t)lookup("ompt_get_record_type");
if (!ompt_get_record_type_fn) {
printf("Warning: No function ompt_get_record_type found in device "
"callbacks\n");
}
static bool IsDeviceMapInitialized = false;
if (!IsDeviceMapInitialized) {
TracedDevices = std::make_unique<OmptDeviceSetTy>();
IsDeviceMapInitialized = true;
}
set_trace_ompt(device);
// In many scenarios, this is a good place to start the
// trace. If start_trace is called from the main program before this
// callback is dispatched, the start_trace handle will be null. This
// is because this device_init callback is invoked during the first
// target construct implementation.
start_trace(device);
}
static void on_ompt_callback_device_finalize(int device_num) {
OmptCallbackHandler::get().handleDeviceFinalize(device_num);
}
static void on_ompt_callback_device_load(int device_num, const char *filename,
int64_t offset_in_file,
void *vma_in_file, size_t bytes,
void *host_addr, void *device_addr,
uint64_t module_id) {
OmptCallbackHandler::get().handleDeviceLoad(
device_num, filename, offset_in_file, vma_in_file, bytes, host_addr,
device_addr, module_id);
}
static void on_ompt_callback_device_unload(int device_num, uint64_t module_id) {
OmptCallbackHandler::get().handleDeviceUnload(device_num, module_id);
}
static void on_ompt_callback_target_data_op(
ompt_id_t target_id, ompt_id_t host_op_id, ompt_target_data_op_t optype,
void *src_addr, int src_device_num, void *dest_addr, int dest_device_num,
size_t bytes, const void *codeptr_ra) {
OmptCallbackHandler::get().handleTargetDataOp(
target_id, host_op_id, optype, src_addr, src_device_num, dest_addr,
dest_device_num, bytes, codeptr_ra);
}
static void on_ompt_callback_target(ompt_target_t kind,
ompt_scope_endpoint_t endpoint,
int device_num, ompt_data_t *task_data,
ompt_id_t target_id,
const void *codeptr_ra) {
OmptCallbackHandler::get().handleTarget(kind, endpoint, device_num, task_data,
target_id, codeptr_ra);
}
static void on_ompt_callback_target_submit(ompt_id_t target_id,
ompt_id_t host_op_id,
unsigned int requested_num_teams) {
OmptCallbackHandler::get().handleTargetSubmit(target_id, host_op_id,
requested_num_teams);
}
static void on_ompt_callback_target_data_op_emi(
ompt_scope_endpoint_t endpoint, ompt_data_t *target_task_data,
ompt_data_t *target_data, ompt_id_t *host_op_id,
ompt_target_data_op_t optype, void *src_addr, int src_device_num,
void *dest_addr, int dest_device_num, size_t bytes,
const void *codeptr_ra) {
assert(codeptr_ra != 0 && "Unexpected null codeptr");
// Both src and dest must not be null
// However, for omp_target_alloc only the END call holds a value for one of
// the two entries
if (optype != ompt_target_data_alloc)
assert((src_addr != 0 || dest_addr != 0) && "Both src and dest addr null");
if (endpoint == ompt_scope_begin)
*host_op_id = NextOpId.fetch_add(1, std::memory_order_relaxed);
OmptCallbackHandler::get().handleTargetDataOpEmi(
endpoint, target_task_data, target_data, host_op_id, optype, src_addr,
src_device_num, dest_addr, dest_device_num, bytes, codeptr_ra);
}
static void on_ompt_callback_target_emi(ompt_target_t kind,
ompt_scope_endpoint_t endpoint,
int device_num, ompt_data_t *task_data,
ompt_data_t *target_task_data,
ompt_data_t *target_data,
const void *codeptr_ra) {
assert(codeptr_ra != 0 && "Unexpected null codeptr");
if (endpoint == ompt_scope_begin)
target_data->value = NextOpId.fetch_add(1, std::memory_order_relaxed);
OmptCallbackHandler::get().handleTargetEmi(kind, endpoint, device_num,
task_data, target_task_data,
target_data, codeptr_ra);
}
static void on_ompt_callback_target_submit_emi(
ompt_scope_endpoint_t endpoint, ompt_data_t *target_data,
ompt_id_t *host_op_id, unsigned int requested_num_teams) {
OmptCallbackHandler::get().handleTargetSubmitEmi(
endpoint, target_data, host_op_id, requested_num_teams);
}
static void on_ompt_callback_target_map(ompt_id_t target_id,
unsigned int nitems, void **host_addr,
void **device_addr, size_t *bytes,
unsigned int *mapping_flags,
const void *codeptr_ra) {
assert(0 && "Target map callback is unimplemented");
}
static void on_ompt_callback_target_map_emi(ompt_data_t *target_data,
unsigned int nitems,
void **host_addr,
void **device_addr, size_t *bytes,
unsigned int *mapping_flags,
const void *codeptr_ra) {
assert(0 && "Target map emi callback is unimplemented");
}
/// Load the value of a given boolean environmental variable.
bool getBoolEnvironmentVariable(const char *VariableName) {
if (VariableName == nullptr)
return false;
if (const char *EnvValue = std::getenv(VariableName)) {
std::string S{EnvValue};
for (auto &C : S)
C = (char)std::tolower(C);
if (S == "1" || S == "on" || S == "true" || S == "yes")
return true;
}
return false;
}
/// Called by the OMP runtime to initialize the OMPT
int ompt_initialize(ompt_function_lookup_t lookup, int initial_device_num,
ompt_data_t *tool_data) {
ompt_set_callback_t ompt_set_callback = nullptr;
ompt_set_callback = (ompt_set_callback_t)lookup("ompt_set_callback");
if (!ompt_set_callback)
return 0; // failure
UseEMICallbacks = getBoolEnvironmentVariable("OMPTEST_USE_OMPT_EMI");
UseTracing = getBoolEnvironmentVariable("OMPTEST_USE_OMPT_TRACING");
RunAsTestSuite = getBoolEnvironmentVariable("OMPTEST_RUN_AS_TESTSUITE");
ColoredLog = getBoolEnvironmentVariable("OMPTEST_LOG_COLORED");
register_ompt_callback(ompt_callback_thread_begin);
register_ompt_callback(ompt_callback_thread_end);
register_ompt_callback(ompt_callback_parallel_begin);
register_ompt_callback(ompt_callback_parallel_end);
register_ompt_callback(ompt_callback_work);
// register_ompt_callback(ompt_callback_dispatch);
register_ompt_callback(ompt_callback_task_create);
// register_ompt_callback(ompt_callback_dependences);
// register_ompt_callback(ompt_callback_task_dependence);
register_ompt_callback(ompt_callback_task_schedule);
register_ompt_callback(ompt_callback_implicit_task);
// register_ompt_callback(ompt_callback_masked);
register_ompt_callback(ompt_callback_sync_region);
// register_ompt_callback(ompt_callback_mutex_acquire);
// register_ompt_callback(ompt_callback_mutex);
// register_ompt_callback(ompt_callback_nestLock);
// register_ompt_callback(ompt_callback_flush);
// register_ompt_callback(ompt_callback_cancel);
register_ompt_callback(ompt_callback_device_initialize);
register_ompt_callback(ompt_callback_device_finalize);
register_ompt_callback(ompt_callback_device_load);
register_ompt_callback(ompt_callback_device_unload);
if (UseEMICallbacks) {
register_ompt_callback(ompt_callback_target_emi);
register_ompt_callback(ompt_callback_target_submit_emi);
register_ompt_callback(ompt_callback_target_data_op_emi);
register_ompt_callback(ompt_callback_target_map_emi);
} else {
register_ompt_callback(ompt_callback_target);
register_ompt_callback(ompt_callback_target_submit);
register_ompt_callback(ompt_callback_target_data_op);
register_ompt_callback(ompt_callback_target_map);
}
// Construct & subscribe the reporter, so it gets notified of events
EventReporter = new OmptEventReporter();
OmptCallbackHandler::get().subscribe(EventReporter);
if (RunAsTestSuite)
EventReporter->setActive(false);
return 1; // success
}
void ompt_finalize(ompt_data_t *tool_data) {
assert(Handler && "Callback handler should be present at this point");
assert(EventReporter && "EventReporter should be present at this point");
delete Handler;
delete EventReporter;
}
#ifdef __cplusplus
extern "C" {
#endif
/// Called from the OMP Runtime to start / initialize the tool
ompt_start_tool_result_t *ompt_start_tool(unsigned int omp_version,
const char *runtime_version) {
static ompt_start_tool_result_t ompt_start_tool_result = {
&ompt_initialize, &ompt_finalize, {0}};
return &ompt_start_tool_result;
}
int start_trace(ompt_device_t *Device) {
if (!ompt_start_trace)
return 0;
// Start tracing this device (add to set)
assert(TracedDevices->find(Device) == TracedDevices->end() &&
"Device already present in the map");
TracedDevices->insert(Device);
return ompt_start_trace(Device, &on_ompt_callback_buffer_request,
&on_ompt_callback_buffer_complete);
}
int flush_trace(ompt_device_t *Device) {
if (!ompt_flush_trace)
return 0;
return ompt_flush_trace(Device);
}
int flush_traced_devices() {
if (!ompt_flush_trace || TracedDevices == nullptr)
return 0;
size_t NumFlushedDevices = 0;
for (auto Device : *TracedDevices)
if (ompt_flush_trace(Device) == 1)
++NumFlushedDevices;
// Provide time to process triggered assert events
std::this_thread::sleep_for(std::chrono::milliseconds(1));
return (NumFlushedDevices == TracedDevices->size());
}
int stop_trace(ompt_device_t *Device) {
if (!ompt_stop_trace)
return 0;
// Stop tracing this device (erase from set)
assert(TracedDevices->find(Device) != TracedDevices->end() &&
"Device not present in the map");
TracedDevices->erase(Device);
return ompt_stop_trace(Device);
}
// This is primarily used to stop unwanted prints from happening.
void libomptest_global_eventreporter_set_active(bool State) {
assert(EventReporter && "EventReporter should be present at this point");
EventReporter->setActive(State);
}
#ifdef __cplusplus
}
#endif

View File

@ -1,147 +0,0 @@
//===- OmptTesterStandalone.cpp - Standalone unit testing impl. -*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file represents the 'standalone' ompTest unit testing core
/// implementation, defining the general test suite and test case execution.
///
//===----------------------------------------------------------------------===//
#include "OmptTesterStandalone.h"
#include "OmptCallbackHandler.h"
#include <cassert>
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include <vector>
using namespace omptest;
Error TestCase::exec() {
Error E;
E.Fail = false;
if (IsDisabled)
return E;
OmptCallbackHandler::get().subscribe(SequenceAsserter.get());
OmptCallbackHandler::get().subscribe(SetAsserter.get());
OmptCallbackHandler::get().subscribe(EventReporter.get());
execImpl();
// Actively flush potential in-flight trace records
flush_traced_devices();
// We remove subscribers to not be notified of events after our test case
// finished.
OmptCallbackHandler::get().clearSubscribers();
omptest::AssertState SequenceResultState = SequenceAsserter->checkState();
omptest::AssertState SetResultState = SetAsserter->checkState();
bool AnyFail = SequenceResultState == omptest::AssertState::Fail ||
SetResultState == omptest::AssertState::Fail;
bool AllPass = SequenceResultState == omptest::AssertState::Pass &&
SetResultState == omptest::AssertState::Pass;
if (ExpectedState == omptest::AssertState::Pass && AnyFail)
E.Fail = true;
else if (ExpectedState == omptest::AssertState::Fail && AllPass)
E.Fail = true;
if (AnyFail)
ResultState = omptest::AssertState::Fail;
return E;
}
TestSuite::TestSuite(TestSuite &&O) {
Name = O.Name;
TestCases.swap(O.TestCases);
}
void TestSuite::setup() {}
void TestSuite::teardown() {}
TestSuite::TestCaseVec::iterator TestSuite::begin() {
return TestCases.begin();
}
TestSuite::TestCaseVec::iterator TestSuite::end() { return TestCases.end(); }
TestRegistrar &TestRegistrar::get() {
static TestRegistrar TR;
return TR;
}
std::vector<TestSuite> TestRegistrar::getTestSuites() {
std::vector<TestSuite> TSs;
for (auto &[k, v] : Tests)
TSs.emplace_back(std::move(v));
return TSs;
}
void TestRegistrar::addCaseToSuite(TestCase *TC, std::string TSName) {
auto &TS = Tests[TSName];
if (TS.Name.empty())
TS.Name = TSName;
TS.TestCases.emplace_back(TC);
}
Registerer::Registerer(TestCase *TC, const std::string SuiteName) {
std::cout << "Adding " << TC->Name << " to " << SuiteName << std::endl;
TestRegistrar::get().addCaseToSuite(TC, SuiteName);
}
int Runner::run() {
int ErrorCount = 0;
for (auto &TS : TestSuites) {
std::cout << "\n======\nExecuting for " << TS.Name << std::endl;
TS.setup();
for (auto &TC : TS) {
std::cout << "\nExecuting " << TC->Name << std::endl;
if (Error Err = TC->exec()) {
reportError(Err);
abortOrKeepGoing();
++ErrorCount;
}
}
TS.teardown();
}
printSummary();
return ErrorCount;
}
void Runner::reportError(const Error &Err) {}
void Runner::abortOrKeepGoing() {}
void Runner::printSummary() {
std::cout << "\n====== SUMMARY\n";
for (auto &TS : TestSuites) {
std::cout << " - " << TS.Name;
for (auto &TC : TS) {
std::string Result;
if (TC->IsDisabled) {
Result = "-#-#-";
} else if (TC->ResultState == TC->ExpectedState) {
if (TC->ResultState == omptest::AssertState::Pass)
Result = "PASS";
else if (TC->ResultState == omptest::AssertState::Fail)
Result = "XFAIL";
} else {
if (TC->ResultState == omptest::AssertState::Fail)
Result = "FAIL";
else if (TC->ResultState == omptest::AssertState::Pass)
Result = "UPASS";
}
std::cout << "\n " << std::setw(5) << Result << " : " << TC->Name;
}
std::cout << std::endl;
}
}

View File

@ -1,28 +0,0 @@
##===----------------------------------------------------------------------===##
#
# Add ompTest unit tests to check-openmp.
#
##===----------------------------------------------------------------------===##
# Target: ompTest library unit tests
file(GLOB UNITTEST_SOURCES "unittests/*.cpp")
add_executable(omptest-unittests ${UNITTEST_SOURCES})
# Add local and LLVM-provided GoogleTest include directories.
target_include_directories(omptest-unittests PRIVATE
../include
${LLVM_THIRD_PARTY_DIR}/unittest/googletest/include)
target_link_libraries(omptest-unittests PRIVATE omptest)
set_target_properties(omptest-unittests PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
# Add ompTest unit tests to check-openmp
add_openmp_testsuite(check-ompt-omptest "Running OMPT ompTest unit tests"
${CMAKE_CURRENT_BINARY_DIR} DEPENDS omptest-unittests)
# Configure the lit.site.cfg.in file
set(AUTO_GEN_COMMENT "## Autogenerated by OPENMP_TOOLS_OMPTEST_TEST "
"configuration.\n# Do not edit!")
configure_file(lit.site.cfg.in lit.site.cfg @ONLY)

View File

@ -1,26 +0,0 @@
# -*- Python -*- vim: set ft=python ts=4 sw=4 expandtab tw=79:
# Configuration file for the 'lit' test runner.
import os
import lit.formats
# Tell pylint that we know config and lit_config exist somewhere.
if 'PYLINT_IMPORT' in os.environ:
config = object()
lit_config = object()
# name: The name of this test suite.
config.name = 'OMPT ompTest'
# suffixes: A list of file extensions to treat as test files.
config.suffixes = ['']
# test_source_root: The root path where tests are located.
config.test_source_root = config.test_obj_root
# test_exec_root: The root object directory where output is placed
config.test_exec_root = config.test_obj_root
# test format, match (omptest-)unittests
# Matched binaries (GoogleTests) are executed
config.test_format = lit.formats.GoogleTest(".", "unittests")

View File

@ -1,9 +0,0 @@
@AUTO_GEN_COMMENT@
config.test_obj_root = "@CMAKE_CURRENT_BINARY_DIR@"
import lit.llvm
lit.llvm.initialize(lit_config, config)
# Let the main config do the real work.
lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")

View File

@ -1,358 +0,0 @@
#include "OmptAliases.h"
#include "OmptAsserter.h"
#include <omp-tools.h>
#include <sstream>
#include "gtest/gtest.h"
using namespace omptest;
using OAE = omptest::OmptAssertEvent;
using OS = omptest::ObserveState;
/// SequencedAsserter test-fixture class to avoid code duplication among tests.
class OmptSequencedAsserterTest : public testing::Test {
protected:
OmptSequencedAsserterTest() {
// Construct default sequenced asserter
SeqAsserter = std::make_unique<omptest::OmptSequencedAsserter>();
// Silence all potential log prints
SeqAsserter->getLog()->setLoggingLevel(logging::Level::Critical);
}
std::unique_ptr<omptest::OmptSequencedAsserter> SeqAsserter;
};
TEST_F(OmptSequencedAsserterTest, DefaultState) {
// Assertion should neither start as 'deactivated' nor 'suspended'
ASSERT_EQ(SeqAsserter->isActive(), true);
ASSERT_EQ(SeqAsserter->AssertionSuspended, false);
// Assertion should begin with event ID zero
ASSERT_EQ(SeqAsserter->NextEvent, 0);
// Assertion should begin without previous notifications or assertions
ASSERT_EQ(SeqAsserter->getNotificationCount(), 0);
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 0);
// There should be no expected events
ASSERT_EQ(SeqAsserter->Events.empty(), true);
ASSERT_EQ(SeqAsserter->getRemainingEventCount(), 0);
// Default mode should be Strict
ASSERT_NE(SeqAsserter->getOperationMode(), AssertMode::Relaxed);
ASSERT_EQ(SeqAsserter->getOperationMode(), AssertMode::Strict);
// Default state should be passing
ASSERT_NE(SeqAsserter->getState(), AssertState::Fail);
ASSERT_EQ(SeqAsserter->getState(), AssertState::Pass);
ASSERT_NE(SeqAsserter->checkState(), AssertState::Fail);
ASSERT_EQ(SeqAsserter->checkState(), AssertState::Pass);
}
TEST_F(OmptSequencedAsserterTest, IgnoreNotificationsWhenEmpty) {
// ParallelBegin events are suppressed by default
auto SuppressedEvent = OAE::ParallelBegin(
/*Name=*/"ParBegin", /*Group=*/"", /*Expected=*/OS::Always,
/*NumThreads=*/3);
// DeviceFinalize events are not ignored by default
auto IgnoredEvent = OAE::DeviceFinalize(
/*Name=*/"DevFini", /*Group=*/"", /*Expected=*/OS::Always,
/*DeviceNum=*/7);
// Situation: There is nothing to assert.
// Result: All notifications are ignored.
// Hence, check that the perceived count of notifications remains unchanged
ASSERT_EQ(SeqAsserter->getNotificationCount(), 0);
SeqAsserter->notify(std::move(SuppressedEvent));
ASSERT_EQ(SeqAsserter->getNotificationCount(), 0);
SeqAsserter->notify(std::move(IgnoredEvent));
ASSERT_EQ(SeqAsserter->getNotificationCount(), 0);
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 0);
ASSERT_EQ(SeqAsserter->checkState(), AssertState::Pass);
}
TEST_F(OmptSequencedAsserterTest, IgnoreNotificationsWhileDeactivated) {
auto ExpectedEvent = OAE::DeviceUnload(
/*Name=*/"DevUnload", /*Group=*/"", /*Expected=*/OS::Always);
SeqAsserter->insert(std::move(ExpectedEvent));
ASSERT_EQ(SeqAsserter->Events.empty(), false);
// Deactivate asserter, effectively ignoring notifications
SeqAsserter->setActive(false);
ASSERT_EQ(SeqAsserter->isActive(), false);
ASSERT_EQ(SeqAsserter->getNotificationCount(), 0);
// DeviceFinalize events are not ignored by default
auto IgnoredEvent = OAE::DeviceFinalize(
/*Name=*/"DevFini", /*Group=*/"", /*Expected=*/OS::Always,
/*DeviceNum=*/7);
SeqAsserter->notify(std::move(IgnoredEvent));
// Assertion was deactivated: No change
ASSERT_EQ(SeqAsserter->getNotificationCount(), 0);
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 0);
SeqAsserter->setActive(true);
ASSERT_EQ(SeqAsserter->isActive(), true);
auto ObservedEvent = OAE::DeviceUnload(
/*Name=*/"DevFini", /*Group=*/"", /*Expected=*/OS::Always);
SeqAsserter->notify(std::move(ObservedEvent));
// Assertion was activated, one notification expected
ASSERT_EQ(SeqAsserter->getNotificationCount(), 1);
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 1);
ASSERT_EQ(SeqAsserter->checkState(), AssertState::Pass);
}
TEST_F(OmptSequencedAsserterTest, AddEvent) {
ASSERT_EQ(SeqAsserter->getRemainingEventCount(), 0);
auto ExpectedEvent = OAE::DeviceFinalize(
/*Name=*/"DevFini", /*Group=*/"", /*Expected=*/OS::Always,
/*DeviceNum=*/7);
SeqAsserter->insert(std::move(ExpectedEvent));
// Sanity check: Notifications should not be triggered
ASSERT_EQ(SeqAsserter->getNotificationCount(), 0);
// Adding an expected event must change the event count but not the state
ASSERT_EQ(SeqAsserter->getRemainingEventCount(), 1);
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 0);
ASSERT_EQ(SeqAsserter->getState(), AssertState::Pass);
}
TEST_F(OmptSequencedAsserterTest, AddEventIgnoreSuppressed) {
auto ExpectedEvent = OAE::DeviceFinalize(
/*Name=*/"DevFini", /*Group=*/"", /*Expected=*/OS::Always,
/*DeviceNum=*/7);
SeqAsserter->insert(std::move(ExpectedEvent));
// ParallelBegin events are suppressed by default
auto SuppressedEvent = OAE::ParallelBegin(
/*Name=*/"ParBegin", /*Group=*/"", /*Expected=*/OS::Always,
/*NumThreads=*/3);
// Situation: There is one expected event and ParallelBegins are suppressed.
// Notification count remains unchanged for suppressed events
ASSERT_EQ(SeqAsserter->getNotificationCount(), 0);
SeqAsserter->notify(std::move(SuppressedEvent));
ASSERT_EQ(SeqAsserter->getNotificationCount(), 0);
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 0);
ASSERT_EQ(SeqAsserter->getState(), AssertState::Pass);
}
TEST_F(OmptSequencedAsserterTest, AddEventObservePass) {
auto ExpectedEvent = OAE::DeviceFinalize(
/*Name=*/"DevFini", /*Group=*/"", /*Expected=*/OS::Always,
/*DeviceNum=*/7);
SeqAsserter->insert(std::move(ExpectedEvent));
// DeviceFinalize events are not ignored by default
auto ObservedEvent = OAE::DeviceFinalize(
/*Name=*/"DevFini", /*Group=*/"", /*Expected=*/OS::Always,
/*DeviceNum=*/7);
SeqAsserter->notify(std::move(ObservedEvent));
ASSERT_EQ(SeqAsserter->getNotificationCount(), 1);
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 1);
ASSERT_EQ(SeqAsserter->checkState(), AssertState::Pass);
}
TEST_F(OmptSequencedAsserterTest, AddEventObserveFail) {
auto ExpectedEvent = OAE::DeviceFinalize(
/*Name=*/"DevFini", /*Group=*/"", /*Expected=*/OS::Always,
/*DeviceNum=*/7);
SeqAsserter->insert(std::move(ExpectedEvent));
// DeviceFinalize events are not ignored by default
// Provide wrong DeviceNum
auto ObservedEvent = OAE::DeviceFinalize(
/*Name=*/"DevFini", /*Group=*/"", /*Expected=*/OS::Always,
/*DeviceNum=*/23);
SeqAsserter->notify(std::move(ObservedEvent));
ASSERT_EQ(SeqAsserter->getNotificationCount(), 1);
// Observed and expected event do not match: Fail
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 0);
ASSERT_EQ(SeqAsserter->checkState(), AssertState::Fail);
}
TEST_F(OmptSequencedAsserterTest, AddEventObserveDifferentType) {
auto ExpectedEvent = OAE::DeviceUnload(
/*Name=*/"DevUnload", /*Group=*/"", /*Expected=*/OS::Always);
SeqAsserter->insert(std::move(ExpectedEvent));
// DeviceFinalize events are not ignored by default
auto ObservedEvent = OAE::DeviceFinalize(
/*Name=*/"DevFini", /*Group=*/"", /*Expected=*/OS::Always,
/*DeviceNum=*/7);
SeqAsserter->notify(std::move(ObservedEvent));
ASSERT_EQ(SeqAsserter->getNotificationCount(), 1);
// Observed and expected event do not match: Fail
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 0);
ASSERT_EQ(SeqAsserter->checkState(), AssertState::Fail);
}
TEST_F(OmptSequencedAsserterTest, CheckTargetGroupNoEffect) {
// Situation: Groups are designed to be used as an indicator -WITHIN- target
// regions. Hence, comparing two target regions w.r.t. their groups has no
// effect on pass or fail.
auto ExpectedEvent = OAE::Target(
/*Name=*/"Target", /*Group=*/"MyTargetGroup", /*Expected=*/OS::Always,
/*Kind=*/TARGET, /*Endpoint=*/BEGIN,
/*DeviceNum=*/7, /*TaskData=*/nullptr, /*TargetId=*/23,
/*CodeptrRA=*/nullptr);
SeqAsserter->insert(std::move(ExpectedEvent));
ASSERT_EQ(SeqAsserter->Events.empty(), false);
// Deactivate asserter, effectively ignoring notifications
SeqAsserter->setActive(false);
ASSERT_EQ(SeqAsserter->isActive(), false);
ASSERT_EQ(SeqAsserter->getNotificationCount(), 0);
// Target events are not ignored by default
auto ObservedEvent = OAE::Target(
/*Name=*/"Target", /*Group=*/"MyTargetGroup", /*Expected=*/OS::Always,
/*Kind=*/TARGET, /*Endpoint=*/BEGIN, /*DeviceNum=*/7,
/*TaskData=*/nullptr, /*TargetId=*/23, /*CodeptrRA=*/nullptr);
SeqAsserter->notify(std::move(ObservedEvent));
// Assertion was deactivated: No change
ASSERT_EQ(SeqAsserter->getNotificationCount(), 0);
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 0);
ASSERT_EQ(SeqAsserter->getRemainingEventCount(), 1);
// Re-activate asserter
SeqAsserter->setActive(true);
ASSERT_EQ(SeqAsserter->isActive(), true);
ASSERT_EQ(SeqAsserter->getNotificationCount(), 0);
// Actually observe a target event from "AnotherGroup"
auto AnotherObservedEvent = OAE::Target(
/*Name=*/"Target", /*Group=*/"AnotherGroup", /*Expected=*/OS::Always,
/*Kind=*/TARGET, /*Endpoint=*/BEGIN, /*DeviceNum=*/7,
/*TaskData=*/nullptr, /*TargetId=*/23, /*CodeptrRA=*/nullptr);
SeqAsserter->notify(std::move(AnotherObservedEvent));
// Observed all expected events; groups of target regions do not affect pass
ASSERT_EQ(SeqAsserter->getNotificationCount(), 1);
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 1);
ASSERT_EQ(SeqAsserter->getRemainingEventCount(), 0);
ASSERT_EQ(SeqAsserter->checkState(), AssertState::Pass);
}
TEST_F(OmptSequencedAsserterTest, CheckSyncPoint) {
auto ExpectedEvent = OAE::Target(
/*Name=*/"Target", /*Group=*/"MyTargetGroup", /*Expected=*/OS::Always,
/*Kind=*/TARGET, /*Endpoint=*/BEGIN,
/*DeviceNum=*/7, /*TaskData=*/nullptr, /*TargetId=*/23,
/*CodeptrRA=*/nullptr);
SeqAsserter->insert(std::move(ExpectedEvent));
ASSERT_EQ(SeqAsserter->Events.empty(), false);
ASSERT_EQ(SeqAsserter->getRemainingEventCount(), 1);
// Target events are not ignored by default
auto ObservedEvent = OAE::Target(
/*Name=*/"Target", /*Group=*/"MyTargetGroup", /*Expected=*/OS::Always,
/*Kind=*/TARGET, /*Endpoint=*/BEGIN, /*DeviceNum=*/7,
/*TaskData=*/nullptr, /*TargetId=*/23, /*CodeptrRA=*/nullptr);
SeqAsserter->notify(std::move(ObservedEvent));
ASSERT_EQ(SeqAsserter->getNotificationCount(), 1);
SeqAsserter->notify(OAE::AssertionSyncPoint(
/*Name=*/"", /*Group=*/"", /*Expected=*/OS::Always,
/*SyncPointName=*/"SyncPoint 1"));
ASSERT_EQ(SeqAsserter->getNotificationCount(), 2);
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 1);
// All events processed: SyncPoint "passes"
ASSERT_EQ(SeqAsserter->checkState(), AssertState::Pass);
auto AnotherExpectedEvent = OAE::Target(
/*Name=*/"Target", /*Group=*/"MyTargetGroup", /*Expected=*/OS::Always,
/*Kind=*/TARGET, /*Endpoint=*/BEGIN,
/*DeviceNum=*/7, /*TaskData=*/nullptr, /*TargetId=*/23,
/*CodeptrRA=*/nullptr);
ASSERT_EQ(SeqAsserter->getRemainingEventCount(), 0);
SeqAsserter->insert(std::move(AnotherExpectedEvent));
ASSERT_EQ(SeqAsserter->getRemainingEventCount(), 1);
// Remaining events present: SyncPoint "fails"
SeqAsserter->notify(OAE::AssertionSyncPoint(
/*Name=*/"", /*Group=*/"", /*Expected=*/OS::Always,
/*SyncPointName=*/"SyncPoint 2"));
ASSERT_EQ(SeqAsserter->checkState(), AssertState::Fail);
}
TEST_F(OmptSequencedAsserterTest, CheckExcessNotify) {
auto ExpectedEvent = OAE::Target(
/*Name=*/"Target", /*Group=*/"MyTargetGroup", /*Expected=*/OS::Always,
/*Kind=*/TARGET, /*Endpoint=*/BEGIN,
/*DeviceNum=*/7, /*TaskData=*/nullptr, /*TargetId=*/23,
/*CodeptrRA=*/nullptr);
SeqAsserter->insert(std::move(ExpectedEvent));
ASSERT_EQ(SeqAsserter->Events.empty(), false);
ASSERT_EQ(SeqAsserter->getRemainingEventCount(), 1);
// Target events are not ignored by default
auto ObservedEvent = OAE::Target(
/*Name=*/"Target", /*Group=*/"MyTargetGroup", /*Expected=*/OS::Always,
/*Kind=*/TARGET, /*Endpoint=*/BEGIN, /*DeviceNum=*/7,
/*TaskData=*/nullptr, /*TargetId=*/23, /*CodeptrRA=*/nullptr);
SeqAsserter->notify(std::move(ObservedEvent));
ASSERT_EQ(SeqAsserter->getNotificationCount(), 1);
// All events processed: pass
ASSERT_EQ(SeqAsserter->checkState(), AssertState::Pass);
// Target events are not ignored by default
auto AnotherObservedEvent = OAE::Target(
/*Name=*/"Target", /*Group=*/"MyTargetGroup", /*Expected=*/OS::Always,
/*Kind=*/TARGET, /*Endpoint=*/BEGIN, /*DeviceNum=*/7,
/*TaskData=*/nullptr, /*TargetId=*/23, /*CodeptrRA=*/nullptr);
// No more events expected: notify "fails"
SeqAsserter->notify(std::move(AnotherObservedEvent));
ASSERT_EQ(SeqAsserter->getNotificationCount(), 2);
ASSERT_EQ(SeqAsserter->checkState(), AssertState::Fail);
}
TEST_F(OmptSequencedAsserterTest, CheckSuspend) {
SeqAsserter->insert(OAE::AssertionSuspend(
/*Name=*/"", /*Group=*/"", /*Expected=*/OS::Never));
ASSERT_EQ(SeqAsserter->Events.empty(), false);
// Being notified while the next expected event is a "suspend" should change
// the asserter's state
ASSERT_EQ(SeqAsserter->getNotificationCount(), 0);
ASSERT_EQ(SeqAsserter->AssertionSuspended, false);
SeqAsserter->notify(OAE::DeviceFinalize(
/*Name=*/"DevFini", /*Group=*/"", /*Expected=*/OS::Always,
/*DeviceNum=*/7));
ASSERT_EQ(SeqAsserter->AssertionSuspended, true);
ASSERT_EQ(SeqAsserter->getNotificationCount(), 1);
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 0);
ASSERT_EQ(SeqAsserter->checkState(), AssertState::Pass);
auto ExpectedEvent = OAE::Target(
/*Name=*/"Target", /*Group=*/"MyTargetGroup", /*Expected=*/OS::Always,
/*Kind=*/TARGET, /*Endpoint=*/BEGIN,
/*DeviceNum=*/7, /*TaskData=*/nullptr, /*TargetId=*/23,
/*CodeptrRA=*/nullptr);
SeqAsserter->insert(std::move(ExpectedEvent));
// Being notified with an observed event, which matches the next expected
// event, resumes assertion (suspended = false)
ASSERT_EQ(SeqAsserter->AssertionSuspended, true);
SeqAsserter->notify(OAE::Target(
/*Name=*/"Target", /*Group=*/"MyTargetGroup", /*Expected=*/OS::Always,
/*Kind=*/TARGET, /*Endpoint=*/BEGIN,
/*DeviceNum=*/7, /*TaskData=*/nullptr, /*TargetId=*/23,
/*CodeptrRA=*/nullptr));
ASSERT_EQ(SeqAsserter->AssertionSuspended, false);
ASSERT_EQ(SeqAsserter->getNotificationCount(), 2);
ASSERT_EQ(SeqAsserter->getSuccessfulAssertionCount(), 1);
ASSERT_EQ(SeqAsserter->checkState(), AssertState::Pass);
}

View File

@ -1,530 +0,0 @@
#include "InternalEvent.h"
#include <omp-tools.h>
#include <sstream>
#include "gtest/gtest.h"
using namespace omptest;
TEST(InternalEvent_toString, AssertionSyncPoint) {
internal::AssertionSyncPoint SP{/*Name=*/"Test Sync Point"};
EXPECT_EQ(SP.toString(), "Assertion SyncPoint: 'Test Sync Point'");
}
TEST(InternalEvent_toString, ThreadBegin) {
internal::ThreadBegin TB{/*ThreadType=*/ompt_thread_t::ompt_thread_initial};
EXPECT_EQ(TB.toString(), "OMPT Callback ThreadBegin: ThreadType=1");
}
TEST(InternalEvent_toString, ThreadEnd) {
internal::ThreadEnd TE{};
EXPECT_EQ(TE.toString(), "OMPT Callback ThreadEnd");
}
TEST(InternalEvent_toString, ParallelBegin) {
internal::ParallelBegin PB{/*NumThreads=*/31};
EXPECT_EQ(PB.toString(), "OMPT Callback ParallelBegin: NumThreads=31");
}
TEST(InternalEvent_toString, ParallelEnd) {
internal::ParallelEnd PE{/*ParallelData=*/(ompt_data_t *)0x11,
/*EncounteringTaskData=*/(ompt_data_t *)0x22,
/*Flags=*/31,
/*CodeptrRA=*/(const void *)0x33};
EXPECT_EQ(PE.toString(), "OMPT Callback ParallelEnd");
}
TEST(InternalEvent_toString, Work) {
internal::Work WK{/*WorkType=*/ompt_work_t::ompt_work_loop_dynamic,
/*Endpoint=*/ompt_scope_endpoint_t::ompt_scope_beginend,
/*ParallelData=*/(ompt_data_t *)0x11,
/*TaskData=*/(ompt_data_t *)0x22,
/*Count=*/31,
/*CodeptrRA=*/(const void *)0x33};
EXPECT_EQ(WK.toString(),
"OMPT Callback Work: work_type=11 endpoint=3 parallel_data=0x11 "
"task_data=0x22 count=31 codeptr=0x33");
}
TEST(InternalEvent_toString, Dispatch_iteration) {
ompt_data_t DI{.value = 31};
internal::Dispatch D{/*ParallelData=*/(ompt_data_t *)0x11,
/*TaskData=*/(ompt_data_t *)0x22,
/*Kind=*/ompt_dispatch_t::ompt_dispatch_iteration,
/*Instance=*/DI};
EXPECT_EQ(D.toString(), "OMPT Callback Dispatch: parallel_data=0x11 "
"task_data=0x22 kind=1 instance=[it=31]");
}
TEST(InternalEvent_toString, Dispatch_section) {
ompt_data_t DI{.ptr = (void *)0x33};
internal::Dispatch D{/*ParallelData=*/(ompt_data_t *)0x11,
/*TaskData=*/(ompt_data_t *)0x22,
/*Kind=*/ompt_dispatch_t::ompt_dispatch_section,
/*Instance=*/DI};
EXPECT_EQ(D.toString(), "OMPT Callback Dispatch: parallel_data=0x11 "
"task_data=0x22 kind=2 instance=[ptr=0x33]");
}
TEST(InternalEvent_toString, Dispatch_chunks) {
ompt_dispatch_chunk_t DC{.start = 7, .iterations = 31};
ompt_data_t DI{.ptr = (void *)&DC};
internal::Dispatch DLoop{
/*ParallelData=*/(ompt_data_t *)0x11,
/*TaskData=*/(ompt_data_t *)0x22,
/*Kind=*/ompt_dispatch_t::ompt_dispatch_ws_loop_chunk,
/*Instance=*/DI};
internal::Dispatch DTask{
/*ParallelData=*/(ompt_data_t *)0x11,
/*TaskData=*/(ompt_data_t *)0x22,
/*Kind=*/ompt_dispatch_t::ompt_dispatch_taskloop_chunk,
/*Instance=*/DI};
internal::Dispatch DDist{
/*ParallelData=*/(ompt_data_t *)0x11,
/*TaskData=*/(ompt_data_t *)0x22,
/*Kind=*/ompt_dispatch_t::ompt_dispatch_distribute_chunk,
/*Instance=*/DI};
ompt_data_t DINull{.ptr = nullptr};
internal::Dispatch DDistNull{
/*ParallelData=*/(ompt_data_t *)0x11,
/*TaskData=*/(ompt_data_t *)0x22,
/*Kind=*/ompt_dispatch_t::ompt_dispatch_distribute_chunk,
/*Instance=*/DINull};
EXPECT_EQ(DLoop.toString(),
"OMPT Callback Dispatch: parallel_data=0x11 "
"task_data=0x22 kind=3 instance=[chunk=(start=7, iterations=31)]");
EXPECT_EQ(DTask.toString(),
"OMPT Callback Dispatch: parallel_data=0x11 "
"task_data=0x22 kind=4 instance=[chunk=(start=7, iterations=31)]");
EXPECT_EQ(DDist.toString(),
"OMPT Callback Dispatch: parallel_data=0x11 "
"task_data=0x22 kind=5 instance=[chunk=(start=7, iterations=31)]");
EXPECT_EQ(DDistNull.toString(), "OMPT Callback Dispatch: parallel_data=0x11 "
"task_data=0x22 kind=5");
}
TEST(InternalEvent_toString, TaskCreate) {
internal::TaskCreate TC{/*EncounteringTaskData=*/(ompt_data_t *)0x11,
/*EncounteringTaskFrame=*/(const ompt_frame_t *)0x22,
/*NewTaskData=*/(ompt_data_t *)0x33,
/*Flags=*/7,
/*HasDependences=*/31,
/*CodeptrRA=*/(const void *)0x44};
EXPECT_EQ(TC.toString(),
"OMPT Callback TaskCreate: encountering_task_data=0x11 "
"encountering_task_frame=0x22 new_task_data=0x33 flags=7 "
"has_dependences=31 codeptr=0x44");
}
TEST(InternalEvent_toString, ImplicitTask) {
internal::ImplicitTask IT{
/*Endpoint=*/ompt_scope_endpoint_t::ompt_scope_begin,
/*ParallelData=*/(ompt_data_t *)0x11,
/*TaskData=*/(ompt_data_t *)0x22,
/*ActualParallelism=*/7,
/*Index=*/31,
/*Flags=*/127};
EXPECT_EQ(IT.toString(),
"OMPT Callback ImplicitTask: endpoint=1 parallel_data=0x11 "
"task_data=0x22 actual_parallelism=7 index=31 flags=127");
}
TEST(InternalEvent_toString, SyncRegion) {
internal::SyncRegion SR{
/*Kind=*/ompt_sync_region_t::ompt_sync_region_taskwait,
/*Endpoint=*/ompt_scope_endpoint_t::ompt_scope_end,
/*ParallelData=*/(ompt_data_t *)0x11,
/*TaskData=*/(ompt_data_t *)0x22,
/*CodeptrRA=*/(const void *)0x33};
EXPECT_EQ(SR.toString(), "OMPT Callback SyncRegion: kind=5 endpoint=2 "
"parallel_data=0x11 task_data=0x22 codeptr=0x33");
}
TEST(InternalEvent_toString, Target) {
internal::Target T{/*Kind=*/ompt_target_t::ompt_target_enter_data_nowait,
/*Endpoint=*/ompt_scope_endpoint_t::ompt_scope_end,
/*DeviceNum=*/7,
/*TaskData=*/(ompt_data_t *)0x11,
/*TargetId=*/(ompt_id_t)31,
/*CodeptrRA=*/(const void *)0x22};
EXPECT_EQ(T.toString(), "Callback Target: target_id=31 kind=10 "
"endpoint=2 device_num=7 code=0x22");
}
TEST(InternalEvent_toString, TargetEmi) {
ompt_data_t TaskData{.value = 31};
ompt_data_t TargetTaskData{.value = 127};
ompt_data_t TargetData{.value = 8191};
internal::TargetEmi T{/*Kind=*/ompt_target_t::ompt_target_update,
/*Endpoint=*/ompt_scope_endpoint_t::ompt_scope_begin,
/*DeviceNum=*/7,
/*TaskData=*/(ompt_data_t *)&TaskData,
/*TargetTaskData=*/(ompt_data_t *)&TargetTaskData,
/*TargetData=*/(ompt_data_t *)&TargetData,
/*CodeptrRA=*/(const void *)0x11};
internal::TargetEmi TDataNull{
/*Kind=*/ompt_target_t::ompt_target_update,
/*Endpoint=*/ompt_scope_endpoint_t::ompt_scope_begin,
/*DeviceNum=*/7,
/*TaskData=*/(ompt_data_t *)&TaskData,
/*TargetTaskData=*/(ompt_data_t *)nullptr,
/*TargetData=*/(ompt_data_t *)&TargetData,
/*CodeptrRA=*/(const void *)0x11};
std::ostringstream StreamT1;
std::ostringstream StreamT2;
std::string CallBackPrefix{
"Callback Target EMI: kind=4 endpoint=1 device_num=7"};
StreamT1 << CallBackPrefix << std::showbase << std::hex;
StreamT1 << " task_data=" << &TaskData << " (0x1f)";
StreamT1 << " target_task_data=" << &TargetTaskData << " (0x7f)";
StreamT1 << " target_data=" << &TargetData << " (0x1fff)";
StreamT1 << " code=0x11";
StreamT2 << CallBackPrefix << std::showbase << std::hex;
StreamT2 << " task_data=" << &TaskData << " (0x1f)";
StreamT2 << " target_task_data=(nil) (0x0)";
StreamT2 << " target_data=" << &TargetData << " (0x1fff)";
StreamT2 << " code=0x11";
EXPECT_EQ(T.toString(), StreamT1.str());
EXPECT_EQ(TDataNull.toString(), StreamT2.str());
}
TEST(InternalEvent_toString, TargetDataOp) {
internal::TargetDataOp TDO{
/*TargetId=*/7,
/*HostOpId=*/31,
/*OpType=*/ompt_target_data_op_t::ompt_target_data_associate,
/*SrcAddr=*/(void *)0x11,
/*SrcDeviceNum=*/127,
/*DstAddr=*/(void *)0x22,
/*DstDeviceNum=*/8191,
/*Bytes=*/4096,
/*CodeptrRA=*/(const void *)0x33};
EXPECT_EQ(
TDO.toString(),
" Callback DataOp: target_id=7 host_op_id=31 optype=5 src=0x11 "
"src_device_num=127 dest=0x22 dest_device_num=8191 bytes=4096 code=0x33");
}
TEST(InternalEvent_toString, TargetDataOpEmi) {
ompt_data_t TargetTaskData{.value = 31};
ompt_data_t TargetData{.value = 127};
ompt_id_t HostOpId = 8191;
internal::TargetDataOpEmi TDO{
/*Endpoint=*/ompt_scope_endpoint_t::ompt_scope_begin,
/*TargetTaskData=*/(ompt_data_t *)&TargetTaskData,
/*TargetData=*/(ompt_data_t *)&TargetData,
/*HostOpId=*/(ompt_id_t *)&HostOpId,
/*OpType=*/ompt_target_data_op_t::ompt_target_data_disassociate,
/*SrcAddr=*/(void *)0x11,
/*SrcDeviceNum=*/1,
/*DstAddr=*/(void *)0x22,
/*DstDeviceNum=*/2,
/*Bytes=*/4096,
/*CodeptrRA=*/(const void *)0x33};
// Set HostOpId=nullptr
internal::TargetDataOpEmi TDO_HostOpIdNull{
/*Endpoint=*/ompt_scope_endpoint_t::ompt_scope_begin,
/*TargetTaskData=*/(ompt_data_t *)&TargetTaskData,
/*TargetData=*/(ompt_data_t *)&TargetData,
/*HostOpId=*/(ompt_id_t *)nullptr,
/*OpType=*/ompt_target_data_op_t::ompt_target_data_disassociate,
/*SrcAddr=*/(void *)0x11,
/*SrcDeviceNum=*/1,
/*DstAddr=*/(void *)0x22,
/*DstDeviceNum=*/2,
/*Bytes=*/4096,
/*CodeptrRA=*/(const void *)0x33};
std::ostringstream StreamTDO1;
std::ostringstream StreamTDO2;
std::string CallBackPrefix{" Callback DataOp EMI: endpoint=1 optype=6"};
std::string CallBackSuffix{
" src=0x11 src_device_num=1 dest=0x22 dest_device_num=2 "
"bytes=4096 code=0x33"};
StreamTDO1 << CallBackPrefix << std::showbase << std::hex;
StreamTDO1 << " target_task_data=" << &TargetTaskData << " (0x1f)";
StreamTDO1 << " target_data=" << &TargetData << " (0x7f)";
StreamTDO1 << " host_op_id=" << &HostOpId << " (0x1fff)";
StreamTDO1 << CallBackSuffix;
StreamTDO2 << CallBackPrefix << std::showbase << std::hex;
StreamTDO2 << " target_task_data=" << &TargetTaskData << " (0x1f)";
StreamTDO2 << " target_data=" << &TargetData << " (0x7f)";
StreamTDO2 << " host_op_id=(nil) (0x0)";
StreamTDO2 << CallBackSuffix;
EXPECT_EQ(TDO.toString(), StreamTDO1.str());
EXPECT_EQ(TDO_HostOpIdNull.toString(), StreamTDO2.str());
}
TEST(InternalEvent_toString, TargetSubmit) {
internal::TargetSubmit TS{/*TargetId=*/7,
/*HostOpId=*/31,
/*RequestedNumTeams=*/127};
EXPECT_EQ(TS.toString(),
" Callback Submit: target_id=7 host_op_id=31 req_num_teams=127");
}
TEST(InternalEvent_toString, TargetSubmitEmi) {
ompt_data_t TargetData{.value = 127};
ompt_id_t HostOpId = 8191;
internal::TargetSubmitEmi TS{
/*Endpoint=*/ompt_scope_endpoint_t::ompt_scope_begin,
/*TargetData=*/(ompt_data_t *)&TargetData,
/*HostOpId=*/(ompt_id_t *)&HostOpId,
/*RequestedNumTeams=*/7};
std::ostringstream StreamTS;
std::string CallBackPrefix{
" Callback Submit EMI: endpoint=1 req_num_teams=7"};
StreamTS << CallBackPrefix << std::showbase << std::hex;
StreamTS << " target_data=" << &TargetData << " (0x7f)";
StreamTS << " host_op_id=" << &HostOpId << " (0x1fff)";
EXPECT_EQ(TS.toString(), StreamTS.str());
}
TEST(InternalEvent_toString, DeviceInitialize) {
const char *Type = "DeviceType";
const char *DocStr = "DocumentationString";
internal::DeviceInitialize DI{/*DeviceNum=*/7,
/*Type=*/Type,
/*Device=*/(ompt_device_t *)0x11,
/*LookupFn=*/(ompt_function_lookup_t)0x22,
/*DocStr=*/DocStr};
internal::DeviceInitialize DINull{/*DeviceNum=*/0,
/*Type=*/nullptr,
/*Device=*/nullptr,
/*LookupFn=*/(ompt_function_lookup_t)0x0,
/*DocStr=*/nullptr};
std::ostringstream StreamDI;
std::string CallBackPrefix{"Callback Init: device_num=7 type=DeviceType "
"device=0x11 lookup=0x22 doc="};
StreamDI << CallBackPrefix << std::showbase << std::hex;
StreamDI << (uint64_t)DocStr;
EXPECT_EQ(DI.toString(), StreamDI.str());
// TODO This looks inconsistent: (null) vs. (nil)
EXPECT_EQ(DINull.toString(), "Callback Init: device_num=0 type=(null) "
"device=(nil) lookup=(nil) doc=(nil)");
}
TEST(InternalEvent_toString, DeviceFinalize) {
internal::DeviceFinalize DF{/*DeviceNum=*/7};
EXPECT_EQ(DF.toString(), "Callback Fini: device_num=7");
}
TEST(InternalEvent_toString, DeviceLoad) {
const char *Filename = "FilenameToLoad";
internal::DeviceLoad DL{/*DeviceNum=*/7,
/*Filename=*/Filename,
/*OffsetInFile=*/31,
/*VmaInFile=*/(void *)0x11,
/*Bytes=*/127,
/*HostAddr=*/(void *)0x22,
/*DeviceAddr=*/(void *)0x33,
/*ModuleId=*/8191};
internal::DeviceLoad DLNull{/*DeviceNum=*/0,
/*Filename=*/nullptr,
/*OffsetInFile=*/0,
/*VmaInFile=*/nullptr,
/*Bytes=*/0,
/*HostAddr=*/nullptr,
/*DeviceAddr=*/nullptr,
/*ModuleId=*/0};
EXPECT_EQ(
DL.toString(),
"Callback Load: device_num:7 module_id:8191 "
"filename:FilenameToLoad host_addr:0x22 device_addr:0x33 bytes:127");
// TODO This looks inconsistent: (null) vs. (nil) and ':' instead of '='
EXPECT_EQ(DLNull.toString(),
"Callback Load: device_num:0 module_id:0 filename:(null) "
"host_addr:(nil) device_addr:(nil) bytes:0");
}
TEST(InternalEvent_toString, BufferRequest) {
size_t Bytes = 7;
ompt_buffer_t *Buffer = (void *)0x11;
internal::BufferRequest BR{/*DeviceNum=*/31,
/*Buffer=*/&Buffer,
/*Bytes=*/&Bytes};
internal::BufferRequest BRNull{/*DeviceNum=*/127,
/*Buffer=*/nullptr,
/*Bytes=*/nullptr};
EXPECT_EQ(BR.toString(),
"Allocated 7 bytes at 0x11 in buffer request callback");
EXPECT_EQ(BRNull.toString(),
"Allocated 0 bytes at (nil) in buffer request callback");
}
TEST(InternalEvent_toString, BufferComplete) {
ompt_buffer_t *Buffer = (void *)0x11;
internal::BufferComplete BC{/*DeviceNum=*/7,
/*Buffer=*/Buffer,
/*Bytes=*/127,
/*Begin=*/8191,
/*BufferOwned=*/1};
internal::BufferComplete BCNull{/*DeviceNum=*/0,
/*Buffer=*/nullptr,
/*Bytes=*/0,
/*Begin=*/0,
/*BufferOwned=*/0};
EXPECT_EQ(BC.toString(),
"Executing buffer complete callback: 7 0x11 127 0x1fff 1");
EXPECT_EQ(BCNull.toString(),
"Executing buffer complete callback: 0 (nil) 0 (nil) 0");
}
TEST(InternalEvent_toString, BufferRecordInvalid) {
ompt_record_ompt_t InvalidRecord{
/*type=*/ompt_callbacks_t::ompt_callback_parallel_begin,
/*time=*/7,
/*thread_id=*/31,
/*target_id=*/127,
/*record=*/{.parallel_begin = {}}};
internal::BufferRecord BRNull{/*RecordPtr=*/nullptr};
internal::BufferRecord BRInvalid{/*RecordPtr=*/&InvalidRecord};
std::ostringstream StreamBRInvalid;
StreamBRInvalid << "rec=" << std::showbase << std::hex << &InvalidRecord;
StreamBRInvalid << " type=3 (unsupported record type)";
EXPECT_EQ(BRNull.toString(), "rec=(nil) type=0 (unsupported record type)");
EXPECT_EQ(BRInvalid.toString(), StreamBRInvalid.str());
}
TEST(InternalEvent_toString, BufferRecordTarget) {
ompt_record_target_t SubRecordTarget{
/*kind=*/ompt_target_t::ompt_target_update,
/*endpoint=*/ompt_scope_endpoint_t::ompt_scope_begin,
/*device_num=*/2,
/*task_id=*/127,
/*target_id=*/31,
/*codeptr_ra=*/(const void *)0x11};
ompt_record_ompt_t TargetRecord{
/*type=*/ompt_callbacks_t::ompt_callback_target,
/*time=*/7,
/*thread_id=*/29,
/*target_id=*/31,
/*record*/ {.target = SubRecordTarget}};
internal::BufferRecord BR{/*RecordPtr=*/&TargetRecord};
std::ostringstream StreamBR;
StreamBR << "rec=" << std::showbase << std::hex << &TargetRecord;
StreamBR << " type=8 (Target task) time=7 thread_id=29 target_id=31 kind=4";
StreamBR << " endpoint=1 device=2 task_id=127 codeptr=0x11";
EXPECT_EQ(BR.toString(), StreamBR.str());
}
TEST(InternalEvent_toString, BufferRecordDataOp) {
ompt_record_target_data_op_t SubRecordTargetDataOp{
/*host_op_id=*/7,
/*optype=*/ompt_target_data_op_t::ompt_target_data_alloc_async,
/*src_addr=*/(void *)0x11,
/*src_device_num=*/1,
/*dest_addr=*/(void *)0x22,
/*dest_device_num=*/2,
/*bytes=*/127,
/*end_time=*/128,
/*codeptr_ra=*/(const void *)0x33,
};
ompt_record_ompt_t DataOpRecord{
/*type=*/ompt_callbacks_t::ompt_callback_target_data_op_emi,
/*time=*/8,
/*thread_id=*/3,
/*target_id=*/5,
/*record=*/{.target_data_op = SubRecordTargetDataOp}};
internal::BufferRecord BR{/*RecordPtr=*/&DataOpRecord};
std::ostringstream StreamBR;
StreamBR << "rec=" << std::showbase << std::hex << &DataOpRecord;
StreamBR << " type=34 (Target data op) time=8 thread_id=3 target_id=5";
StreamBR << " host_op_id=7 optype=17 src_addr=0x11 src_device=1";
StreamBR << " dest_addr=0x22 dest_device=2 bytes=127 end_time=128";
StreamBR << " duration=120 ns codeptr=0x33";
EXPECT_EQ(BR.toString(), StreamBR.str());
}
TEST(InternalEvent_toString, BufferRecordKernel) {
ompt_record_target_kernel_t SubRecordTargetKernel{
/*host_op_id=*/11,
/*requested_num_teams=*/127,
/*granted_num_teams=*/63,
/*end_time=*/8191,
};
ompt_record_ompt_t KernelRecord{
/*type=*/ompt_callbacks_t::ompt_callback_target_submit_emi,
/*time=*/9,
/*thread_id=*/19,
/*target_id=*/33,
/*record=*/{.target_kernel = SubRecordTargetKernel}};
internal::BufferRecord BR{/*RecordPtr=*/&KernelRecord};
std::ostringstream StreamBR;
StreamBR << "rec=" << std::showbase << std::hex << &KernelRecord;
StreamBR << " type=35 (Target kernel) time=9 thread_id=19 target_id=33";
StreamBR << " host_op_id=11 requested_num_teams=127 granted_num_teams=63";
StreamBR << " end_time=8191 duration=8182 ns";
EXPECT_EQ(BR.toString(), StreamBR.str());
}
TEST(InternalEvent_toString, BufferRecordDeallocation) {
internal::BufferRecordDeallocation BRD{/*Buffer=*/(ompt_record_ompt_t *)0x11};
internal::BufferRecordDeallocation BRDNull{/*Buffer=*/nullptr};
EXPECT_EQ(BRD.toString(), "Deallocated 0x11");
EXPECT_EQ(BRDNull.toString(), "Deallocated (nil)");
}

View File

@ -1,90 +0,0 @@
#include "InternalEvent.h"
#include <omp-tools.h>
#include "gtest/gtest.h"
using namespace omptest;
using namespace util;
TEST(InternalUtility, ExpectedDefault_Integer) {
// int: -2147483648 (decimal) = 0x80000000 (hexadecimal)
EXPECT_EQ(expectedDefault(int), 0x80000000);
EXPECT_EQ(expectedDefault(int), (0x1 << 31));
// int64_t: -9223372036854775808 (decimal) = 0x8000000000000000 (hexadecimal)
EXPECT_EQ(expectedDefault(int64_t), 0x8000000000000000);
EXPECT_EQ(expectedDefault(int64_t), (0x1L << 63));
}
TEST(InternalUtility, ExpectedDefault_Zero) {
// Expectedly zero
EXPECT_EQ(expectedDefault(size_t), 0);
EXPECT_EQ(expectedDefault(unsigned int), 0);
EXPECT_EQ(expectedDefault(ompt_id_t), 0);
EXPECT_EQ(expectedDefault(ompt_dispatch_t), 0);
EXPECT_EQ(expectedDefault(ompt_device_time_t), 0);
}
TEST(InternalUtility, ExpectedDefault_Nullpointer) {
// Expectedly nullptr
EXPECT_EQ(expectedDefault(const char *), nullptr);
EXPECT_EQ(expectedDefault(const void *), nullptr);
EXPECT_EQ(expectedDefault(int *), nullptr);
EXPECT_EQ(expectedDefault(void *), nullptr);
EXPECT_EQ(expectedDefault(ompt_data_t *), nullptr);
EXPECT_EQ(expectedDefault(ompt_device_t *), nullptr);
EXPECT_EQ(expectedDefault(ompt_frame_t *), nullptr);
EXPECT_EQ(expectedDefault(ompt_function_lookup_t), nullptr);
EXPECT_EQ(expectedDefault(ompt_id_t *), nullptr);
}
TEST(InternalUtility, MakeHexString_PointerValues) {
// IsPointer should only affect zero value
EXPECT_EQ(makeHexString(0, /*IsPointer=*/true), "(nil)");
EXPECT_EQ(makeHexString(0, /*IsPointer=*/false), "0x0");
EXPECT_EQ(makeHexString(255, /*IsPointer=*/true), "0xff");
EXPECT_EQ(makeHexString(255, /*IsPointer=*/false), "0xff");
}
TEST(InternalUtility, MakeHexString_MinimumBytes) {
// Return a minimum length, based on the (minimum) requested bytes
EXPECT_EQ(makeHexString(15, /*IsPointer=*/true, /*MinBytes=*/0), "0xf");
EXPECT_EQ(makeHexString(15, /*IsPointer=*/true, /*MinBytes=*/1), "0x0f");
EXPECT_EQ(makeHexString(255, /*IsPointer=*/true, /*MinBytes=*/0), "0xff");
EXPECT_EQ(makeHexString(255, /*IsPointer=*/true, /*MinBytes=*/1), "0xff");
EXPECT_EQ(makeHexString(255, /*IsPointer=*/true, /*MinBytes=*/2), "0x00ff");
EXPECT_EQ(makeHexString(255, /*IsPointer=*/true, /*MinBytes=*/3), "0x0000ff");
EXPECT_EQ(makeHexString(255, /*IsPointer=*/true, /*MinBytes=*/4),
"0x000000ff");
EXPECT_EQ(makeHexString(255, /*IsPointer=*/true, /*MinBytes=*/5),
"0x00000000ff");
EXPECT_EQ(makeHexString(255, /*IsPointer=*/true, /*MinBytes=*/6),
"0x0000000000ff");
EXPECT_EQ(makeHexString(255, /*IsPointer=*/true, /*MinBytes=*/7),
"0x000000000000ff");
EXPECT_EQ(makeHexString(255, /*IsPointer=*/true, /*MinBytes=*/8),
"0x00000000000000ff");
// Default to four bytes, if request exceeds eight byte range
EXPECT_EQ(makeHexString(255, /*IsPointer=*/true, /*MinBytes=*/9),
"0x000000ff");
// Disregard requested minimum byte width, if actual value exceeds it
EXPECT_EQ(makeHexString(1024, /*IsPointer=*/true, /*MinBytes=*/1), "0x400");
}
TEST(InternalUtility, MakeHexString_HexBase) {
// Cut off "0x" when requested
EXPECT_EQ(makeHexString(0, /*IsPointer=*/true, /*MinBytes=*/0,
/*ShowHexBase=*/false),
"(nil)");
EXPECT_EQ(makeHexString(0, /*IsPointer=*/false, /*MinBytes=*/0,
/*ShowHexBase=*/false),
"0");
EXPECT_EQ(makeHexString(0, /*IsPointer=*/false, /*MinBytes=*/1,
/*ShowHexBase=*/false),
"00");
EXPECT_EQ(makeHexString(255, /*IsPointer=*/true,
/*MinBytes=*/2,
/*ShowHexBase=*/false),
"00ff");
}

View File

@ -1,141 +0,0 @@
#include "OmptAssertEvent.h"
#include "OmptAsserter.h"
#include "OmptTester.h"
#include <omp-tools.h>
#include "gtest/gtest.h"
using OS = omptest::ObserveState;
using OAE = omptest::OmptAssertEvent;
TEST(CompareOperatorTests, ThreadBeginIdentity) {
auto TBInitial =
OAE::ThreadBegin("dflt", "", OS::Always, ompt_thread_initial);
auto TBWorker = OAE::ThreadBegin("dflt", "", OS::Always, ompt_thread_worker);
auto TBOther = OAE::ThreadBegin("dflt", "", OS::Always, ompt_thread_other);
auto TBUnknown =
OAE::ThreadBegin("dflt", "", OS::Always, ompt_thread_unknown);
ASSERT_EQ(TBInitial, TBInitial);
ASSERT_EQ(TBWorker, TBWorker);
ASSERT_EQ(TBOther, TBOther);
ASSERT_EQ(TBUnknown, TBUnknown);
}
TEST(CompareOperatorTests, ThreadEndIdentity) {
auto TE = OAE::ThreadEnd("dflt", "", OS::Always);
ASSERT_EQ(TE, TE);
}
TEST(CompareOperatorTests, ParallelBeginIdentity) {
auto PBNumT = OAE::ParallelBegin("thrdenable", "", OS::Always, 3);
ASSERT_EQ(PBNumT, PBNumT);
}
TEST(CompareOperatorTests, ParallelEndIdentity) {
auto PEDflt = OAE::ParallelEnd("dflt", "", OS::Always);
// TODO: Add cases with parallel data set, task data set, flags
ASSERT_EQ(PEDflt, PEDflt);
}
TEST(CompareOperatorTests, WorkIdentity) {
auto WDLoopBgn =
OAE::Work("loopbgn", "", OS::Always, ompt_work_loop, ompt_scope_begin);
auto WDLoopEnd =
OAE::Work("loopend", "", OS::Always, ompt_work_loop, ompt_scope_end);
ASSERT_EQ(WDLoopBgn, WDLoopBgn);
ASSERT_EQ(WDLoopEnd, WDLoopEnd);
auto WDSectionsBgn = OAE::Work("sectionsbgn", "", OS::Always,
ompt_work_sections, ompt_scope_begin);
auto WDSectionsEnd = OAE::Work("sectionsend", "", OS::Always,
ompt_work_sections, ompt_scope_end);
// TODO: singleexecutor, single_other, workshare, distribute, taskloop, scope,
// loop_static, loop_dynamic, loop_guided, loop_other
ASSERT_EQ(WDSectionsBgn, WDSectionsBgn);
ASSERT_EQ(WDSectionsEnd, WDSectionsEnd);
}
TEST(CompareOperatorTests, DispatchIdentity) {
auto DIDflt = OAE::Dispatch("dflt", "", OS::Always);
ASSERT_EQ(DIDflt, DIDflt);
}
TEST(CompareOperatorTests, TaskCreateIdentity) {
auto TCDflt = OAE::TaskCreate("dflt", "", OS::Always);
ASSERT_EQ(TCDflt, TCDflt);
}
TEST(CompareOperatorTests, TaskScheduleIdentity) {
auto TS = OAE::TaskSchedule("dflt", "", OS::Always);
ASSERT_EQ(TS, TS);
}
TEST(CompareOperatorTests, ImplicitTaskIdentity) {
auto ITDfltBgn =
OAE::ImplicitTask("dfltbgn", "", OS::Always, ompt_scope_begin);
auto ITDfltEnd = OAE::ImplicitTask("dfltend", "", OS::Always, ompt_scope_end);
ASSERT_EQ(ITDfltBgn, ITDfltBgn);
ASSERT_EQ(ITDfltEnd, ITDfltEnd);
}
TEST(CompareOperatorTests, SyncRegionIdentity) {
auto SRDfltBgn =
OAE::SyncRegion("srdfltbgn", "", OS::Always,
ompt_sync_region_barrier_explicit, ompt_scope_begin);
auto SRDfltEnd =
OAE::SyncRegion("srdfltend", "", OS::Always,
ompt_sync_region_barrier_explicit, ompt_scope_end);
ASSERT_EQ(SRDfltBgn, SRDfltBgn);
ASSERT_EQ(SRDfltEnd, SRDfltEnd);
}
TEST(CompareOperatorTests, TargetIdentity) {
auto TargetDfltBgn =
OAE::Target("dfltbgn", "", OS::Always, ompt_target, ompt_scope_begin);
auto TargetDfltEnd =
OAE::Target("dfltend", "", OS::Always, ompt_target, ompt_scope_end);
ASSERT_EQ(TargetDfltBgn, TargetDfltBgn);
ASSERT_EQ(TargetDfltEnd, TargetDfltEnd);
auto TargetDevBgn = OAE::Target("tgtdevbgn", "", OS::Always, ompt_target,
ompt_scope_begin, 1);
auto TargetDevEnd =
OAE::Target("tgtdevend", "", OS::Always, ompt_target, ompt_scope_end, 1);
ASSERT_EQ(TargetDevBgn, TargetDevBgn);
ASSERT_EQ(TargetDevEnd, TargetDevEnd);
}
TEST(CompareOperatorTests, BufferRecordIdentity) {
// Default, no time limit or anything
auto BRDflt =
OAE::BufferRecord("dflt", "", OS::Always, ompt_callback_target_submit);
// Minimum time set, no max time
auto BRMinSet = OAE::BufferRecord("minset", "", OS::Always,
ompt_callback_target_submit, 10);
// Minimum time and maximum time set
auto BRMinMaxSet = OAE::BufferRecord("minmaxset", "", OS::Always,
ompt_callback_target_submit, {10, 100});
ASSERT_EQ(BRDflt, BRDflt);
ASSERT_EQ(BRMinSet, BRMinSet);
ASSERT_EQ(BRMinMaxSet, BRMinMaxSet);
}
// Add main definition
OMPTEST_TESTSUITE_MAIN()

View File

@ -1,13 +1,10 @@
set(ORC_RT_HEADERS
orc-rt-c/ExternC.h
orc-rt-c/WrapperFunctionResult.h
orc-rt-c/orc-rt.h
orc-rt/BitmaskEnum.h
orc-rt/Compiler.h
orc-rt/Error.h
orc-rt/Math.h
orc-rt/RTTI.h
orc-rt/WrapperFunctionResult.h
orc-rt/move_only_function.h
orc-rt/span.h
)

View File

@ -1,41 +0,0 @@
/*===- ExternC.h - C API for the ORC runtime ----------------------*- 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 *|
|* *|
|*===----------------------------------------------------------------------===*|
|* *|
|* This file defines the C API for the ORC runtime *|
|* *|
\*===----------------------------------------------------------------------===*/
#ifndef ORC_RT_C_EXTERNC_H
#define ORC_RT_C_EXTERNC_H
/* Helper to suppress strict prototype warnings. */
#ifdef __clang__
#define ORC_RT_C_STRICT_PROTOTYPES_BEGIN \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic error \"-Wstrict-prototypes\"")
#define ORC_RT_C_STRICT_PROTOTYPES_END _Pragma("clang diagnostic pop")
#else
#define ORC_RT_C_STRICT_PROTOTYPES_BEGIN
#define ORC_RT_C_STRICT_PROTOTYPES_END
#endif
/* Helper to wrap C code for C++ */
#ifdef __cplusplus
#define ORC_RT_C_EXTERN_C_BEGIN \
extern "C" { \
ORC_RT_C_STRICT_PROTOTYPES_BEGIN
#define ORC_RT_C_EXTERN_C_END \
ORC_RT_C_STRICT_PROTOTYPES_END \
}
#else
#define ORC_RT_C_EXTERN_C_BEGIN ORC_RT_C_STRICT_PROTOTYPES_BEGIN
#define ORC_RT_C_EXTERN_C_END ORC_RT_C_STRICT_PROTOTYPES_END
#endif
#endif /* ORC_RT_C_EXTERNC_H */

View File

@ -1,178 +0,0 @@
/*===----- WrapperFunctionResult.h - blob-of-bytes container -----*- 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 *|
|* *|
|*===----------------------------------------------------------------------===*|
|* *|
|* Defines orc_rt_WrapperFunctionResult and related APIs. *|
|* *|
\*===----------------------------------------------------------------------===*/
#ifndef ORC_RT_C_WRAPPERFUNCTIONRESULT_H
#define ORC_RT_C_WRAPPERFUNCTIONRESULT_H
#include "orc-rt-c/ExternC.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
ORC_RT_C_EXTERN_C_BEGIN
typedef union {
char *ValuePtr;
char Value[sizeof(char *)];
} orc_rt_WrapperFunctionResultDataUnion;
/**
* orc_rt_WrapperFunctionResult is a kind of C-SmallVector with an
* out-of-band error state.
*
* If Size == 0 and Data.ValuePtr is non-zero then the value is in the
* 'out-of-band error' state, and Data.ValuePtr points at a malloc-allocated,
* null-terminated string error message.
*
* If Size <= sizeof(orc_rt_WrapperFunctionResultData) then the value is in
* the 'small' state and the content is held in the first Size bytes of
* Data.Value.
*
* If Size > sizeof(orc_rt_WrapperFunctionResultData) then the value is in the
* 'large' state and the content is held in the first Size bytes of the
* memory pointed to by Data.ValuePtr. This memory must have been allocated by
* malloc, and will be freed with free when this value is destroyed.
*/
typedef struct {
orc_rt_WrapperFunctionResultDataUnion Data;
size_t Size;
} orc_rt_WrapperFunctionResult;
/**
* Zero-initialize an orc_rt_WrapperFunctionResult.
*/
static inline void
orc_rt_WrapperFunctionResultInit(orc_rt_WrapperFunctionResult *R) {
R->Size = 0;
R->Data.ValuePtr = 0;
}
/**
* Create an orc_rt_WrapperFunctionResult with an uninitialized buffer of
* size Size. The buffer is returned via the DataPtr argument.
*/
static inline orc_rt_WrapperFunctionResult
orc_rt_WrapperFunctionResultAllocate(size_t Size) {
orc_rt_WrapperFunctionResult R;
R.Size = Size;
// If Size is 0 ValuePtr must be 0 or it is considered an out-of-band error.
R.Data.ValuePtr = 0;
if (Size > sizeof(R.Data.Value))
R.Data.ValuePtr = (char *)malloc(Size);
return R;
}
/**
* Create an orc_rt_WrapperFunctionResult from the given data range.
*/
static inline orc_rt_WrapperFunctionResult
orc_rt_CreateWrapperFunctionResultFromRange(const char *Data, size_t Size) {
orc_rt_WrapperFunctionResult R;
R.Size = Size;
if (R.Size > sizeof(R.Data.Value)) {
char *Tmp = (char *)malloc(Size);
memcpy(Tmp, Data, Size);
R.Data.ValuePtr = Tmp;
} else
memcpy(R.Data.Value, Data, Size);
return R;
}
/**
* Create an orc_rt_WrapperFunctionResult by copying the given string,
* including the null-terminator.
*
* This function copies the input string. The client is responsible for freeing
* the ErrMsg arg.
*/
static inline orc_rt_WrapperFunctionResult
orc_rt_CreateWrapperFunctionResultFromString(const char *Source) {
return orc_rt_CreateWrapperFunctionResultFromRange(Source,
strlen(Source) + 1);
}
/**
* Create an orc_rt_WrapperFunctionResult representing an out-of-band
* error.
*
* This function copies the input string. The client is responsible for freeing
* the ErrMsg arg.
*/
static inline orc_rt_WrapperFunctionResult
orc_rt_CreateWrapperFunctionResultFromOutOfBandError(const char *ErrMsg) {
orc_rt_WrapperFunctionResult R;
R.Size = 0;
char *Tmp = (char *)malloc(strlen(ErrMsg) + 1);
strcpy(Tmp, ErrMsg);
R.Data.ValuePtr = Tmp;
return R;
}
/**
* This should be called to destroy orc_rt_WrapperFunctionResult values
* regardless of their state.
*/
static inline void
orc_rt_DisposeWrapperFunctionResult(orc_rt_WrapperFunctionResult *R) {
if (R->Size > sizeof(R->Data.Value) || (R->Size == 0 && R->Data.ValuePtr))
free(R->Data.ValuePtr);
}
/**
* Get a pointer to the data contained in the given
* orc_rt_WrapperFunctionResult.
*/
static inline char *
orc_rt_WrapperFunctionResultData(orc_rt_WrapperFunctionResult *R) {
assert((R->Size != 0 || R->Data.ValuePtr == NULL) &&
"Cannot get data for out-of-band error value");
return R->Size > sizeof(R->Data.Value) ? R->Data.ValuePtr : R->Data.Value;
}
/**
* Safely get the size of the given orc_rt_WrapperFunctionResult.
*
* Asserts that we're not trying to access the size of an error value.
*/
static inline size_t
orc_rt_WrapperFunctionResultSize(const orc_rt_WrapperFunctionResult *R) {
assert((R->Size != 0 || R->Data.ValuePtr == NULL) &&
"Cannot get size for out-of-band error value");
return R->Size;
}
/**
* Returns 1 if this value is equivalent to a value just initialized by
* orc_rt_WrapperFunctionResultInit, 0 otherwise.
*/
static inline size_t
orc_rt_WrapperFunctionResultEmpty(const orc_rt_WrapperFunctionResult *R) {
return R->Size == 0 && R->Data.ValuePtr == 0;
}
/**
* Returns a pointer to the out-of-band error string for this
* orc_rt_WrapperFunctionResult, or null if there is no error.
*
* The orc_rt_WrapperFunctionResult retains ownership of the error
* string, so it should be copied if the caller wishes to preserve it.
*/
static inline const char *orc_rt_WrapperFunctionResultGetOutOfBandError(
const orc_rt_WrapperFunctionResult *R) {
return R->Size == 0 ? R->Data.ValuePtr : 0;
}
ORC_RT_C_EXTERN_C_END
#endif /* ORC_RT_WRAPPERFUNCTIONRESULT_H */

View File

@ -1,106 +0,0 @@
//===---- WrapperFunctionResult.h -- blob-of-bytes container ----*- 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
//
//===----------------------------------------------------------------------===//
//
// Defines WrapperFunctionResult and related APIs.
//
//===----------------------------------------------------------------------===//
#ifndef ORC_RT_WRAPPERFUNCTIONRESULT_H
#define ORC_RT_WRAPPERFUNCTIONRESULT_H
#include "orc-rt-c/WrapperFunctionResult.h"
#include <utility>
namespace orc_rt {
/// A C++ convenience wrapper for orc_rt_WrapperFunctionResult. Auto-disposes
/// the contained result on destruction.
class WrapperFunctionResult {
public:
/// Create a default WrapperFunctionResult.
WrapperFunctionResult() { orc_rt_WrapperFunctionResultInit(&R); }
/// Create a WrapperFunctionResult from a WrapperFunctionResult. This
/// instance takes ownership of the result object and will automatically
/// call dispose on the result upon destruction.
WrapperFunctionResult(orc_rt_WrapperFunctionResult R) : R(R) {}
WrapperFunctionResult(const WrapperFunctionResult &) = delete;
WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
WrapperFunctionResult(WrapperFunctionResult &&Other) {
orc_rt_WrapperFunctionResultInit(&R);
std::swap(R, Other.R);
}
WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
orc_rt_WrapperFunctionResult Tmp;
orc_rt_WrapperFunctionResultInit(&Tmp);
std::swap(Tmp, Other.R);
std::swap(R, Tmp);
return *this;
}
~WrapperFunctionResult() { orc_rt_DisposeWrapperFunctionResult(&R); }
/// Relinquish ownership of and return the
/// orc_rt_WrapperFunctionResult.
orc_rt_WrapperFunctionResult release() {
orc_rt_WrapperFunctionResult Tmp;
orc_rt_WrapperFunctionResultInit(&Tmp);
std::swap(R, Tmp);
return Tmp;
}
/// Get a pointer to the data contained in this instance.
char *data() { return orc_rt_WrapperFunctionResultData(&R); }
/// Returns the size of the data contained in this instance.
size_t size() const { return orc_rt_WrapperFunctionResultSize(&R); }
/// Returns true if this value is equivalent to a default-constructed
/// WrapperFunctionResult.
bool empty() const { return orc_rt_WrapperFunctionResultEmpty(&R); }
/// Create a WrapperFunctionResult with the given size and return a pointer
/// to the underlying memory.
static WrapperFunctionResult allocate(size_t Size) {
WrapperFunctionResult R;
R.R = orc_rt_WrapperFunctionResultAllocate(Size);
return R;
}
/// Copy from the given char range.
static WrapperFunctionResult copyFrom(const char *Source, size_t Size) {
return orc_rt_CreateWrapperFunctionResultFromRange(Source, Size);
}
/// Copy from the given null-terminated string (includes the null-terminator).
static WrapperFunctionResult copyFrom(const char *Source) {
return orc_rt_CreateWrapperFunctionResultFromString(Source);
}
/// Create an out-of-band error by copying the given string.
static WrapperFunctionResult createOutOfBandError(const char *Msg) {
return orc_rt_CreateWrapperFunctionResultFromOutOfBandError(Msg);
}
/// If this value is an out-of-band error then this returns the error message,
/// otherwise returns nullptr.
const char *getOutOfBandError() const {
return orc_rt_WrapperFunctionResultGetOutOfBandError(&R);
}
private:
orc_rt_WrapperFunctionResult R;
};
} // namespace orc_rt
#endif // ORC_RT_WRAPPERFUNCTIONRESULT_H

View File

@ -16,7 +16,6 @@ add_orc_rt_unittest(CoreTests
ErrorTest.cpp
MathTest.cpp
RTTITest.cpp
WrapperFunctionResultTest.cpp
move_only_function-test.cpp
span-test.cpp
DISABLE_LLVM_LINK_LLVM_DYLIB

View File

@ -1,60 +0,0 @@
//===-- wrapper_function_utils_test.cpp -----------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file is a part of the ORC runtime.
//
//===----------------------------------------------------------------------===//
#include "orc-rt-c/WrapperFunctionResult.h"
#include "orc-rt/WrapperFunctionResult.h"
#include "gtest/gtest.h"
using namespace orc_rt;
namespace {
constexpr const char *TestString = "test string";
} // end anonymous namespace
TEST(WrapperFunctionUtilsTest, DefaultWrapperFunctionResult) {
WrapperFunctionResult R;
EXPECT_TRUE(R.empty());
EXPECT_EQ(R.size(), 0U);
EXPECT_EQ(R.getOutOfBandError(), nullptr);
}
TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCStruct) {
orc_rt_WrapperFunctionResult CR =
orc_rt_CreateWrapperFunctionResultFromString(TestString);
WrapperFunctionResult R(CR);
EXPECT_EQ(R.size(), strlen(TestString) + 1);
EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
EXPECT_FALSE(R.empty());
EXPECT_EQ(R.getOutOfBandError(), nullptr);
}
TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromRange) {
auto R = WrapperFunctionResult::copyFrom(TestString, strlen(TestString) + 1);
EXPECT_EQ(R.size(), strlen(TestString) + 1);
EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
EXPECT_FALSE(R.empty());
EXPECT_EQ(R.getOutOfBandError(), nullptr);
}
TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCString) {
auto R = WrapperFunctionResult::copyFrom(TestString);
EXPECT_EQ(R.size(), strlen(TestString) + 1);
EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
EXPECT_FALSE(R.empty());
EXPECT_EQ(R.getOutOfBandError(), nullptr);
}
TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromOutOfBandError) {
auto R = WrapperFunctionResult::createOutOfBandError(TestString);
EXPECT_FALSE(R.empty());
EXPECT_TRUE(strcmp(R.getOutOfBandError(), TestString) == 0);
}