Skip to content

[XPTI][INFRA] Refactored API implementations to improve performance #19160

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: sycl
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 122 additions & 42 deletions xpti/include/xpti/xpti_data_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ enum class payload_flag_t {
//
using trace_point_t = uint16_t;
using event_type_t = uint16_t;
using string_id_t = int32_t;
using string_id_t = uint32_t;
using object_id_t = int32_t;

using safe_flag_t = std::atomic<bool>;
Expand Down Expand Up @@ -455,60 +455,105 @@ struct payload_t {

payload_t() = default;

// If the address of the kernel/function name is provided, we mark it as
// valid since we can potentially reconstruct the name and the source file
// information during post-processing step of symbol resolution; this
// indicates a partial but valid payload.
///
/// @brief Constructs a payload_t with only a code pointer.
///
/// @details
/// Initializes the payload with the provided code pointer address. All other
/// fields (name, source file, line number, column number) are set to invalid
/// or null values. If a valid code pointer is provided, the corresponding
/// flag is set to indicate its availability.
///
/// If the address of the kernel/function name is provided, we mark it as
/// valid since we can potentially reconstruct the name and the source file
/// information during post-processing step of symbol resolution; this
/// indicates a partial but valid payload.
///
/// @param codeptr Pointer to the code location associated with this payload.
///
payload_t(const void *codeptr) {
code_ptr_va = codeptr;
name = nullptr; ///< Invalid name string pointer
source_file = nullptr; ///< Invalid source file string pointer
line_no = invalid_id<>; ///< Invalid line number
column_no = invalid_id<>; ///< Invalid column number
code_ptr_va = codeptr; ///< Override the default initialization
// If the incoming code ptr is null, we ensure that the flags are set
// correctly
if (codeptr) {
flags = (uint64_t)payload_flag_t::CodePointerAvailable;
}
}

// If neither an address or the fully identifyable source file name and
// location are not available, we take in the name of the
// function/task/user-defined name as input and create a hash from it. We
// mark it as valid since we can display the name in a timeline view, but
// the payload is considered to be a partial but valid payload.
///
/// @brief Constructs a payload_t with only a function or kernel name.
///
/// @details
/// Initializes the payload with the provided function or kernel name.
/// If neither an address or the fully identifyable source file name and
/// location are not available, we take in the name of the
/// function/task/user-defined name as input and create a hash from it. We
/// mark it as valid since we can display the name in a timeline view, but
/// the payload is considered to be a partial but valid payload.
///
/// @param func_name Name of the function, kernel, or user-defined entity.
///
payload_t(const char *func_name) {
code_ptr_va = nullptr;
name = func_name; ///< Invalid name string pointer
source_file = nullptr; ///< Invalid source file string pointer
name = func_name; ///< Override the default initialization
// If the incoming name is null, we ensure that the flags are set correctly
if (func_name) {
flags = (uint64_t)(payload_flag_t::NameAvailable);
}
}

///
/// @brief Constructs a payload_t with a function or kernel name and code
/// pointer.
///
/// @details
/// Initializes the payload with the provided function or kernel name and code
/// pointer. The source file is set to null. Flags are set to indicate which
/// fields are available. The payload is considered partial, but valid.
///
/// @param func_name Name of the function, kernel, or user-defined entity.
/// @param codeptr Pointer to the code location associated with this payload.
///
payload_t(const char *func_name, const void *codeptr) {
code_ptr_va = codeptr;
name = func_name; ///< Invalid name string pointer
source_file = nullptr; ///< Invalid source file string pointer
code_ptr_va = codeptr; ///< Override the default initialization
name = func_name; ///< Override the default initialization
// If the incoming name is null, we ensure that the flags are set correctly
if (func_name) {
flags = (uint64_t)(payload_flag_t::NameAvailable);
}
// If the incoming code ptr is null, we ensure that the flags are set
// correctly
if (codeptr) {
flags |= (uint64_t)payload_flag_t::CodePointerAvailable;
}
}

// When the end user opts out of preserving the code location information and
// the KernelInfo is not available from the given entry point, we will rely
// on dynamic backtrace as a possibility. In this case, we send in the
// caller/callee information as a string in the form "caller->callee" that
// will be used to generate the unique ID.
///
/// @brief Constructs a payload_t with a name, stack trace, and code pointer.
///
/// @details
/// Used when code location information is not preserved and dynamic backtrace
/// is used. Initializes the payload with the provided kernel name,
/// caller-callee stack trace, and code pointer. Sets flags to indicate which
/// fields are available.
///
/// When the end user opts out of preserving the code location information and
/// the KernelInfo is not available from the given entry point, we will rely
/// on dynamic backtrace as a possibility. In this case, we send in the
/// caller/callee information as a string in the form "caller->callee" that
/// will be used to generate the unique ID.
///
/// @param kname Name of the kernel or function.
/// @param caller_callee String representing the caller->callee relationship.
/// @param codeptr Pointer to the code location associated with this payload.
///
payload_t(const char *kname, const char *caller_callee, const void *codeptr) {
if (codeptr) {
code_ptr_va = codeptr;
code_ptr_va = codeptr; ///< Override the default initialization
flags |= (uint64_t)payload_flag_t::CodePointerAvailable;
}
/// Capture the rest of the parameters
// If the incoming name is null, we ensure that the flags are set correctly
if (kname) {
name = kname;
name = kname; ///< Override the default initialization
flags |= (uint64_t)payload_flag_t::NameAvailable;
}
if (caller_callee) {
Expand All @@ -517,34 +562,69 @@ struct payload_t {
}
}

// We need the payload to contain at the very least, the code pointer
// information of the kernel or function. In the full payload case, we will
// also have the function name and source file name along with the line and
// column number of the trace point that forms the payload.
///
/// @brief Constructs a fully populated payload_t.
///
/// @details
/// Initializes the payload with the provided kernel name, source file, line
/// number, column number, and optionally a code pointer. Sets flags to
/// indicate which fields are available. This would constitute a fully
/// populated payload.
///
/// @param kname Name of the kernel or function.
/// @param sf Source file name.
/// @param line Line number in the source file.
/// @param col Column number in the source file.
/// @param codeptr (Optional) Pointer to the code location associated with
/// this payload.
///
payload_t(const char *kname, const char *sf, int line, int col,
const void *codeptr = nullptr) {
code_ptr_va = codeptr;
/// Capture the rest of the parameters
name = kname;
source_file = sf;
line_no = static_cast<uint32_t>(line);
column_no = static_cast<uint32_t>(col);
code_ptr_va = codeptr; ///< Override the default initialization
name = kname; ///< Override the default initialization
source_file = sf; ///< Override the default initialization
line_no =
static_cast<uint32_t>(line); ///< Override the default initialization
column_no =
static_cast<uint32_t>(col); ///< Override the default initialization
// If the incoming name is null, we ensure that the flags are set correctly
if (kname && kname[0] != '\0') {
flags = (uint64_t)payload_flag_t::NameAvailable;
}
// If the incoming source file name is null, we ensure that the flags are
// set correctly
if (sf && sf[0] != '\0') {
flags |= (uint64_t)payload_flag_t::SourceFileAvailable |
(uint64_t)payload_flag_t::LineInfoAvailable |
(uint64_t)payload_flag_t::ColumnInfoAvailable;
}
// If the incoming code ptr is null, we ensure that the flags are set
// correctly
if (codeptr) {
flags |= (uint64_t)payload_flag_t::CodePointerAvailable;
}
}

int32_t name_sid() const { return (int32_t)(uid.p2 & 0x00000000ffffffff); }
int32_t stacktrace_sid() const { return (int32_t)(uid.p2 >> 32); }
int32_t source_file_sid() const { return (int32_t)(uid.p1 >> 32); }
/// @brief Retrieves the string ID (SID) for the name.
/// @details Extracts the lower 32 bits of the uid.p2 member, which represents
/// the xpti::string_id_t in legacy implementations or XPTI_USE_STRICT_HASH
/// mode and contains the FNV1a hash value associated with the name.
/// @return The 32-bit name string ID.
uint32_t name_sid() const { return (uint32_t)(uid.p2 & 0x00000000ffffffff); }

/// @brief Retrieves the string ID (SID) for the stack trace.
/// @details Extracts the upper 32 bits of the uid.p2 member, which represents
/// the xpti::string_id_t in legacy implementations or XPTI_USE_STRICT_HASH
/// mode and contains the FNV1a hash value associated with the stack trace.
/// @return The 32-bit stack trace string ID.
uint32_t stacktrace_sid() const { return (uint32_t)(uid.p2 >> 32); }

/// @brief Retrieves the string ID (SID) for the source file.
/// @details Extracts the upper 32 bits of the uid.p1 member, which represents
/// the xpti::string_id_t in legacy implementations or XPTI_USE_STRICT_HASH
/// mode and contains the FNV1a hash value associated with the source file.
/// @return The 32-bit source file string ID.
uint32_t source_file_sid() const { return (uint32_t)(uid.p1 >> 32); }
};

/// A data structure that holds information about an API function call and its
Expand Down
24 changes: 17 additions & 7 deletions xpti/include/xpti/xpti_trace_framework.h
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,11 @@ XPTI_EXPORT_API const xpti_trace_event_t *xptiLookupEvent(uint64_t uid);
/// @param column_no A uint32_t value representing the column number on the
/// specified line where the tracepoint is located. This provides the most
/// precise location of the tracepoint.
/// @param code_ptr_va A void pointer representing the virtual address of the
/// code where the tracepoint is located. This can be used to associate the
/// tracepoint with a specific code location in memory, which is particularly
/// useful for debugging and performance analysis. If not provided, it defaults
/// to nullptr, indicating that the code pointer is not specified.
///
/// @return A pointer to the created `xpti_tracepoint_t` structure, which
/// represents the tracepoint. If the tracepoint cannot be created, the function
Expand All @@ -704,10 +709,10 @@ XPTI_EXPORT_API const xpti_trace_event_t *xptiLookupEvent(uint64_t uid);
/// @note In order to preserve ABI compatibility, an interface pointer to
/// `xpti_tracepoint_t` is returned.

XPTI_EXPORT_API xpti_tracepoint_t *xptiCreateTracepoint(const char *func_name,
const char *file_name,
uint32_t line_no,
uint32_t column_no);
XPTI_EXPORT_API xpti_tracepoint_t *
xptiCreateTracepoint(const char *func_name, const char *file_name,
uint32_t line_no, uint32_t column_no,
void *code_ptr_va = nullptr);

/// @brief Deletes a tracepoint object.
///
Expand Down Expand Up @@ -916,12 +921,16 @@ XPTI_EXPORT_API void xptiUnsetTracepointScopeData();
/// @param columnNo The column number in the source file where the trace point
/// is defined. If column information is not available, this can
/// be set to 0.
/// @param codePtrVa The code pointer value associated with the trace point.
/// If code pointer information is not available, this can
/// be set to nullptr.
/// @return Returns a pointer to the registered `xpti_tracepoint_t` structure if
/// the registration is successful; otherwise, returns NULL. The
/// returned pointer should not be freed by the caller.
XPTI_EXPORT_API const xpti_tracepoint_t *
xptiRegisterTracepointScope(const char *funcName, const char *fileName,
uint32_t lineNo, uint32_t columnNo);
uint32_t lineNo, uint32_t columnNo,
void *codePtrVa = nullptr);

/// @brief Retrieves the default stream ID.
/// @details This function is used to get the default stream ID that is
Expand Down Expand Up @@ -1042,7 +1051,8 @@ typedef xpti::result_t (*xpti_make_key_from_payload_t)(xpti::payload_t *,
xpti::uid128_t *);
typedef const xpti_tracepoint_t *(*xpti_get_trace_point_scope_data_t)();
typedef const xpti_tracepoint_t *(*xpti_register_tracepoint_scope_t)(
const char *func, const char *file, uint32_t line, uint32_t col);
const char *func, const char *file, uint32_t line, uint32_t col,
void *code_ptr_va);
typedef xpti::result_t (*xpti_set_trace_point_scope_data_t)(
xpti_tracepoint_t *);
typedef void (*xpti_unset_trace_point_scope_data_t)();
Expand All @@ -1059,6 +1069,6 @@ typedef const xpti_payload_t *(*xpti_lookup_payload_t)(uint64_t);
typedef const xpti_trace_event_t *(*xpti_lookup_event_t)(uint64_t);
typedef xpti_tracepoint_t *(*xpti_create_tracepoint_t)(const char *,
const char *, uint32_t,
uint32_t);
uint32_t, void *);
typedef xpti::result_t (*xpti_delete_tracepoint_t)(xpti_tracepoint_t *);
}
49 changes: 34 additions & 15 deletions xpti/include/xpti/xpti_trace_framework.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ typedef void *xpti_plugin_function_t;
#endif

