Skip to content

Commit 283073a

Browse files
tovinkereKseniyaTikhomirovaagainull
authored
[SYCL][XPTI] Refactoring framework to use 128-bit keys for collision elimination (#14467)
Previous implementation of the XPTI framework used 64-bit hash values to represent trace points in the code and this has led to a few of hash collisions.This refactoring moves to a 128-bit key to guarantee uniqueness. The changes needed to SYCL runtime to fully migrate to newer APIs will be pushed as a **separate Part 2 pull request**. Current pull request include changes to the XPTI framework and minor changes to SYCL runtime to reflect the transition to 128-bit keys and ensure validity of the tests. - 128-bit keys for internal storage and lookups - Support 64-bit universal IDs for backward compatibility - Updated tests to handle legacy API and new APIs for correctness tests - Updated performance tests to report metrics for both 64-bit and 28-bit native APIs - Updated SYCL instrumentation to return a new trace event for each instance of a trace point. Earlier implementation always returned the same trace event for a give trace point as the metadata associated with a trace event was deemed to be invariant. However, with the need for mutable metadata, this change is required. - Minor updates to documentation **NOTE**: Since more events are generated due to the creation of a new trace event for each trace point instance, some tests that rely on event sequences may have to be updated. --------- Signed-off-by: Vasanth Tovinkere <[email protected]> Signed-off-by: Tikhomirova, Kseniya <[email protected]> Co-authored-by: Tikhomirova, Kseniya <[email protected]> Co-authored-by: Artur Gainullin <[email protected]>
1 parent f995f55 commit 283073a

28 files changed

+6375
-1036
lines changed

sycl/doc/design/SYCLInstrumentationUsingXPTI.md

+77-77
Large diffs are not rendered by default.

sycl/source/detail/event_impl.cpp

+13-7
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,6 @@ void *event_impl::instrumentationProlog(std::string &Name, int32_t StreamID,
178178
constexpr uint16_t NotificationTraceType = xpti::trace_wait_begin;
179179
if (!xptiCheckTraceEnabled(StreamID, NotificationTraceType))
180180
return TraceEvent;
181-
// Use a thread-safe counter to get a unique instance ID for the wait() on the
182-
// event
183-
static std::atomic<uint64_t> InstanceID = {1};
184181
xpti::trace_event_data_t *WaitEvent = nullptr;
185182

186183
// Create a string with the event address so it
@@ -195,11 +192,20 @@ void *event_impl::instrumentationProlog(std::string &Name, int32_t StreamID,
195192
Command *Cmd = (Command *)MCommand;
196193
WaitEvent = Cmd->MTraceEvent ? static_cast<xpti_td *>(Cmd->MTraceEvent)
197194
: GSYCLGraphEvent;
198-
} else
199-
WaitEvent = GSYCLGraphEvent;
200-
195+
} else {
196+
// If queue.wait() is used, we want to make sure the information about the
197+
// queue is available with the wait events. We check to see if the
198+
// TraceEvent is available in the Queue object.
199+
void *TraceEvent = nullptr;
200+
if (QueueImplPtr Queue = MQueue.lock()) {
201+
TraceEvent = Queue->getTraceEvent();
202+
WaitEvent =
203+
(TraceEvent ? static_cast<xpti_td *>(TraceEvent) : GSYCLGraphEvent);
204+
} else
205+
WaitEvent = GSYCLGraphEvent;
206+
}
201207
// Record the current instance ID for use by Epilog
202-
IId = InstanceID++;
208+
IId = xptiGetUniqueId();
203209
xptiNotifySubscribers(StreamID, NotificationTraceType, nullptr, WaitEvent,
204210
IId, static_cast<const void *>(Name.c_str()));
205211
TraceEvent = (void *)WaitEvent;

sycl/source/detail/queue_impl.cpp

+60-2
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ event queue_impl::memset(const std::shared_ptr<detail::queue_impl> &Self,
154154
// information
155155
XPTIScope PrepareNotify((void *)this,
156156
(uint16_t)xpti::trace_point_type_t::node_create,
157-
SYCL_STREAM_NAME, "memory_transfer_node");
157+
SYCL_STREAM_NAME, "memory_transfer_node::memset");
158158
PrepareNotify.addMetadata([&](auto TEvent) {
159159
xpti::addMetadata(TEvent, "sycl_device",
160160
reinterpret_cast<size_t>(MDevice->getHandleRef()));
@@ -202,7 +202,7 @@ event queue_impl::memcpy(const std::shared_ptr<detail::queue_impl> &Self,
202202
// pointer.
203203
XPTIScope PrepareNotify((void *)this,
204204
(uint16_t)xpti::trace_point_type_t::node_create,
205-
SYCL_STREAM_NAME, "memory_transfer_node");
205+
SYCL_STREAM_NAME, "memory_transfer_node::memcpy");
206206
PrepareNotify.addMetadata([&](auto TEvent) {
207207
xpti::addMetadata(TEvent, "sycl_device",
208208
reinterpret_cast<size_t>(MDevice->getHandleRef()));
@@ -631,6 +631,64 @@ void queue_impl::wait(const detail::code_location &CodeLoc) {
631631
#endif
632632
}
633633

634+
void queue_impl::constructorNotification() {
635+
#if XPTI_ENABLE_INSTRUMENTATION
636+
if (xptiTraceEnabled()) {
637+
MStreamID = xptiRegisterStream(SYCL_STREAM_NAME);
638+
constexpr uint16_t NotificationTraceType =
639+
static_cast<uint16_t>(xpti::trace_point_type_t::queue_create);
640+
if (xptiCheckTraceEnabled(MStreamID, NotificationTraceType)) {
641+
xpti::utils::StringHelper SH;
642+
std::string AddrStr = SH.addressAsString<size_t>(MQueueID);
643+
std::string QueueName = SH.nameWithAddressString("queue", AddrStr);
644+
// Create a payload for the queue create event as we do not get code
645+
// location for the queue create event
646+
xpti::payload_t QPayload(QueueName.c_str());
647+
MInstanceID = xptiGetUniqueId();
648+
uint64_t RetInstanceNo;
649+
xpti_td *TEvent =
650+
xptiMakeEvent("queue_create", &QPayload,
651+
(uint16_t)xpti::trace_event_type_t::algorithm,
652+
xpti_at::active, &RetInstanceNo);
653+
// Cache the trace event, stream id and instance IDs for the destructor
654+
MTraceEvent = (void *)TEvent;
655+
656+
xpti::addMetadata(TEvent, "sycl_context",
657+
reinterpret_cast<size_t>(MContext->getHandleRef()));
658+
if (MDevice) {
659+
xpti::addMetadata(TEvent, "sycl_device_name", MDevice->getDeviceName());
660+
xpti::addMetadata(TEvent, "sycl_device",
661+
reinterpret_cast<size_t>(MDevice->getHandleRef()));
662+
}
663+
xpti::addMetadata(TEvent, "is_inorder", MIsInorder);
664+
xpti::addMetadata(TEvent, "queue_id", MQueueID);
665+
xpti::addMetadata(TEvent, "queue_handle",
666+
reinterpret_cast<size_t>(getHandleRef()));
667+
// Also publish to TLS before notification
668+
xpti::framework::stash_tuple(XPTI_QUEUE_INSTANCE_ID_KEY, MQueueID);
669+
xptiNotifySubscribers(
670+
MStreamID, (uint16_t)xpti::trace_point_type_t::queue_create, nullptr,
671+
TEvent, MInstanceID, static_cast<const void *>("queue_create"));
672+
}
673+
}
674+
#endif
675+
}
676+
677+
void queue_impl::destructorNotification() {
678+
#if XPTI_ENABLE_INSTRUMENTATION
679+
constexpr uint16_t NotificationTraceType =
680+
static_cast<uint16_t>(xpti::trace_point_type_t::queue_destroy);
681+
if (xptiCheckTraceEnabled(MStreamID, NotificationTraceType)) {
682+
// Use the cached trace event, stream id and instance IDs for the
683+
// destructor
684+
xptiNotifySubscribers(MStreamID, NotificationTraceType, nullptr,
685+
(xpti::trace_event_data_t *)MTraceEvent, MInstanceID,
686+
static_cast<const void *>("queue_destroy"));
687+
xptiReleaseEvent((xpti::trace_event_data_t *)MTraceEvent);
688+
}
689+
#endif
690+
}
691+
634692
ur_native_handle_t queue_impl::getNative(int32_t &NativeHandleDesc) const {
635693
const PluginPtr &Plugin = getPlugin();
636694
if (getContextImplPtr()->getBackend() == backend::opencl)

sycl/source/detail/queue_impl.hpp

+21-73
Original file line numberDiff line numberDiff line change
@@ -173,37 +173,10 @@ class queue_impl {
173173
// We enable XPTI tracing events using the TLS mechanism; if the code
174174
// location data is available, then the tracing data will be rich.
175175
#if XPTI_ENABLE_INSTRUMENTATION
176-
constexpr uint16_t NotificationTraceType =
177-
static_cast<uint16_t>(xpti::trace_point_type_t::queue_create);
178-
// Using the instance override constructor for use with queues as queues
179-
// maintain instance IDs in the object
180-
XPTIScope PrepareNotify((void *)this, NotificationTraceType,
181-
SYCL_STREAM_NAME, MQueueID, "queue_create");
182-
// Cache the trace event, stream id and instance IDs for the destructor
183-
if (xptiCheckTraceEnabled(PrepareNotify.streamID(),
184-
NotificationTraceType)) {
185-
MTraceEvent = (void *)PrepareNotify.traceEvent();
186-
MStreamID = PrepareNotify.streamID();
187-
MInstanceID = PrepareNotify.instanceID();
188-
// Add the function to capture meta data for the XPTI trace event
189-
PrepareNotify.addMetadata([&](auto TEvent) {
190-
xpti::addMetadata(TEvent, "sycl_context",
191-
reinterpret_cast<size_t>(MContext->getHandleRef()));
192-
if (MDevice) {
193-
xpti::addMetadata(TEvent, "sycl_device_name",
194-
MDevice->getDeviceName());
195-
xpti::addMetadata(TEvent, "sycl_device",
196-
reinterpret_cast<size_t>(MDevice->getHandleRef()));
197-
}
198-
xpti::addMetadata(TEvent, "is_inorder", MIsInorder);
199-
xpti::addMetadata(TEvent, "queue_id", MQueueID);
200-
xpti::addMetadata(TEvent, "queue_handle",
201-
reinterpret_cast<size_t>(getHandleRef()));
202-
});
203-
// Also publish to TLS
204-
xpti::framework::stash_tuple(XPTI_QUEUE_INSTANCE_ID_KEY, MQueueID);
205-
PrepareNotify.notify();
206-
}
176+
// Emit a trace event for queue creation; we currently do not get code
177+
// location information, so all queueus will have the same UID with a
178+
// different instance ID until this gets added.
179+
constructorNotification();
207180
#endif
208181
}
209182

@@ -236,35 +209,10 @@ class queue_impl {
236209
// is the prolog section and the epilog section will initiate the
237210
// notification.
238211
#if XPTI_ENABLE_INSTRUMENTATION
239-
constexpr uint16_t NotificationTraceType =
240-
static_cast<uint16_t>(xpti::trace_point_type_t::queue_create);
241-
XPTIScope PrepareNotify((void *)this, NotificationTraceType,
242-
SYCL_STREAM_NAME, MQueueID, "queue_create");
243-
if (xptiCheckTraceEnabled(PrepareNotify.streamID(),
244-
NotificationTraceType)) {
245-
// Cache the trace event, stream id and instance IDs for the destructor
246-
MTraceEvent = (void *)PrepareNotify.traceEvent();
247-
MStreamID = PrepareNotify.streamID();
248-
MInstanceID = PrepareNotify.instanceID();
249-
250-
// Add the function to capture meta data for the XPTI trace event
251-
PrepareNotify.addMetadata([&](auto TEvent) {
252-
xpti::addMetadata(TEvent, "sycl_context",
253-
reinterpret_cast<size_t>(MContext->getHandleRef()));
254-
if (MDevice) {
255-
xpti::addMetadata(TEvent, "sycl_device_name",
256-
MDevice->getDeviceName());
257-
xpti::addMetadata(TEvent, "sycl_device",
258-
reinterpret_cast<size_t>(MDevice->getHandleRef()));
259-
}
260-
xpti::addMetadata(TEvent, "is_inorder", MIsInorder);
261-
xpti::addMetadata(TEvent, "queue_id", MQueueID);
262-
xpti::addMetadata(TEvent, "queue_handle", getHandleRef());
263-
});
264-
// Also publish to TLS before notification
265-
xpti::framework::stash_tuple(XPTI_QUEUE_INSTANCE_ID_KEY, MQueueID);
266-
PrepareNotify.notify();
267-
}
212+
// Emit a trace event for queue creation; we currently do not get code
213+
// location information, so all queueus will have the same UID with a
214+
// different instance ID until this gets added.
215+
constructorNotification();
268216
#endif
269217
}
270218

@@ -306,20 +254,11 @@ class queue_impl {
306254

307255
~queue_impl() {
308256
try {
309-
// The trace event created in the constructor should be active through the
310-
// lifetime of the queue object as member variables when ABI breakage is
311-
// allowed. This example shows MTraceEvent as a member variable.
312257
#if XPTI_ENABLE_INSTRUMENTATION
313-
constexpr uint16_t NotificationTraceType =
314-
static_cast<uint16_t>(xpti::trace_point_type_t::queue_destroy);
315-
if (xptiCheckTraceEnabled(MStreamID, NotificationTraceType)) {
316-
// Used cached information in member variables
317-
xptiNotifySubscribers(MStreamID, NotificationTraceType, nullptr,
318-
(xpti::trace_event_data_t *)MTraceEvent,
319-
MInstanceID,
320-
static_cast<const void *>("queue_destroy"));
321-
xptiReleaseEvent((xpti::trace_event_data_t *)MTraceEvent);
322-
}
258+
// The trace event created in the constructor should be active through the
259+
// lifetime of the queue object as member variable. We will send a
260+
// notification and destroy the trace event for this queue.
261+
destructorNotification();
323262
#endif
324263
throw_asynchronous();
325264
cleanup_fusion_cmd();
@@ -748,6 +687,8 @@ class queue_impl {
748687

749688
unsigned long long getQueueID() { return MQueueID; }
750689

690+
void *getTraceEvent() { return MTraceEvent; }
691+
751692
void setExternalEvent(const event &Event) {
752693
std::lock_guard<std::mutex> Lock(MInOrderExternalEventMtx);
753694
MInOrderExternalEvent = Event;
@@ -937,6 +878,13 @@ class queue_impl {
937878
void instrumentationEpilog(void *TelementryEvent, std::string &Name,
938879
int32_t StreamID, uint64_t IId);
939880

881+
// We need to emit a queue_create notification when a queue object is created
882+
void constructorNotification();
883+
884+
// We need to emit a queue_destroy notification when a queue object is
885+
// destroyed
886+
void destructorNotification();
887+
940888
/// queue_impl.addEvent tracks events with weak pointers
941889
/// but some events have no other owners. addSharedEvent()
942890
/// follows events with a shared pointer.

0 commit comments

Comments
 (0)