diff --git a/sycl/doc/SYCLInstrumentationUsingXPTI.md b/sycl/doc/SYCLInstrumentationUsingXPTI.md index 89a7a89137f0b..76f363bf9ecf9 100644 --- a/sycl/doc/SYCLInstrumentationUsingXPTI.md +++ b/sycl/doc/SYCLInstrumentationUsingXPTI.md @@ -256,3 +256,12 @@ All trace point types in bold provide semantic information about the graph, node | `wait_end` |
  • **trace_type**: `xpti::trace_point_type_t::wait_end` that marks the beginning of the wait on an `event`
  • **parent**: `nullptr`
  • **event**: The event ID will reflect the ID of the command group object submission that created this event or a new event based on the combination of the string "queue.wait" and the address of the event.
  • **instance**: Unique ID to allow the correlation of the `wait_begin` event with the `wait_end` event.
  • **user_data**: String indicating `queue.wait` and the address of the event as `const char *`
  • | **`sycl_device`**, `sym_function_name`, `sym_source_file_name`, `sym_line_no` | | `barrier_begin` |
  • **trace_type**: `xpti::trace_point_type_t::barrier_begin` that marks the beginning of a barrier while enqueuing a command group object
  • **parent**: The global graph event that is created during the `graph_create` event.
  • **event**: The event ID will reflect the ID of the command group object that has encountered a barrier during the enqueue operation.
  • **instance**: Unique ID to allow the correlation of the `barrier_begin` event with the `barrier_end` event.
  • **user_data**: String indicating `enqueue.barrier` and the reason for the barrier as a `const char *`
  • The reason for the barrier could be one of `Buffer locked by host accessor`, `Blocked by host task` or `Unknown reason`.
    |
  • Computational Kernels
  • `sycl_device`, `kernel_name`, `from_source`, `sym_function_name`, `sym_source_file_name`, `sym_line_no`
  • Memory operations
  • `memory_object`, `offset`, `access_range`, `allocation_type`, `copy_from`, `copy_to` | | `barrier_end` |
  • **trace_type**: `xpti::trace_point_type_t::barrier_end` that marks the end of the barrier that is encountered during enqueue.
  • **parent**: The global graph event that is created during the `graph_create` event.
  • **event**: The event ID will reflect the ID of the command group object that has encountered a barrier during the enqueue operation.
  • **instance**: Unique ID to allow the correlation of the `barrier_begin` event with the `barrier_end` event.
  • **user_data**: String indicating `enqueue.barrier` and the reason for the barrier as a `const char *`
  • The reason for the barrier could be one of `Buffer locked by host accessor`, `Blocked by host task` or `Unknown reason`.
    |
  • Computational Kernels
  • `sycl_device`, `kernel_name`, `from_source`, `sym_function_name`, `sym_source_file_name`, `sym_line_no`
  • Memory operations
  • `memory_object`, `offset`, `access_range`, `allocation_type`, `copy_from`, `copy_to` | + +## Level Zero Plugin Stream `"oneapi.level_zero.experimental.mem_alloc"` Notification Signatures + +| Trace Point Type | Parameter Description | Metadata | +| :------------------------: | :-------------------- | :------- | +| `mem_alloc_begin` |
  • **trace_type**: `xpti::trace_point_type_t::mem_alloc_begin` that marks the beginning of memory allocation process
  • **parent**: Event ID created for all functions in the `oneapi.level_zero.experimental.mem_alloc` layer.
  • **event**: `nullptr` - since the stream of data just captures functions being called.
  • **instance**: Unique ID to allow the correlation of the `mem_alloc_begin` event with the `mem_alloc_end` event.
  • **user_data**: A pointer to `mem_alloc_data_t` object, that includes memory object ID (if any), allocation size, and guard zone size (if any).
  • | None | +| `mem_alloc_end` |
  • **trace_type**: `xpti::trace_point_type_t::mem_alloc_end` that marks the end of memory allocation process
  • **parent**: Event ID created for all functions in the `oneapi.level_zero.experimental.mem_alloc` layer.
  • **event**: `nullptr` - since the stream of data just captures functions being called.
  • **instance**: Unique ID to allow the correlation of the `mem_alloc_begin` event with the `mem_alloc_end` event. This value is guaranteed to be the same value received by the trace event for the corresponding `mem_alloc_begin`.
  • **user_data**: A pointer to `mem_alloc_data_t` object, that includes memory object ID (if any), allocated pointer, allocation size, and guard zone size (if any).
  • | None | +| `mem_release_begin` |
  • **trace_type**: `xpti::trace_point_type_t::mem_release_begin` that marks the beginning of memory allocation process
  • **parent**: Event ID created for all functions in the `oneapi.level_zero.experimental.mem_alloc` layer.
  • **event**: `nullptr` - since the stream of data just captures functions being called.
  • **instance**: Unique ID to allow the correlation of the `mem_release_begin` event with the `mem_release_end` event.
  • **user_data**: A pointer to `mem_alloc_data_t` object, that includes memory object ID (if any) and released pointer.
  • | None | +| `mem_release_end` |
  • **trace_type**: `xpti::trace_point_type_t::mem_release_end` that marks the end of memory allocation process
  • **parent**: Event ID created for all functions in the `oneapi.level_zero.experimental.mem_alloc` layer.
  • **event**: `nullptr` - since the stream of data just captures functions being called.
  • **instance**: Unique ID to allow the correlation of the `mem_release_begin` event with the `mem_release_end` event. This value is guaranteed to be the same value received by the trace event for the corresponding `mem_release_begin`.
  • **user_data**: A pointer to `mem_alloc_data_t` object, that includes memory object ID (if any) and released pointer.
  • | None | diff --git a/sycl/source/detail/device_image_impl.hpp b/sycl/source/detail/device_image_impl.hpp index c038031201705..d37944d0978d9 100644 --- a/sycl/source/detail/device_image_impl.hpp +++ b/sycl/source/detail/device_image_impl.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -185,11 +186,11 @@ class device_image_impl { std::lock_guard Lock{MSpecConstAccessMtx}; if (nullptr == MSpecConstsBuffer && !MSpecConstsBlob.empty()) { const detail::plugin &Plugin = getSyclObjImpl(MContext)->getPlugin(); - Plugin.call( - detail::getSyclObjImpl(MContext)->getHandleRef(), - PI_MEM_FLAGS_ACCESS_RW | PI_MEM_FLAGS_HOST_PTR_USE, - MSpecConstsBlob.size(), MSpecConstsBlob.data(), &MSpecConstsBuffer, - nullptr); + memBufferCreateHelper(Plugin, + detail::getSyclObjImpl(MContext)->getHandleRef(), + PI_MEM_FLAGS_ACCESS_RW | PI_MEM_FLAGS_HOST_PTR_USE, + MSpecConstsBlob.size(), MSpecConstsBlob.data(), + &MSpecConstsBuffer, nullptr); } return MSpecConstsBuffer; } diff --git a/sycl/source/detail/mem_alloc_helper.hpp b/sycl/source/detail/mem_alloc_helper.hpp new file mode 100644 index 0000000000000..0cbc8c4bada86 --- /dev/null +++ b/sycl/source/detail/mem_alloc_helper.hpp @@ -0,0 +1,32 @@ +//==-------- mem_alloc_helper.hpp - SYCL mem alloc helper ------------------==// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include + +__SYCL_INLINE_NAMESPACE(cl) { +namespace sycl { +namespace detail { +void memBufferCreateHelper(const plugin &Plugin, pi_context Ctx, + pi_mem_flags Flags, size_t Size, void *HostPtr, + pi_mem *RetMem, + const pi_mem_properties *Props = nullptr); +void memReleaseHelper(const plugin &Plugin, pi_mem Mem); +void memBufferMapHelper(const plugin &Plugin, pi_queue command_queue, + pi_mem buffer, pi_bool blocking_map, + pi_map_flags map_flags, size_t offset, size_t size, + pi_uint32 num_events_in_wait_list, + const pi_event *event_wait_list, pi_event *event, + void **ret_map); +void memUnmapHelper(const plugin &Plugin, pi_queue command_queue, pi_mem memobj, + void *mapped_ptr, pi_uint32 num_events_in_wait_list, + const pi_event *event_wait_list, pi_event *event); +} // namespace detail +} // namespace sycl +} // __SYCL_INLINE_NAMESPACE(cl) diff --git a/sycl/source/detail/memory_manager.cpp b/sycl/source/detail/memory_manager.cpp index 67c308ba4c8ff..bd54884200f4f 100644 --- a/sycl/source/detail/memory_manager.cpp +++ b/sycl/source/detail/memory_manager.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -16,10 +17,98 @@ #include #include +#ifdef XPTI_ENABLE_INSTRUMENTATION +#include +#include +#endif + __SYCL_INLINE_NAMESPACE(cl) { namespace sycl { namespace detail { +#ifdef XPTI_ENABLE_INSTRUMENTATION +uint8_t GMemAllocStreamID; +xpti::trace_event_data_t *GMemAllocEvent; +#endif + +uint64_t emitMemAllocBeginTrace(uintptr_t ObjHandle, size_t AllocSize, + size_t GuardZone) { + (void)ObjHandle; + (void)AllocSize; + (void)GuardZone; + uint64_t CorrelationID = 0; +#ifdef XPTI_ENABLE_INSTRUMENTATION + if (xptiTraceEnabled()) { + xpti::mem_alloc_data_t MemAlloc{ObjHandle, 0 /* alloc ptr */, AllocSize, + GuardZone}; + + CorrelationID = xptiGetUniqueId(); + xptiNotifySubscribers( + GMemAllocStreamID, + static_cast(xpti::trace_point_type_t::mem_alloc_begin), + GMemAllocEvent, nullptr, CorrelationID, &MemAlloc); + } +#endif + return CorrelationID; +} + +void emitMemAllocEndTrace(uintptr_t ObjHandle, uintptr_t AllocPtr, + size_t AllocSize, size_t GuardZone, + uint64_t CorrelationID) { + (void)ObjHandle; + (void)AllocPtr; + (void)AllocSize; + (void)GuardZone; + (void)CorrelationID; +#ifdef XPTI_ENABLE_INSTRUMENTATION + if (xptiTraceEnabled()) { + xpti::mem_alloc_data_t MemAlloc{ObjHandle, AllocPtr, AllocSize, GuardZone}; + + xptiNotifySubscribers( + GMemAllocStreamID, + static_cast(xpti::trace_point_type_t::mem_alloc_end), + GMemAllocEvent, nullptr, CorrelationID, &MemAlloc); + } +#endif +} + +uint64_t emitMemReleaseBeginTrace(uintptr_t ObjHandle, uintptr_t AllocPtr) { + (void)ObjHandle; + (void)AllocPtr; +#ifdef XPTI_ENABLE_INSTRUMENTATION + uint64_t CorrelationID = 0; + if (xptiTraceEnabled()) { + xpti::mem_alloc_data_t MemAlloc{ObjHandle, AllocPtr, 0 /* alloc size */, + 0 /* guard zone */}; + + CorrelationID = xptiGetUniqueId(); + xptiNotifySubscribers( + GMemAllocStreamID, + static_cast(xpti::trace_point_type_t::mem_release_begin), + GMemAllocEvent, nullptr, CorrelationID, &MemAlloc); + } +#endif + return CorrelationID; +} + +void emitMemReleaseEndTrace(uintptr_t ObjHandle, uintptr_t AllocPtr, + uint64_t CorrelationID) { + (void)ObjHandle; + (void)AllocPtr; + (void)CorrelationID; +#ifdef XPTI_ENABLE_INSTRUMENTATION + if (xptiTraceEnabled()) { + xpti::mem_alloc_data_t MemAlloc{ObjHandle, AllocPtr, 0 /* alloc size */, + 0 /* guard zone */}; + + xptiNotifySubscribers( + GMemAllocStreamID, + static_cast(xpti::trace_point_type_t::mem_release_end), + GMemAllocEvent, nullptr, CorrelationID, &MemAlloc); + } +#endif +} + static void waitForEvents(const std::vector &Events) { // Assuming all events will be on the same device or // devices associated with the same Backend. @@ -34,6 +123,97 @@ static void waitForEvents(const std::vector &Events) { } } +void memBufferCreateHelper(const plugin &Plugin, pi_context Ctx, + pi_mem_flags Flags, size_t Size, void *HostPtr, + pi_mem *RetMem, const pi_mem_properties *Props) { + uint64_t CorrID = 0; + // We only want to instrument piMemBufferCreate + { + CorrID = + emitMemAllocBeginTrace(0 /* mem object */, Size, 0 /* guard zone */); + xpti::utils::finally _{[&] { + // C-style cast is required for MSVC + uintptr_t MemObjID = (uintptr_t)(*RetMem); + pi_native_handle Ptr = 0; + // Always use call_nocheck here, because call may throw an exception, + // and this lambda will be called from destructor, which in combination + // rewards us with UB. + Plugin.call_nocheck(*RetMem, &Ptr); + emitMemAllocEndTrace(MemObjID, (uintptr_t)(Ptr), Size, 0 /* guard zone */, + CorrID); + }}; + Plugin.call(Ctx, Flags, Size, HostPtr, RetMem, + Props); + } +} + +void memReleaseHelper(const plugin &Plugin, pi_mem Mem) { + // FIXME piMemRelease does not guarante memory release. It is only true if + // reference counter is 1. However, SYCL runtime currently only calls + // piMemRetain only for OpenCL interop + uint64_t CorrID = 0; + // C-style cast is required for MSVC + uintptr_t MemObjID = (uintptr_t)(Mem); + uintptr_t Ptr = 0; + // Do not make unnecessary PI calls without instrumentation enabled + if (xptiTraceEnabled()) { + pi_native_handle PtrHandle = 0; + Plugin.call(Mem, &PtrHandle); + Ptr = (uintptr_t)(PtrHandle); + } + // We only want to instrument piMemRelease + { + CorrID = emitMemReleaseBeginTrace(MemObjID, Ptr); + xpti::utils::finally _{ + [&] { emitMemReleaseEndTrace(MemObjID, Ptr, CorrID); }}; + Plugin.call(Mem); + } +} + +void memBufferMapHelper(const plugin &Plugin, pi_queue Queue, pi_mem Buffer, + pi_bool Blocking, pi_map_flags Flags, size_t Offset, + size_t Size, pi_uint32 NumEvents, + const pi_event *WaitList, pi_event *Event, + void **RetMap) { + uint64_t CorrID = 0; + uintptr_t MemObjID = (uintptr_t)(Buffer); + // We only want to instrument piEnqueueMemBufferMap + { + CorrID = emitMemAllocBeginTrace(MemObjID, Size, 0 /* guard zone */); + xpti::utils::finally _{[&] { + emitMemAllocEndTrace(MemObjID, (uintptr_t)(*RetMap), Size, + 0 /* guard zone */, CorrID); + }}; + Plugin.call( + Queue, Buffer, Blocking, Flags, Offset, Size, NumEvents, WaitList, + Event, RetMap); + } +} + +void memUnmapHelper(const plugin &Plugin, pi_queue Queue, pi_mem Mem, + void *MappedPtr, pi_uint32 NumEvents, + const pi_event *WaitList, pi_event *Event) { + uint64_t CorrID = 0; + uintptr_t MemObjID = (uintptr_t)(Mem); + uintptr_t Ptr = (uintptr_t)(MappedPtr); + // We only want to instrument piEnqueueMemUnmap + { + CorrID = emitMemReleaseBeginTrace(MemObjID, Ptr); + xpti::utils::finally _{[&] { + // There's no way for SYCL to know, when the pointer is freed, so we have + // to explicitly wait for the end of data transfers here in order to + // report correct events. + // Always use call_nocheck here, because call may throw an exception, + // and this lambda will be called from destructor, which in combination + // rewards us with UB. + Plugin.call_nocheck(1, Event); + emitMemReleaseEndTrace(MemObjID, Ptr, CorrID); + }}; + Plugin.call(Queue, Mem, MappedPtr, NumEvents, + WaitList, Event); + } +} + void MemoryManager::release(ContextImplPtr TargetContext, SYCLMemObjI *MemObj, void *MemAllocation, std::vector DepEvents, @@ -67,7 +247,7 @@ void MemoryManager::releaseMemObj(ContextImplPtr TargetContext, } const detail::plugin &Plugin = TargetContext->getPlugin(); - Plugin.call(pi::cast(MemAllocation)); + memReleaseHelper(Plugin, pi::cast(MemAllocation)); } void *MemoryManager::allocate(ContextImplPtr TargetContext, SYCLMemObjI *MemObj, @@ -165,9 +345,8 @@ MemoryManager::allocateBufferObject(ContextImplPtr TargetContext, void *UserPtr, RT::PiMem NewMem = nullptr; const detail::plugin &Plugin = TargetContext->getPlugin(); - Plugin.call(TargetContext->getHandleRef(), - CreationFlags, Size, UserPtr, - &NewMem, nullptr); + memBufferCreateHelper(Plugin, TargetContext->getHandleRef(), CreationFlags, + Size, UserPtr, &NewMem, nullptr); return NewMem; } @@ -623,10 +802,9 @@ void *MemoryManager::map(SYCLMemObjI *, void *Mem, QueueImplPtr Queue, void *MappedPtr = nullptr; const size_t BytesToMap = AccessRange[0] * AccessRange[1] * AccessRange[2]; const detail::plugin &Plugin = Queue->getPlugin(); - Plugin.call( - Queue->getHandleRef(), pi::cast(Mem), CL_FALSE, Flags, - AccessOffset[0], BytesToMap, DepEvents.size(), DepEvents.data(), - &OutEvent, &MappedPtr); + memBufferMapHelper(Plugin, Queue->getHandleRef(), pi::cast(Mem), + CL_FALSE, Flags, AccessOffset[0], BytesToMap, + DepEvents.size(), DepEvents.data(), &OutEvent, &MappedPtr); return MappedPtr; } @@ -639,9 +817,8 @@ void MemoryManager::unmap(SYCLMemObjI *, void *Mem, QueueImplPtr Queue, // Using the plugin of the Queue. const detail::plugin &Plugin = Queue->getPlugin(); - Plugin.call( - Queue->getHandleRef(), pi::cast(Mem), MappedPtr, - DepEvents.size(), DepEvents.data(), &OutEvent); + memUnmapHelper(Plugin, Queue->getHandleRef(), pi::cast(Mem), + MappedPtr, DepEvents.size(), DepEvents.data(), &OutEvent); } void MemoryManager::copy_usm(const void *SrcMem, QueueImplPtr SrcQueue, diff --git a/sycl/source/detail/xpti_registry.hpp b/sycl/source/detail/xpti_registry.hpp index f82a000b1378b..0ed5fd3fc96b8 100644 --- a/sycl/source/detail/xpti_registry.hpp +++ b/sycl/source/detail/xpti_registry.hpp @@ -29,12 +29,30 @@ inline constexpr const char *SYCL_PICALL_STREAM_NAME = "sycl.pi"; // Stream name being used for traces generated from PI calls. This stream // contains information about function arguments. inline constexpr const char *SYCL_PIDEBUGCALL_STREAM_NAME = "sycl.pi.debug"; +inline constexpr auto SYCL_MEM_ALLOC_STREAM_NAME = + "sycl.experimental.mem_alloc"; + +#ifdef XPTI_ENABLE_INSTRUMENTATION +extern uint8_t GMemAllocStreamID; +extern xpti::trace_event_data_t *GMemAllocEvent; +#endif class XPTIRegistry { public: void initializeFrameworkOnce() { #ifdef XPTI_ENABLE_INSTRUMENTATION - std::call_once(MInitialized, [] { xptiFrameworkInitialize(); }); + std::call_once(MInitialized, [this] { + xptiFrameworkInitialize(); + + // Memory allocation events + GMemAllocStreamID = xptiRegisterStream(SYCL_MEM_ALLOC_STREAM_NAME); + initializeStream(SYCL_MEM_ALLOC_STREAM_NAME, 0, 1, "0.1"); + xpti::payload_t MAPayload("SYCL Memory Allocations Layer"); + uint64_t MAInstanceNo = 0; + GMemAllocEvent = xptiMakeEvent("SYCL Memory Allocations", &MAPayload, + xpti::trace_algorithm_event, + xpti_at::active, &MAInstanceNo); + }); #endif } diff --git a/xpti/include/xpti/xpti_data_types.h b/xpti/include/xpti/xpti_data_types.h index 5dfed90dd23c0..caa8e445fc58b 100644 --- a/xpti/include/xpti/xpti_data_types.h +++ b/xpti/include/xpti/xpti_data_types.h @@ -370,6 +370,14 @@ enum class trace_point_type_t : uint16_t { function_with_args_begin = XPTI_TRACE_POINT_BEGIN(14), /// Used to trace function call end. function_with_args_end = XPTI_TRACE_POINT_END(15), + /// Used to notify that a new memory allocation is about to start. + mem_alloc_begin = XPTI_TRACE_POINT_BEGIN(16), + /// Used to notify that a memory allocation took place. + mem_alloc_end = XPTI_TRACE_POINT_END(17), + /// Used to notify that memory chunk will be released. + mem_release_begin = XPTI_TRACE_POINT_BEGIN(18), + /// Used to notify that memory has been released. + mem_release_end = XPTI_TRACE_POINT_END(19), /// Indicates that the trace point is user defined and only the tool defined /// for a stream will be able to handle it user_defined = 1 << 7 @@ -493,6 +501,29 @@ struct trace_event_data_t { void *global_user_data = nullptr; }; +/// Describes memory allocation +struct mem_alloc_data_t { + /// A platform-specific memory object handle. Some heterogeneous programming + /// models (like OpenCL and SYCL) have notion of memory objects, that are + /// universal across host and all devices. In such models, for each device a + /// new device-specific allocation must take place. This handle can be used to + /// tie different allocations across devices to their runtime-managed memory + /// objects. + uintptr_t mem_object_handle = 0; + /// A pointer to allocated piece of memory. + uintptr_t alloc_pointer = 0; + /// Size of memory allocation in bytes. + size_t alloc_size = 0; + /// Size of guard zone in bytes. Some analysis tools can ask allocators to add + /// some extra space in the end of memory allocation to catch out-of-bounds + /// memory accesses. Allocators, however, must honor rules of the programming + /// model when allocating memory. This value can be used to indicate the real + /// guard zone size, that has been used to perform allocation. + size_t guard_zone_size = 0; + /// Reserved for future needs + void *reserved = nullptr; +}; + /// /// The error code list is incomplete and still /// being defined. diff --git a/xpti/include/xpti/xpti_trace_framework.hpp b/xpti/include/xpti/xpti_trace_framework.hpp index a86d024a32aac..fcd4c80c4668f 100644 --- a/xpti/include/xpti/xpti_trace_framework.hpp +++ b/xpti/include/xpti/xpti_trace_framework.hpp @@ -288,6 +288,21 @@ class SpinLock { private: std::atomic_flag MLock = ATOMIC_FLAG_INIT; }; + +/// RAII-like helper to call a function upon exit from the scope. +/// +/// This can be used to ensure that a specific XPTI API is called even if an +/// exception is thrown on code path. For convenience the function will only be +/// invoked if instrumentation is enabled. +struct finally { + std::function MFunc; + + ~finally() { + if (xptiTraceEnabled()) + MFunc(); + } +}; + } // namespace utils namespace framework { diff --git a/xptifw/src/xpti_trace_framework.cpp b/xptifw/src/xpti_trace_framework.cpp index f8af4f56c5a3f..e1e259acbde05 100644 --- a/xptifw/src/xpti_trace_framework.cpp +++ b/xptifw/src/xpti_trace_framework.cpp @@ -7,6 +7,8 @@ #include "xpti_int64_hash_table.hpp" #include "xpti_string_table.hpp" +#include +#include #include #include #include @@ -939,13 +941,20 @@ class Framework { // have 'nullptr' for both the Parent and Object only if UserData is // provided and the trace_point_type is function_begin/function_end. // This allows us to trace function calls without too much effort. + std::array AllowedTypes = { + trace_point_type_t::function_begin, + trace_point_type_t::function_end, + trace_point_type_t::function_with_args_begin, + trace_point_type_t::function_with_args_end, + trace_point_type_t::mem_alloc_begin, + trace_point_type_t::mem_alloc_end, + trace_point_type_t::mem_release_begin, + trace_point_type_t::mem_release_end}; + const auto Predicate = [TraceType](trace_point_type_t RHS) { + return TraceType == static_cast(RHS); + }; if (!(UserData && - (TraceType == (uint16_t)trace_point_type_t::function_begin || - TraceType == (uint16_t)trace_point_type_t::function_end || - TraceType == - (uint16_t)trace_point_type_t::function_with_args_begin || - TraceType == - (uint16_t)trace_point_type_t::function_with_args_end))) { + std::any_of(AllowedTypes.begin(), AllowedTypes.end(), Predicate))) { return xpti::result_t::XPTI_RESULT_INVALIDARG; } } diff --git a/xptifw/unit_test/xpti_api_tests.cpp b/xptifw/unit_test/xpti_api_tests.cpp index bca3cfb0e0b96..6b3622c745bdf 100644 --- a/xptifw/unit_test/xpti_api_tests.cpp +++ b/xptifw/unit_test/xpti_api_tests.cpp @@ -254,6 +254,25 @@ TEST_F(xptiApiTest, xptiRegisterCallbackGoodInput) { StreamID, (uint16_t)xpti::trace_point_type_t::function_begin, fn_callback); EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); + + Result = xptiRegisterCallback( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_alloc_begin, + fn_callback); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); + + Result = xptiRegisterCallback( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_alloc_end, fn_callback); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); + + Result = xptiRegisterCallback( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_release_begin, + fn_callback); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); + + Result = xptiRegisterCallback( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_release_end, + fn_callback); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); } TEST_F(xptiApiTest, xptiUnregisterCallbackBadInput) { @@ -295,6 +314,26 @@ TEST_F(xptiApiTest, xptiNotifySubscribersBadInput) { StreamID, (uint16_t)xpti::trace_point_type_t::function_begin, nullptr, nullptr, 0, nullptr); EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_INVALIDARG); + + Result = xptiNotifySubscribers( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_alloc_begin, nullptr, + nullptr, 0, nullptr); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_INVALIDARG); + + Result = xptiNotifySubscribers( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_alloc_end, nullptr, + nullptr, 0, nullptr); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_INVALIDARG); + + Result = xptiNotifySubscribers( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_release_begin, nullptr, + nullptr, 0, nullptr); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_INVALIDARG); + + Result = xptiNotifySubscribers( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_release_end, nullptr, + nullptr, 0, nullptr); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_INVALIDARG); } TEST_F(xptiApiTest, xptiNotifySubscribersGoodInput) { @@ -331,6 +370,49 @@ TEST_F(xptiApiTest, xptiNotifySubscribersGoodInput) { (xpti::trace_event_data_t *)1, 0, "foo"); EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); EXPECT_NE(tmp, func_callback_update); + + Result = xptiRegisterCallback( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_alloc_begin, + fn_callback); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); + Result = xptiRegisterCallback( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_alloc_end, fn_callback); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); + Result = xptiRegisterCallback( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_release_begin, + fn_callback); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); + Result = xptiRegisterCallback( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_release_end, + fn_callback); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); + + xpti::mem_alloc_data_t AllocData{10, 100, 1, 0}; + + tmp = func_callback_update; + Result = xptiNotifySubscribers( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_alloc_begin, nullptr, + nullptr, 0, &AllocData); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); + EXPECT_NE(tmp, func_callback_update); + tmp = func_callback_update; + Result = xptiNotifySubscribers( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_alloc_end, nullptr, + (xpti::trace_event_data_t *)1, 0, &AllocData); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); + EXPECT_NE(tmp, func_callback_update); + + Result = xptiNotifySubscribers( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_release_begin, nullptr, + nullptr, 0, &AllocData); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); + EXPECT_NE(tmp, func_callback_update); + tmp = func_callback_update; + Result = xptiNotifySubscribers( + StreamID, (uint16_t)xpti::trace_point_type_t::mem_release_end, nullptr, + (xpti::trace_event_data_t *)1, 0, &AllocData); + EXPECT_EQ(Result, xpti::result_t::XPTI_RESULT_SUCCESS); + EXPECT_NE(tmp, func_callback_update); } TEST_F(xptiApiTest, xptiAddMetadataBadInput) {