namespace xpti {
constexpr const char *g_unknown_function = "<unknown-function>";
constexpr const char *g_unknown_file = "<unknown-file>";
namespace utils {
/// @class StringHelper
/// @brief A helper class for string manipulations.
Expand Down Expand Up @@ -575,12 +577,28 @@ inline std::string readMetadata(const metadata_t::value_type &MD) {
inline bool is_valid_payload(const xpti::payload_t *Payload) {
if (!Payload)
return false;
else
return (Payload->flags != 0) &&
((Payload->flags &
static_cast<uint64_t>(payload_flag_t::SourceFileAvailable) ||
(Payload->flags &
static_cast<uint64_t>(payload_flag_t::NameAvailable))));
else {
bool isValid = false;
bool hasSourceFile =
(Payload->flags &
static_cast<uint64_t>(payload_flag_t::SourceFileAvailable)) &&
Payload->source_file;
bool hasName = (Payload->flags &
static_cast<uint64_t>(payload_flag_t::NameAvailable)) &&
Payload->name;
bool hasCodePtrVa =
(Payload->flags &
static_cast<uint64_t>(payload_flag_t::CodePointerAvailable)) &&
Payload->code_ptr_va;
bool hasLineInfo =
(Payload->flags &
static_cast<uint64_t>(payload_flag_t::LineInfoAvailable)) &&
Payload->line_no != xpti::invalid_id<uint32_t>;
// We ignore checking for column info as it may not always be available
isValid = ((hasSourceFile && hasLineInfo) || hasName || hasCodePtrVa);

return isValid;
}
}

/// @brief Generates a default payload object with unknown details.
Expand All @@ -595,11 +613,11 @@ inline bool is_valid_payload(const xpti::payload_t *Payload) {
///
/// @return A `xpti::payload_t` object with its members set to represent an
/// unknown or unspecified payload. This includes setting the function name and
/// file name to "unknown", line and column numbers to 0, and the module handle
/// to nullptr.
/// file name to "<unknown-function>" and "<unknown-file>" respectively, line
/// and column numbers to 0, and the module handle to nullptr.
///
inline xpti::payload_t unknown_payload() {
xpti::payload_t Payload("unknown", "unknown-file", 0, 0, nullptr);
xpti::payload_t Payload(g_unknown_function, g_unknown_file, 0, 0, nullptr);
return Payload;
}

Expand Down Expand Up @@ -951,7 +969,8 @@ class tracepoint_scope_t {
/// @note MSFT compiler 2019/2022 support __builtin_FUNCTION() macro
///
tracepoint_scope_t(const char *fileName, const char *funcName, int line,
int column, bool selfNotify = false,
int column, void *codePtrVa = nullptr,
bool selfNotify = false,
const char *callerFuncName = __builtin_FUNCTION())
: MTop(false), MSelfNotify(selfNotify), MCallerFuncName(callerFuncName) {
if (!xptiTraceEnabled())
Expand All @@ -962,9 +981,9 @@ class tracepoint_scope_t {
if (!MData) {
if (funcName && fileName)
init(funcName, fileName, static_cast<uint32_t>(line),
static_cast<uint32_t>(column));
static_cast<uint32_t>(column), codePtrVa);
else
init(callerFuncName, nullptr, 0u, 0u);
init(callerFuncName, nullptr, 0u, 0u, codePtrVa);
} else {
MTraceEvent = MData->event_ref();
}
Expand Down Expand Up @@ -1014,11 +1033,11 @@ class tracepoint_scope_t {
/// tracepoint data.
///
void init(const char *FuncName, const char *FileName, uint32_t LineNo,
uint32_t ColumnNo) {
uint32_t ColumnNo, void *CodePtrVa) {
// Register the payload and prepare the tracepoint data. The function
// returns a UID, associated payload and trace event
MData = const_cast<xpti_tracepoint_t *>(
xptiRegisterTracepointScope(FuncName, FileName, LineNo, ColumnNo));
MData = const_cast<xpti_tracepoint_t *>(xptiRegisterTracepointScope(
FuncName, FileName, LineNo, ColumnNo, CodePtrVa));
if (MData) {
// Set the tracepoint scope with the prepared data so all nested functions
// will have access to it; this call also sets the Universal ID separately
Expand Down
Loading
Loading