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) {