Skip to content

Commit 77d9dfb

Browse files
authored
[SYCL][PI][XPTI] Instrumenting PI Layer API - Part I (#1655)
+ Added new trace point type 'function_begin/function_end' to support pure API tracing without having to create a trace event. + PI Layer API tracing enabled using function_begin/end + xptiNotifySubscribers() behaves differently when the tracepoint type is function_begin/end and requires the per_instance_user_data field to be valid with a function name. + Updated XPTI API documentation to reflect this change and added additional tests to test xptiNotifySubscribers Signed-off-by: Vasanth Tovinkere <[email protected]>
1 parent 98119bd commit 77d9dfb

File tree

15 files changed

+319
-26
lines changed

15 files changed

+319
-26
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,4 @@ sycl/doc/ @pvchupin @kbobrovs
8585
sycl/doc/extensions/ @mkinsner @jbrodman
8686

8787
xpti/ @tovinkere @andykaylor
88+
xptifw/ @tovinkere @andykaylor

sycl/include/CL/sycl/detail/common.hpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,13 @@
2727
__SYCL_INLINE_NAMESPACE(cl) {
2828
namespace sycl {
2929
namespace detail {
30-
// We define a sycl stream name and this will
31-
// be used by the instrumentation framework
30+
// We define a sycl stream name and this will be used by the instrumentation
31+
// framework
3232
constexpr const char *SYCL_STREAM_NAME = "sycl";
33-
// Data structure that captures the user code
34-
// location information using the builtin capabilities
35-
// of the compiler
33+
// Stream name being used for traces generated from the SYCL plugin layer
34+
constexpr const char *SYCL_PICALL_STREAM_NAME = "sycl.pi";
35+
// Data structure that captures the user code location information using the
36+
// builtin capabilities of the compiler
3637
struct code_location {
3738
#ifdef _MSC_VER
3839
// Since MSVC does not support the required builtins, we

sycl/include/CL/sycl/detail/pi.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,18 @@ template <PiApiKind PiApiOffset> struct PiFuncInfo {};
150150
};
151151
#include <CL/sycl/detail/pi.def>
152152

153+
/// Emits an XPTI trace before a PI API call is made
154+
/// \param FName The name of the PI API call
155+
/// \return The correlation ID for the API call that is to be used by the
156+
/// emitFunctionEndTrace() call
157+
uint64_t emitFunctionBeginTrace(const char *FName);
158+
159+
/// Emits an XPTI trace after the PI API call has been made
160+
/// \param CorrelationID The correlation ID for the API call generated by the
161+
/// emitFunctionBeginTrace() call.
162+
/// \param FName The name of the PI API call
163+
void emitFunctionEndTrace(uint64_t CorrelationID, const char *FName);
164+
153165
// Helper utilities for PI Tracing
154166
// The run-time tracing of PI calls.
155167
// Print functions used by Trace class.

sycl/source/detail/pi.cpp

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,84 @@ __SYCL_INLINE_NAMESPACE(cl) {
3737
namespace sycl {
3838
namespace detail {
3939
#ifdef XPTI_ENABLE_INSTRUMENTATION
40-
// Stream name being used for traces generated from the SYCL runtime
41-
constexpr const char *PICALL_STREAM_NAME = "sycl.pi";
4240
// Global (to the SYCL runtime) graph handle that all command groups are a
4341
// child of
44-
///< Event to be used by graph related activities
42+
/// Event to be used by graph related activities
4543
xpti_td *GSYCLGraphEvent = nullptr;
46-
///< Event to be used by PI layer related activities
44+
/// Event to be used by PI layer related activities
4745
xpti_td *GPICallEvent = nullptr;
48-
///< Constansts being used as placeholder until one is able to reliably get the
49-
///< version of the SYCL runtime
46+
/// Constants being used as placeholder until one is able to reliably get the
47+
/// version of the SYCL runtime
5048
constexpr uint32_t GMajVer = 1;
5149
constexpr uint32_t GMinVer = 0;
5250
constexpr const char *GVerStr = "sycl 1.0";
53-
#endif
51+
#endif // XPTI_ENABLE_INSTRUMENTATION
5452

5553
namespace pi {
5654

5755
bool XPTIInitDone = false;
5856

57+
// Implementation of the SYCL PI API call tracing methods that use XPTI
58+
// framework to emit these traces that will be used by tools.
59+
uint64_t emitFunctionBeginTrace(const char *FName) {
60+
uint64_t CorrelationID = 0;
61+
#ifdef XPTI_ENABLE_INSTRUMENTATION
62+
// The function_begin and function_end trace point types are defined to
63+
// trace library API calls and they are currently enabled here for support
64+
// tools that need the API scope. The methods emitFunctionBeginTrace() and
65+
// emitFunctionEndTrace() can be extended to also trace the arguments of the
66+
// PI API call using a trace point type the extends the predefined trace
67+
// point types.
68+
//
69+
// You can use the sample collector in llvm/xptifw/samples/syclpi_collector
70+
// to print the API traces and also extend them to support arguments that
71+
// may be traced later.
72+
//
73+
/// Example Usage:
74+
/// \code{cpp}
75+
/// // Two diagnostic trace types defined for function begin and function end
76+
/// // with different semantics than the one in the default trace type list.
77+
/// typedef enum {
78+
/// diagnostic_func_begin = XPTI_TRACE_POINT_BEGIN(0),
79+
/// diagnostic_func_end = XPTI_TRACE_POINT_END(0),
80+
/// }syclpi_extension_t;
81+
/// ...
82+
/// uint16_t pi_func_begin =
83+
/// xptiRegisterUserDefinedTracePoint("sycl.pi", func_begin);
84+
/// uint16_t pi_func_end =
85+
/// xptiRegisterUserDefinedTracePoint("sycl.pi", func_end);
86+
/// ...
87+
/// // Setup argument data for the function being traced
88+
/// ...
89+
/// xptiNotifySubscribers(stream_id, pi_func_begin, parent, event, instance,
90+
/// (void *)argument_data);
91+
/// \endcode
92+
if (xptiTraceEnabled()) {
93+
uint8_t StreamID = xptiRegisterStream(SYCL_PICALL_STREAM_NAME);
94+
CorrelationID = xptiGetUniqueId();
95+
xptiNotifySubscribers(
96+
StreamID, (uint16_t)xpti::trace_point_type_t::function_begin,
97+
GPICallEvent, nullptr, CorrelationID, static_cast<const void *>(FName));
98+
}
99+
#endif // XPTI_ENABLE_INSTRUMENTATION
100+
return CorrelationID;
101+
}
102+
103+
void emitFunctionEndTrace(uint64_t CorrelationID, const char *FName) {
104+
#ifdef XPTI_ENABLE_INSTRUMENTATION
105+
if (xptiTraceEnabled()) {
106+
// CorrelationID is the unique ID that ties together a function_begin and
107+
// function_end pair of trace calls. The splitting of a scoped_notify into
108+
// two function calls incurs an additional overhead as the StreamID must
109+
// be looked up twice.
110+
uint8_t StreamID = xptiRegisterStream(SYCL_PICALL_STREAM_NAME);
111+
xptiNotifySubscribers(
112+
StreamID, (uint16_t)xpti::trace_point_type_t::function_end,
113+
GPICallEvent, nullptr, CorrelationID, static_cast<const void *>(FName));
114+
}
115+
#endif // XPTI_ENABLE_INSTRUMENTATION
116+
}
117+
59118
void contextSetExtendedDeleter(const cl::sycl::context &context,
60119
pi_context_extended_deleter func,
61120
void *user_data) {
@@ -285,6 +344,8 @@ vector_class<plugin> initialize() {
285344
GSYCLGraphEvent, GraphInstanceNo, nullptr);
286345
}
287346

347+
// Let subscribers know a new stream is being initialized
348+
xptiInitialize(SYCL_PICALL_STREAM_NAME, GMajVer, GMinVer, GVerStr);
288349
xpti::payload_t PIPayload("Plugin Interface Layer");
289350
uint64_t PiInstanceNo;
290351
GPICallEvent =

sycl/source/detail/plugin.hpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,17 @@
1212
#include <CL/sycl/detail/pi.hpp>
1313
#include <CL/sycl/stl.hpp>
1414

15+
#ifdef XPTI_ENABLE_INSTRUMENTATION
16+
// Include the headers necessary for emitting traces using the trace framework
17+
#include "xpti_trace_framework.h"
18+
#endif
19+
1520
__SYCL_INLINE_NAMESPACE(cl) {
1621
namespace sycl {
1722
namespace detail {
18-
23+
#ifdef XPTI_ENABLE_INSTRUMENTATION
24+
extern xpti::trace_event_data_t *GPICallEvent;
25+
#endif
1926
/// The plugin class provides a unified interface to the underlying low-level
2027
/// runtimes for the device-agnostic SYCL runtime.
2128
///
@@ -53,6 +60,13 @@ class plugin {
5360
template <PiApiKind PiApiOffset, typename... ArgsT>
5461
RT::PiResult call_nocheck(ArgsT... Args) const {
5562
RT::PiFuncInfo<PiApiOffset> PiCallInfo;
63+
#ifdef XPTI_ENABLE_INSTRUMENTATION
64+
// Emit a function_begin trace for the PI API before the call is executed.
65+
// If arguments need to be captured, then a data structure can be sent in
66+
// the per_instance_user_data field.
67+
std::string PIFnName = PiCallInfo.getFuncName();
68+
uint64_t CorrelationID = pi::emitFunctionBeginTrace(PIFnName.c_str());
69+
#endif
5670
if (pi::trace(pi::TraceLevel::PI_TRACE_CALLS)) {
5771
std::string FnName = PiCallInfo.getFuncName();
5872
std::cout << "---> " << FnName << "(" << std::endl;
@@ -63,6 +77,10 @@ class plugin {
6377
std::cout << ") ---> ";
6478
RT::printArgs(R);
6579
}
80+
#ifdef XPTI_ENABLE_INSTRUMENTATION
81+
// Close the function begin with a call to function end
82+
pi::emitFunctionEndTrace(CorrelationID, PIFnName.c_str());
83+
#endif
6684
return R;
6785
}
6886

xpti/include/xpti_data_types.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,15 @@ enum class trace_point_type_t : uint16_t {
246246
wait_begin = XPTI_TRACE_POINT_BEGIN(11),
247247
/// Models the explicit barrier end in SYCL
248248
wait_end = XPTI_TRACE_POINT_END(11),
249+
/// Used to trace function call begin, from libraries, for example. This trace
250+
/// point type does not require an event object for the parent or the event of
251+
/// interest, but information about the function being traced needs to be sent
252+
/// using the user_data parameter in the xptiNotifySubscribers() call.
253+
function_begin = XPTI_TRACE_POINT_BEGIN(12),
254+
/// Used to trace function call end
255+
function_end = XPTI_TRACE_POINT_END(12),
256+
/// Use to notify that a new metadata entry is available for a given event
257+
metadata = XPTI_TRACE_POINT_BEGIN(13),
249258
/// Indicates that the trace point is user defined and only the tool defined
250259
/// for a stream will be able to handle it
251260
user_defined = 1 << 7
@@ -363,7 +372,7 @@ struct trace_event_data_t {
363372
reserved_data_t reserved;
364373
/// User defined data, if required; owned by the user shared object and will
365374
/// not be deleted when event data is destroyed
366-
void *user_data = nullptr;
375+
void *global_user_data = nullptr;
367376
};
368377

369378
///

xpti/include/xpti_trace_framework.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ xptiRegisterCallback(uint8_t stream_id, uint16_t trace_type,
288288
/// 1. XPTI_RESULT_SUCCESS when the unregistration is successful
289289
/// 2. XPTI_RESULT_DUPLICATE when the callback function has already
290290
/// been disabled for the stream and trace point type
291-
/// 3. XPTI_RESULT_NOTFOUND if the callbackhas not been previously
291+
/// 3. XPTI_RESULT_NOTFOUND if the callback has not been previously
292292
/// registered.
293293
XPTI_EXPORT_API xpti::result_t
294294
xptiUnregisterCallback(uint8_t stream_id, uint16_t trace_type,
@@ -308,17 +308,27 @@ xptiUnregisterCallback(uint8_t stream_id, uint16_t trace_type,
308308
/// @param object The event object for which the notification must be sent out.
309309
/// @param instance The instance number of the current event and this value is
310310
/// guaranteed to be static for the duration of the callback handler.
311-
/// @param temporal_user_data This is the field where each tool can send in some
312-
/// state information and the handshake of the type of this data type must be
313-
/// handled by extending tracepoint types that handle diffent types od user
314-
/// data.
311+
/// @param per_instance_user_data This is the field where each tool can send in
312+
/// some state information and the handshake of the type of this data type must
313+
/// be handled by extending tracepoint types that handle diffent types of user
314+
/// data. If the trace type is function_begin/function_end, then the parent and
315+
/// object parameters can be null, but the per_instance_user_data must contain
316+
/// information about the function being traced (preferably the function name).
315317
/// @return The result code which can be one of:
316318
/// 1. XPTI_RESULT_SUCCESS when the notification is successful
319+
/// 2. XPTI_RESULT_FALSE when tracing is turned off
320+
/// 3. XPTI_RESULT_INVALIDARG when one or more input parameters are
321+
/// invalid. For example, for all trace types except function_begin
322+
/// and function_end, the event 'object' cannot be NULL. If a NULL
323+
/// value is provided for this parameter, you will see an
324+
/// XPTI_RESULT_INVALIDARG return value. Similarly, for
325+
/// function_begin and function_end, the per_instance_user_data value
326+
/// must be populated to not get this return value.
317327
XPTI_EXPORT_API xpti::result_t
318328
xptiNotifySubscribers(uint8_t stream_id, uint16_t trace_type,
319329
xpti::trace_event_data_t *parent,
320330
xpti::trace_event_data_t *object, uint64_t instance,
321-
const void *temporal_user_data);
331+
const void *per_instance_user_data);
322332

323333
/// @brief Associates <key-value> pairs with an event
324334
/// @details If the instrumentation embedded in applications need to send

xpti/include/xpti_trace_framework.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ class scoped_notify {
285285
const void *user_data = nullptr)
286286
: m_object(object), m_parent(parent), m_stream_id(0),
287287
m_trace_type(trace_type), m_user_data(user_data), m_instance(instance) {
288-
if (xptiTraceEnabled() && object) {
288+
if (xptiTraceEnabled()) {
289289
uint16_t open = m_trace_type & 0xfffe;
290290
m_stream_id = xptiRegisterStream(stream);
291291
xptiNotifySubscribers(m_stream_id, open, parent, object, instance,
@@ -294,7 +294,7 @@ class scoped_notify {
294294
}
295295

296296
~scoped_notify() {
297-
if (xptiTraceEnabled() && m_object) {
297+
if (xptiTraceEnabled()) {
298298
switch (m_trace_type) {
299299
case signal:
300300
case graph_create:

xptifw/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ include_directories(${CMAKE_SOURCE_DIR}/include ${XPTI_DIR}/include)
2424
add_subdirectory(src)
2525
add_subdirectory(unit_test)
2626
add_subdirectory(samples/basic_collector)
27+
add_subdirectory(samples/syclpi_collector)
2728
# The tests in basic_test are written using TBB, so these tests are enabled
2829
# only if TBB has been enabled.
2930
if (XPTI_ENABLE_TBB)

xptifw/doc/XPTI_Framework.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,12 @@ below.
269269
```
270270

271271
You can now run a SYCL application that has been linked with a runtime that
272-
supports the XPTI instrumentation and inspect the resulting stream.
272+
supports the XPTI instrumentation and inspect the resulting stream. An
273+
example collector that subscribes to a specific stream is also provided under
274+
`xptifw/samples/syclpi_collector`. This example demonstrates how a tool can
275+
selectively subscribe to a known stream and ignore all other traces. All
276+
trace notifications for the streams that have no callbacks registered will
277+
return immediately.
273278

274279
3. **Running the unit tests:** The unit tests included cover the exported API
275280
and incorporate some correctness tests.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
cmake_minimum_required(VERSION 2.8.9)
2+
project (syclpi_collector)
3+
4+
file(GLOB SOURCES *.cpp)
5+
include_directories(${XPTIFW_DIR}/include)
6+
include_directories(${XPTI_DIR}/include)
7+
include_directories(${XPTIFW_DIR}/samples/include)
8+
9+
remove_definitions(-DXPTI_STATIC_LIBRARY)
10+
add_definitions(-DXPTI_API_EXPORTS)
11+
add_library(syclpi_collector SHARED ${SOURCES})
12+
add_dependencies(syclpi_collector xptifw)
13+
target_link_libraries(syclpi_collector PRIVATE xptifw)
14+
if(UNIX)
15+
target_link_libraries(syclpi_collector PRIVATE dl)
16+
endif()
17+
18+
if (XPTI_ENABLE_TBB)
19+
target_link_libraries(syclpi_collector PRIVATE tbb)
20+
endif()
21+
# Set the location of the library installation
22+
install(TARGETS syclpi_collector DESTINATION ${CMAKE_BINARY_DIR})
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Example SYCL PI Layer Collector
2+
3+
The SYCL PI layer collector demonstrates the creation of a subscriber and prints
4+
of the data received from SYCL PI layer stream. In order to obtain the data from
5+
an application instrumented with XPTI, the following steps must be performed.
6+
7+
1. Set the environment variable that indicates that tracing has been enabled.
8+
9+
This is defined by the variable `XPTI_TRACE_ENABLE`. The possible
10+
values taken by this environment variable are:
11+
12+
To enable: `XPTI_TRACE_ENABLE=1` or `XPTI_TRACE_ENABLE=true`
13+
14+
To disable: `XPTI_TRACE_ENABLE=0` or `XPTI_TRACE_ENABLE=false`
15+
16+
2. Set the environment variable that points to the XPTI framework dispatcher so
17+
the stub library can dynamically load it and dispatch the calls to the
18+
dispatcher.
19+
`XPTI_FRAMEWORK_DISPATCHER=/path/to/libxptifw.[so,dll,dylib]`
20+
21+
3. Set the environment variable that points to the subscriber, which in this
22+
case is `libsyclpi_collector.[so,dll,dylib]`.
23+
24+
`XPTI_SUBSCRIBERS=/path/to/libsyclpi_collector.[so,dll,dylib]`
25+
26+
For more detail on the framework, the tests that are provided and their usage,
27+
please consult the [XPTI Framework library documentation](doc/XPTI_Framework.md).

0 commit comments

Comments
 (0)