Skip to content

Commit e239fdf

Browse files
author
Alexander Batashev
authored
[SYCL][XPTI] Enable PI calls notifications with arguments (#3973)
This PR adds capability to capture PI calls' arguments and pass this data to XPTI subscribers. The sample pi-trace library demonstrates how one can parse this data on the subscriber side. An example usage of this utility would be: ```bash XPTI_TRACE_ENABLE=1 XPTI_FRAMEWORK_DISPATCHER=lib/libxptifw.so XPTI_SUBSCRIBERS=lib/libpi_trace.so ./my_app ```
1 parent 8a757be commit e239fdf

File tree

14 files changed

+407
-1
lines changed

14 files changed

+407
-1
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ namespace detail {
3131
constexpr const char *SYCL_STREAM_NAME = "sycl";
3232
// Stream name being used for traces generated from the SYCL plugin layer
3333
constexpr const char *SYCL_PICALL_STREAM_NAME = "sycl.pi";
34+
// Stream name being used for traces generated from PI calls. This stream
35+
// contains information about function arguments.
36+
constexpr const char *SYCL_PIDEBUGCALL_STREAM_NAME = "sycl.pi.debug";
3437
// Data structure that captures the user code location information using the
3538
// builtin capabilities of the compiler
3639
struct code_location {

sycl/include/CL/sycl/detail/pi.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
// This is for convinience of doing same thing for all interfaces, e.g.
1515
// declare, define, initialize.
1616
//
17+
// This list is used to define PiApiKind enum, which is part of external
18+
// interface. To avoid ABI breakage, please, add new entries to the end of the
19+
// list.
20+
//
1721
// Platform
1822
_PI_API(piPlatformsGet)
1923
_PI_API(piPlatformGetInfo)

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,26 @@ uint64_t emitFunctionBeginTrace(const char *FName);
184184
/// \param FName The name of the PI API call
185185
void emitFunctionEndTrace(uint64_t CorrelationID, const char *FName);
186186

187+
/// Notifies XPTI subscribers about PI function calls and packs call arguments.
188+
///
189+
/// \param FuncID is the API hash ID from PiApiID type trait.
190+
/// \param FName The name of the PI API call.
191+
/// \param ArgsData is a pointer to packed function call arguments.
192+
uint64_t emitFunctionWithArgsBeginTrace(uint32_t FuncID, const char *FName,
193+
unsigned char *ArgsData);
194+
195+
/// Notifies XPTI subscribers about PI function call result.
196+
///
197+
/// \param CorrelationID The correlation ID for the API call generated by the
198+
/// emitFunctionWithArgsBeginTrace() call.
199+
/// \param FuncID is the API hash ID from PiApiID type trait.
200+
/// \param FName The name of the PI API call.
201+
/// \param ArgsData is a pointer to packed function call arguments.
202+
/// \param Result is function call result value.
203+
void emitFunctionWithArgsEndTrace(uint64_t CorrelationID, uint32_t FuncID,
204+
const char *FName, unsigned char *ArgsData,
205+
pi_result Result);
206+
187207
// A wrapper for passing around byte array properties
188208
class ByteArray {
189209
public:
@@ -393,3 +413,5 @@ namespace RT = cl::sycl::detail::pi;
393413

394414
} // namespace sycl
395415
} // __SYCL_INLINE_NAMESPACE(cl)
416+
417+
#undef _PI_API

sycl/include/CL/sycl/detail/type_traits.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <CL/sycl/detail/type_list.hpp>
1515

1616
#include <array>
17+
#include <tuple>
1718
#include <type_traits>
1819

1920
__SYCL_INLINE_NAMESPACE(cl) {
@@ -344,6 +345,12 @@ template <access::address_space AS, class DataT>
344345
using const_if_const_AS = DataT;
345346
#endif
346347

348+
template <typename T> struct function_traits {};
349+
350+
template <typename Ret, typename... Args> struct function_traits<Ret(Args...)> {
351+
using ret_type = Ret;
352+
using args_type = std::tuple<Args...>;
353+
};
347354

348355
} // namespace detail
349356
} // namespace sycl

sycl/source/detail/pi.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ namespace detail {
4646
xpti_td *GSYCLGraphEvent = nullptr;
4747
/// Event to be used by PI layer related activities
4848
xpti_td *GPICallEvent = nullptr;
49+
/// Event to be used by PI layer calls with arguments
50+
xpti_td *GPIArgCallEvent = nullptr;
4951
/// Constants being used as placeholder until one is able to reliably get the
5052
/// version of the SYCL runtime
5153
constexpr uint32_t GMajVer = 1;
@@ -135,6 +137,42 @@ void emitFunctionEndTrace(uint64_t CorrelationID, const char *FName) {
135137
#endif // XPTI_ENABLE_INSTRUMENTATION
136138
}
137139

140+
uint64_t emitFunctionWithArgsBeginTrace(uint32_t FuncID, const char *FuncName,
141+
unsigned char *ArgsData) {
142+
uint64_t CorrelationID = 0;
143+
#ifdef XPTI_ENABLE_INSTRUMENTATION
144+
if (xptiTraceEnabled()) {
145+
uint8_t StreamID = xptiRegisterStream(SYCL_PIDEBUGCALL_STREAM_NAME);
146+
CorrelationID = xptiGetUniqueId();
147+
148+
xpti::function_with_args_t Payload{FuncID, FuncName, ArgsData, nullptr,
149+
nullptr};
150+
151+
xptiNotifySubscribers(
152+
StreamID, (uint16_t)xpti::trace_point_type_t::function_with_args_begin,
153+
GPIArgCallEvent, nullptr, CorrelationID, &Payload);
154+
}
155+
#endif
156+
return CorrelationID;
157+
}
158+
159+
void emitFunctionWithArgsEndTrace(uint64_t CorrelationID, uint32_t FuncID,
160+
const char *FuncName, unsigned char *ArgsData,
161+
pi_result Result) {
162+
#ifdef XPTI_ENABLE_INSTRUMENTATION
163+
if (xptiTraceEnabled()) {
164+
uint8_t StreamID = xptiRegisterStream(SYCL_PIDEBUGCALL_STREAM_NAME);
165+
166+
xpti::function_with_args_t Payload{FuncID, FuncName, ArgsData, &Result,
167+
nullptr};
168+
169+
xptiNotifySubscribers(
170+
StreamID, (uint16_t)xpti::trace_point_type_t::function_with_args_end,
171+
GPIArgCallEvent, nullptr, CorrelationID, &Payload);
172+
}
173+
#endif
174+
}
175+
138176
void contextSetExtendedDeleter(const cl::sycl::context &context,
139177
pi_context_extended_deleter func,
140178
void *user_data) {
@@ -430,6 +468,14 @@ static void initializePlugins(std::vector<plugin> *Plugins) {
430468
GPICallEvent =
431469
xptiMakeEvent("PI Layer", &PIPayload, xpti::trace_algorithm_event,
432470
xpti_at::active, &PiInstanceNo);
471+
472+
xptiInitialize(SYCL_PIDEBUGCALL_STREAM_NAME, GMajVer, GMinVer, GVerStr);
473+
xpti::payload_t PIArgPayload(
474+
"Plugin Interface Layer (with function arguments)");
475+
uint64_t PiArgInstanceNo;
476+
GPIArgCallEvent = xptiMakeEvent("PI Layer with arguments", &PIArgPayload,
477+
xpti::trace_algorithm_event, xpti_at::active,
478+
&PiArgInstanceNo);
433479
#endif
434480
}
435481

sycl/source/detail/plugin.hpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <CL/sycl/backend_types.hpp>
1111
#include <CL/sycl/detail/common.hpp>
1212
#include <CL/sycl/detail/pi.hpp>
13+
#include <CL/sycl/detail/type_traits.hpp>
1314
#include <CL/sycl/stl.hpp>
1415
#include <detail/plugin_printers.hpp>
1516
#include <memory>
@@ -25,7 +26,62 @@ namespace sycl {
2526
namespace detail {
2627
#ifdef XPTI_ENABLE_INSTRUMENTATION
2728
extern xpti::trace_event_data_t *GPICallEvent;
29+
extern xpti::trace_event_data_t *GPIArgCallEvent;
2830
#endif
31+
32+
template <PiApiKind Kind, size_t Idx, typename... Args>
33+
struct array_fill_helper;
34+
35+
template <PiApiKind Kind> struct PiApiArgTuple;
36+
37+
#define _PI_API(api) \
38+
template <> struct PiApiArgTuple<PiApiKind::api> { \
39+
using type = typename function_traits<decltype(api)>::args_type; \
40+
};
41+
42+
#include <CL/sycl/detail/pi.def>
43+
#undef _PI_API
44+
45+
template <PiApiKind Kind, size_t Idx, typename T>
46+
struct array_fill_helper<Kind, Idx, T> {
47+
static void fill(unsigned char *Dst, T &&Arg) {
48+
using ArgsTuple = typename PiApiArgTuple<Kind>::type;
49+
// C-style cast is required here.
50+
auto RealArg = (std::tuple_element_t<Idx, ArgsTuple>)(Arg);
51+
*(std::remove_cv_t<std::tuple_element_t<Idx, ArgsTuple>> *)Dst = RealArg;
52+
}
53+
};
54+
55+
template <PiApiKind Kind, size_t Idx, typename T, typename... Args>
56+
struct array_fill_helper<Kind, Idx, T, Args...> {
57+
static void fill(unsigned char *Dst, const T &&Arg, Args &&... Rest) {
58+
using ArgsTuple = typename PiApiArgTuple<Kind>::type;
59+
// C-style cast is required here.
60+
auto RealArg = (std::tuple_element_t<Idx, ArgsTuple>)(Arg);
61+
*(std::remove_cv_t<std::tuple_element_t<Idx, ArgsTuple>> *)Dst = RealArg;
62+
array_fill_helper<Kind, Idx + 1, Args...>::fill(
63+
Dst + sizeof(decltype(RealArg)), std::forward<Args>(Rest)...);
64+
}
65+
};
66+
67+
template <typename... Ts>
68+
constexpr size_t totalSize(const std::tuple<Ts...> &) {
69+
return (sizeof(Ts) + ...);
70+
}
71+
72+
template <PiApiKind Kind, typename... ArgsT>
73+
auto packCallArguments(ArgsT &&... Args) {
74+
using ArgsTuple = typename PiApiArgTuple<Kind>::type;
75+
76+
constexpr size_t TotalSize = totalSize(ArgsTuple{});
77+
78+
std::array<unsigned char, TotalSize> ArgsData;
79+
array_fill_helper<Kind, 0, ArgsT...>::fill(ArgsData.data(),
80+
std::forward<ArgsT>(Args)...);
81+
82+
return ArgsData;
83+
}
84+
2985
/// The plugin class provides a unified interface to the underlying low-level
3086
/// runtimes for the device-agnostic SYCL runtime.
3187
///
@@ -85,6 +141,10 @@ class plugin {
85141
// the per_instance_user_data field.
86142
const char *PIFnName = PiCallInfo.getFuncName();
87143
uint64_t CorrelationID = pi::emitFunctionBeginTrace(PIFnName);
144+
auto ArgsData =
145+
packCallArguments<PiApiOffset>(std::forward<ArgsT>(Args)...);
146+
uint64_t CorrelationIDWithArgs = pi::emitFunctionWithArgsBeginTrace(
147+
static_cast<uint32_t>(PiApiOffset), PIFnName, ArgsData.data());
88148
#endif
89149
RT::PiResult R;
90150
if (pi::trace(pi::TraceLevel::PI_TRACE_CALLS)) {
@@ -103,6 +163,9 @@ class plugin {
103163
#ifdef XPTI_ENABLE_INSTRUMENTATION
104164
// Close the function begin with a call to function end
105165
pi::emitFunctionEndTrace(CorrelationID, PIFnName);
166+
pi::emitFunctionWithArgsEndTrace(CorrelationIDWithArgs,
167+
static_cast<uint32_t>(PiApiOffset),
168+
PIFnName, ArgsData.data(), R);
106169
#endif
107170
return R;
108171
}

sycl/tools/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_subdirectory(sycl-ls)
2+
add_subdirectory(pi-trace)
23

34
# TODO: move each tool in its own sub-directory
45
add_executable(get_device_count_by_type get_device_count_by_type.cpp)

sycl/tools/pi-trace/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
add_library(pi_trace SHARED pi_trace.cpp)
2+
target_link_libraries(pi_trace PRIVATE xptifw)
3+
target_include_directories(pi_trace PRIVATE "${XPTI_SOURCE_DIR}/include")
4+
target_include_directories(pi_trace PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../xpti_helpers/")
5+
target_include_directories(pi_trace PRIVATE "${sycl_inc_dir}")
6+
target_include_directories(pi_trace PRIVATE "${sycl_src_dir}")
7+
8+
if(UNIX)
9+
target_link_libraries(pi_trace PRIVATE dl)
10+
endif()
11+
12+
if (XPTI_ENABLE_TBB)
13+
target_link_libraries(pi_trace PRIVATE tbb)
14+
endif()

sycl/tools/pi-trace/pi_trace.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//==----------- pi_trace.cpp.cpp -------------------------------------------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
/// \file pi_trace.cpp
10+
/// A sample XPTI subscriber to demonstrate how to collect PI function call
11+
/// arguments.
12+
13+
#include "xpti_trace_framework.h"
14+
15+
#include "pi_arguments_handler.hpp"
16+
17+
#include <detail/plugin_printers.hpp>
18+
19+
#include <iostream>
20+
#include <mutex>
21+
#include <string>
22+
#include <string_view>
23+
#include <thread>
24+
25+
static uint8_t GStreamID = 0;
26+
std::mutex GIOMutex;
27+
28+
sycl::xpti_helpers::PiArgumentsHandler ArgHandler;
29+
30+
// The lone callback function we are going to use to demonstrate how to attach
31+
// the collector to the running executable
32+
XPTI_CALLBACK_API void tpCallback(uint16_t trace_type,
33+
xpti::trace_event_data_t *parent,
34+
xpti::trace_event_data_t *event,
35+
uint64_t instance, const void *user_data);
36+
37+
// Based on the documentation, every subscriber MUST implement the
38+
// xptiTraceInit() and xptiTraceFinish() APIs for their subscriber collector to
39+
// be loaded successfully.
40+
XPTI_CALLBACK_API void xptiTraceInit(unsigned int major_version,
41+
unsigned int minor_version,
42+
const char *version_str,
43+
const char *stream_name) {
44+
if (std::string_view(stream_name) == "sycl.pi.arg") {
45+
GStreamID = xptiRegisterStream(stream_name);
46+
xptiRegisterCallback(
47+
GStreamID, (uint16_t)xpti::trace_point_type_t::function_with_args_begin,
48+
tpCallback);
49+
xptiRegisterCallback(
50+
GStreamID, (uint16_t)xpti::trace_point_type_t::function_with_args_end,
51+
tpCallback);
52+
53+
#define _PI_API(api) \
54+
ArgHandler.set##_##api([](auto &&... Args) { \
55+
std::cout << "---> " << #api << "(" \
56+
<< "\n"; \
57+
sycl::detail::pi::printArgs(Args...); \
58+
std::cout << ") ---> "; \
59+
});
60+
#include <CL/sycl/detail/pi.def>
61+
#undef _PI_API
62+
}
63+
}
64+
65+
XPTI_CALLBACK_API void xptiTraceFinish(const char *stream_name) {
66+
// NOP
67+
}
68+
69+
XPTI_CALLBACK_API void tpCallback(uint16_t TraceType,
70+
xpti::trace_event_data_t *Parent,
71+
xpti::trace_event_data_t *Event,
72+
uint64_t Instance, const void *UserData) {
73+
auto Type = static_cast<xpti::trace_point_type_t>(TraceType);
74+
if (Type == xpti::trace_point_type_t::function_with_args_end) {
75+
// Lock while we print information
76+
std::lock_guard<std::mutex> Lock(GIOMutex);
77+
78+
const auto *Data =
79+
static_cast<const xpti::function_with_args_t *>(UserData);
80+
81+
ArgHandler.handle(Data->function_id, Data->args_data);
82+
std::cout << *static_cast<pi_result *>(Data->ret_data) << "\n";
83+
}
84+
}

0 commit comments

Comments
 (0)