rocprofiler-sdk/intercept_table.h Source File

rocprofiler-sdk/intercept_table.h Source File#

Rocprofiler SDK Developer API: rocprofiler-sdk/intercept_table.h Source File
Rocprofiler SDK Developer API 0.4.0
ROCm Profiling API and tools
intercept_table.h
Go to the documentation of this file.
1// MIT License
2//
3// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23#pragma once
24
26#include <rocprofiler-sdk/fwd.h>
27
28ROCPROFILER_EXTERN_C_INIT
29
30/**
31 * @defgroup INTERCEPT_TABLE Intercept table for runtime libraries
32 * @brief Enable tools to wrap the runtime API function calls of HIP, HSA, and ROCTx before and
33 * after the "real" implementation is called.
34 *
35 * When an application invokes the public function from the HIP, HSA, and ROCTx libraries, these
36 * functions invoke a function pointer which, when properly chained, allow tools to wrap these
37 * function calls to collect information. When this capability is used alongside the rocprofiler API
38 * tracing, tools will wrap the rocprofiler wrappers of the API function, e.g. if the tool installs
39 * a wrapper around the `hsa_init` function called `tool_hsa_init`, and rocprofiler installs a
40 * wrapper around the `hsa_init` function called `rocp_hsa_init`, and within the HSA runtime
41 * library, the "real" implementation of the `hsa_init` invokes a function called `real_hsa_init`,
42 * the invocation chain (starting from within the user application) will be: `<application>` ->
43 * `hsa_init` -> `tool_hsa_init` -> `rocp_hsa_init` -> `real_hsa_init`. The return sequence will be
44 * the inverse of invocation chain: `real_hsa_init` -> `rocp_hsa_init` -> `tool_hsa_init` ->
45 * `<application>`. Thus, it is important for tools that use this feature to (A) call the next
46 * function in the chain and (B) properly handle the return value.
47 *
48 * @{
49 */
50
51/**
52 * @brief Callback type when a new runtime library is loaded. @see
53 * rocprofiler_at_intercept_table_registration
54 * @param [in] type Type of API table
55 * @param [in] lib_version Major, minor, and patch version of library encoded into single number
56 * similar to @ref ROCPROFILER_VERSION
57 * @param [in] lib_instance The number of times this runtime library has been registered previously
58 * @param [in] tables An array of pointers to the API tables
59 * @param [in] num_tables The size of the array of pointers to the API tables
60 * @param [in] user_data The pointer to the data provided to @ref
61 * rocprofiler_at_intercept_table_registration
62 */
64 uint64_t lib_version,
65 uint64_t lib_instance,
66 void** tables,
67 uint64_t num_tables,
68 void* user_data);
69
70/**
71 * @brief Invoke this function to receive callbacks when a ROCm library registers its API
72 * intercept table with rocprofiler. Use the @ref rocprofiler_intercept_table_t enumeration for
73 * specifying which raw API tables the tool would like to have access to. E.g. including @ref
74 * ROCPROFILER_HSA_TABLE in the @ref rocprofiler_at_intercept_table_registration function call
75 * communicates to rocprofiler that, when rocprofiler receives a `HsaApiTable` instance, the tool
76 * would like rocprofiler to provide it access too.
77 *
78 * When the HIP, HSA, and ROCTx libraries are initialized (either explicitly or on the first
79 * invocation of one of their public API functions), these runtimes will provide a table of function
80 * pointers to the rocprofiler library via the rocprofiler-register library if the
81 * `rocprofiler_configure` symbol is visible in the application's symbol table. The vast majority of
82 * tools will want to use the @ref CALLBACK_TRACING_SERVICE to trace these runtime APIs, however,
83 * some tools may want or require installing their own intercept functions in lieu of receiving
84 * these callbacks and those tools should use the @ref rocprofiler_at_intercept_table_registration
85 * to install their intercept functions. There are no restrictions to where or how early this
86 * function can be invoked but it will return ::ROCPROFILER_STATUS_ERROR_CONFIGURATION_LOCKED if it
87 * is invoked after rocprofiler has requested all the tool configurations. Thus, it is highly
88 * recommended to invoke this function within the @ref rocprofiler_configure function or the
89 * callback passed to the @ref rocprofiler_force_configure function -- the reason for this
90 * recommendation is that if @ref rocprofiler_at_intercept_table_registration is invoked in one of
91 * these locations, rocprofiler can guarantee that the tool will be passed the API table because, at
92 * the first instance of a runtime registering it's API table, rocprofiler will ensure that, in the
93 * case of the former, rocprofiler will invoke all of the @ref rocprofiler_configure symbols that
94 * are visible before checking the list of tools which want to receive the API tables and, in the
95 * case of the latter, @ref rocprofiler_force_configure will fail with error code @ref
96 * ROCPROFILER_STATUS_ERROR_CONFIGURATION_LOCKED if a runtime has already been registered (and,
97 * therefore, already scanned and invoked the visible @ref rocprofiler_configure symbols and
98 * completed the tool initialization). If @ref rocprofiler_at_intercept_table_registration is
99 * invoked outside of these recommended places, even if it is done before the `main` function starts
100 * (e.g. in a library init/constructor function), it is possible that another library, such as
101 * ROCm-aware MPI, caused the HIP and HSA runtime libraries to be initialized when that library was
102 * loaded. In this aforementioned scenario, if the ROCm-aware MPI library library init/constructor
103 * function runs before your library init/constructor function, rocprofiler will have already
104 * processed the API table and will not provide the API table to the tool due to the fact that the
105 * API may already be in use and, thus, any modifications to the table might result in thread-safety
106 * violations or more disastrous consequences.
107 *
108 * @param [in] callback Callback to tool invoked when a runtime registers their API table with
109 * rocprofiler
110 * @param [in] libs Bitwise-or of libraries, e.g. `ROCPROFILER_HSA_TABLE |
111 * ROCPROFILER_HIP_RUNTIME_TABLE | ROCPROFILER_MARKER_CORE_TABLE` means the callbacks will be
112 * invoked whenever the HSA, HIP runtime, and ROCTx core API tables register their intercept
113 * table(s).
114 * @param [in] data Data to provide to callback(s)
115 * @return ::rocprofiler_status_t
116 * @retval ::ROCPROFILER_STATUS_SUCCESS Callback was registered for specified runtime(s)
117 * @retval ::ROCPROFILER_STATUS_ERROR_CONFIGURATION_LOCKED rocprofiler has already initialized
118 * @retval ::ROCPROFILER_STATUS_ERROR_INVALID_ARGUMENT this error code is returned if
119 * `ROCPROFILER_TABLE` is included in bitwise-or of the libs
120 * @retval ::ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED this error code is returned if one of the
121 * specified libraries does not have support for API intercept tables (which should not be the case
122 * by the time this code is publicly released)
123 *
124 * @code{.cpp}
125 * namespace
126 * {
127 * // this function generates a wrapper around the original function that
128 * // prints out the function name and then invokes the original function
129 * template <size_t Idx, typename RetT, typename... Args>
130 * auto
131 * generate_wrapper(const char* name, RetT (*func)(Args...))
132 * {
133 * using functor_type = RetT (*)(Args...);
134 *
135 * // save function name, "real function"
136 * static const auto* func_name = name;
137 * static functor_type underlying_func = func;
138 * static functor_type wrapped_func = [](Args... args) -> RetT {
139 * std::cout << "Wrapping " << func_name << "..." << std::endl;
140 * if(underlying_func) return underlying_func(args...);
141 * if constexpr(!std::is_void<RetT>::value) return RetT{};
142 * };
143 *
144 * return wrapped_func;
145 * }
146 *
147 *
148 * // this macro installs the wrapper in place of the original function
149 * #define GENERATE_WRAPPER(TABLE, FUNC) \
150 * TABLE->FUNC##_fn = generate_wrapper<__COUNTER__>(#FUNC, TABLE->FUNC##_fn)
151 *
152 *
153 * // this is the function that gets called when the HSA runtime
154 * // intercept table is registered with rocprofiler
155 * void
156 * api_registration_callback(rocprofiler_intercept_table_t type,
157 * uint64_t lib_version,
158 * uint64_t lib_instance,
159 * void** tables,
160 * uint64_t num_tables,
161 * void* user_data)
162 * {
163 * if(type != ROCPROFILER_HSA_TABLE)
164 * throw std::runtime_error{"unexpected library type: " +
165 * std::to_string(static_cast<int>(type))};
166 * if(lib_instance != 0) throw std::runtime_error{"multiple instances of HSA runtime library"};
167 * if(num_tables != 1) throw std::runtime_error{"expected only one table of type HsaApiTable"};
168 *
169 * auto* hsa_api_table = static_cast<HsaApiTable*>(tables[0]);
170 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_agent_get_info);
171 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_agent_iterate_isas);
172 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_code_object_reader_create_from_memory);
173 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_executable_create_alt);
174 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_executable_freeze);
175 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_executable_get_symbol_by_name);
176 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_executable_iterate_symbols);
177 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_executable_load_agent_code_object);
178 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_executable_symbol_get_info);
179 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_isa_get_info_alt);
180 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_iterate_agents);
181 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_queue_add_write_index_screlease);
182 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_queue_create);
183 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_queue_load_read_index_relaxed);
184 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_queue_load_read_index_scacquire);
185 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_signal_create);
186 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_signal_destroy);
187 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_signal_load_relaxed);
188 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_signal_silent_store_relaxed);
189 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_signal_store_screlease);
190 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_signal_wait_scacquire);
191 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_system_get_info);
192 * GENERATE_WRAPPER(hsa_api_table->core_, hsa_system_get_major_extension_table);
193 * }
194 * } // namespace
195 *
196 *
197 * extern "C" rocprofiler_tool_configure_result_t*
198 * rocprofiler_configure(uint32_t version,
199 * const char* runtime_version,
200 * uint32_t priority,
201 * rocprofiler_client_id_t* id)
202 * {
203 * // set the client name
204 * id->name = "ExampleTool";
205 *
206 * // specify that we only want to intercept the HSA library
207 * rocprofiler_at_intercept_table_registration(api_registration_callback,
208 * ROCPROFILER_HSA_TABLE, nullptr);
209 *
210 * return nullptr;
211 * }
212 * @endcode
213 *
214 * @example intercept_table/client.cpp
215 * Example demonstrating @ref rocprofiler_at_intercept_table_registration usage
216 */
219 int libs,
220 void* data) ROCPROFILER_API;
221
222/** @} */
223
224ROCPROFILER_EXTERN_C_FINI
rocprofiler_intercept_table_t
Enumeration for specifying intercept tables supported by rocprofiler. This enumeration is used for in...
Definition fwd.h:361
rocprofiler_status_t
Status codes.
Definition fwd.h:55
void(* rocprofiler_intercept_library_cb_t)(rocprofiler_intercept_table_t type, uint64_t lib_version, uint64_t lib_instance, void **tables, uint64_t num_tables, void *user_data)
Callback type when a new runtime library is loaded.
rocprofiler_status_t rocprofiler_at_intercept_table_registration(rocprofiler_intercept_library_cb_t callback, int libs, void *data)