Initial skeleton (#1)
* googletest submodule
* cmake folder
* misc root files
- clang-format
- cmake-format
- pyproject.toml
- requirements.txt
- VERSION
* workflows
* RPM files
* external folder
* samples folder
* tests root folder
* source/bin folder
* source/include folder
* source/lib/common folder
* source/lib/plugins folder
* source/lib/tests folder
- for library unit tests
* source/lib/rocprofiler folder
- rocprofiler library implementation
* Remaining cmake files
* lib/common/containers
- ring_buffer
- atomic_ring_buffer
- stable_vector
- static_vector
* Update .gitignore
* Update hsa.hpp
- include cstdint
* cmake formatting (cmake-format) (#2)
Co-authored-by: jrmadsen <jrmadsen@users.noreply.github.com>
* Remove linting.yml
- uses self-hosted runners
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
[ROCm/rocprofiler-sdk commit: 527aa71f5a]
This commit is contained in:
committed by
GitHub
parent
0ef1281557
commit
ccac2ee157
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(bin)
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
add_subdirectory(rocprofiler)
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#
|
||||
# Installation of public headers
|
||||
#
|
||||
#
|
||||
set(ROCPROFILER_INCLUDE_FILES config.h rocprofiler.h rocprofiler_plugin.h)
|
||||
install(FILES ${ROCPROFILER_INCLUDE_FILES}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/rocprofiler)
|
||||
@@ -0,0 +1,189 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <hip/hip_runtime.h>
|
||||
#include <rocprofiler/rocprofiler.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ROCPROFILER_API_VERSION_ID 1
|
||||
#define ROCPROFILER_DOMAIN_OPS_MAX 512
|
||||
#define ROCPROFILER_DOMAIN_OPS_RESERVED ((ROCPROFILER_DOMAIN_OPS_MAX * ACTIVITY_DOMAIN_NUMBER / 8))
|
||||
|
||||
typedef uint64_t (*rocprofiler_external_cid_cb_t)(rocprofiler_tracer_activity_domain_t,
|
||||
uint32_t,
|
||||
uint64_t);
|
||||
typedef int (*rocprofiler_filter_name_t)(const char*);
|
||||
typedef int (*rocprofiler_filter_op_id_t)(uint32_t);
|
||||
typedef int (*rocprofiler_filter_range_t)(uint32_t, uint32_t);
|
||||
typedef int (*rocprofiler_filter_dispatch_id_t)(uint64_t);
|
||||
|
||||
/// permits tools opportunity to modify the correlation id based on the domain, op, and
|
||||
/// the rocprofiler generated correlation id
|
||||
struct rocprofiler_correlation_config
|
||||
{
|
||||
rocprofiler_external_cid_cb_t external_id_callback;
|
||||
};
|
||||
|
||||
/// how the tools specify the tracing domain and (optionally) which operations in the
|
||||
/// domain they want to trace
|
||||
struct rocprofiler_domain_config
|
||||
{
|
||||
rocprofiler_sync_callback_t callback;
|
||||
char reserved0[sizeof(uint64_t)];
|
||||
char reserved1[ROCPROFILER_DOMAIN_OPS_RESERVED];
|
||||
};
|
||||
|
||||
/// for buffered callbacks, the tool provides a callback to create a buffer and the size
|
||||
struct rocprofiler_buffer_config
|
||||
{
|
||||
rocprofiler_buffer_callback_t callback;
|
||||
uint64_t buffer_size;
|
||||
// void* reserved0;
|
||||
char reserved1[sizeof(uint64_t)];
|
||||
};
|
||||
|
||||
/// filters are available to make quick decisions about whether rocprofiler should
|
||||
/// assemble the data necessary for a callback. This is more for convenience and
|
||||
/// performance -- anything decisions here could be made in the callback but rocprofiler
|
||||
/// has to first assemble all the infomation on the callback before it (eventually) gets
|
||||
/// discarded because the tool has decided it (after configuration), that it no longer
|
||||
/// wants info meeting certain requirements
|
||||
struct rocprofiler_filter_config
|
||||
{
|
||||
// filter callbacks
|
||||
rocprofiler_filter_name_t name;
|
||||
rocprofiler_filter_op_id_t hip_function_id;
|
||||
rocprofiler_filter_op_id_t hsa_function_id;
|
||||
rocprofiler_filter_range_t range;
|
||||
rocprofiler_filter_dispatch_id_t dispatch_id;
|
||||
|
||||
// reserved padding
|
||||
char padding[24 * sizeof(void*)];
|
||||
};
|
||||
|
||||
/// this is the "single source of truth" for the capabilities of rocprofiler.
|
||||
/// you can one configuration that activates all the capabilities you want
|
||||
/// and holistically start/stop the sum of those features. Alternatively,
|
||||
/// you can have multiple configurations in order to activate certain features
|
||||
/// modularly.
|
||||
///
|
||||
/// The general workflow is:
|
||||
///
|
||||
/// 1. invoke rocprofiler_allocate_config(...)
|
||||
/// - rocprofiler allocates any space internally needed for the config
|
||||
/// - rocprofiler sets a few initial values:
|
||||
/// - "size" to the size of the config structure used internally
|
||||
/// - "api_version" to the version id of the API in the rocprofiler library that
|
||||
/// is being used.
|
||||
/// - these two values can be used by the tool to identify any potential
|
||||
/// incompatibilities that the tool might want to know about
|
||||
/// - rocprofiler checks whether it is too late to configure the tool, e.g.
|
||||
/// something went wrong and rocprofiler was not able to set itself up as
|
||||
/// the intercepter
|
||||
/// 2. tool sets up the configuration struct and sets the "size" variable to the size of
|
||||
/// their configuration struct and sets the "compat_version" field to the
|
||||
/// ROCPROFILER_API_VERSION_ID defined by the rocprofiler headers when the tool was
|
||||
/// built
|
||||
/// - in other words, the user can communicate to rocprofiler, don't read
|
||||
/// past this distance in my configuration struct and I built against X version
|
||||
/// so assume the default behavior and capabilties of version X.
|
||||
/// 3. tool passes this struct to rocprofiler_validate_config(...)
|
||||
/// - this step checks the config in isolation and will communicate any potential
|
||||
/// warnings/issues with that configuration, e.g. rocprofiler_X_config is needed,
|
||||
/// to HW counters XYZ are not available, etc. The tool then has an opportunity
|
||||
/// to address these issues however they see fit.
|
||||
/// 4. tool passes this struct to rocprofiler_start_config(...)
|
||||
/// - internally, we make a call to rocprofiler_validate_config(...) and if any
|
||||
/// issues still exist with the config in isolation, rocprofiler tells the app
|
||||
/// to abort -- mechanisms were provided to prevent aborting prior to this call,
|
||||
/// aborting the app at this point is to guard against rocprofiler "silently"
|
||||
/// not working because error codes were ignored
|
||||
/// - rocprofiler then checks whether this config can actually be activated
|
||||
/// alongside any other active configuration, e.g. this config wants 4 HW counters
|
||||
/// and another wants 4 HW counters but we can only activate 6 out of 8 of
|
||||
/// them in this run. Any issues here will not abort execution but, instead,
|
||||
/// the features of this configuration will not happen (i.e. config won't be
|
||||
/// activated) and the issues will be communicated with error codes -- giving
|
||||
/// the tool the opportunity to address the conflicts (i.e. only request tracing
|
||||
/// and no HW counters) before attempting to activate the modified config.
|
||||
/// - once rocprofiler determines all features of a config can be activated, it
|
||||
/// makes an internal copy of the config and returns an identifier for that
|
||||
/// configuration. The tool is then free to delete the config and any modification
|
||||
/// to the config will NOT be reflected in the behavior of rocprofiler.
|
||||
///
|
||||
///
|
||||
struct rocprofiler_config
|
||||
{
|
||||
// size is used to ensure that we never read past the end of the version
|
||||
size_t size; // = sizeof(rocprofiler_config)
|
||||
uint32_t compat_version; // set by user
|
||||
uint32_t api_version; // set by rocprofiler
|
||||
uint64_t reserved0; // internal field
|
||||
void* user_data; // data passed to callbacks
|
||||
struct rocprofiler_correlation_config* correlation_id; // = &my_cid_config (optional)
|
||||
struct rocprofiler_buffer_config* buffer; // = &my_buffer_config (required)
|
||||
struct rocprofiler_domain_config* domain; // = &my_domain_config (required)
|
||||
struct rocprofiler_filter_config* filter; // = &my_filter_config (optional)
|
||||
};
|
||||
|
||||
/// \brief returns a properly initialized config struct and allocates any data structures
|
||||
/// necessary for the config to be used
|
||||
///
|
||||
/// \param [out] cfg may adjust config or assign values within structs.
|
||||
rocprofiler_status_t
|
||||
rocprofiler_allocate_config(struct rocprofiler_config* cfg);
|
||||
|
||||
/// \brief rocprofiler validates config, checks for conflicts, etc. Ensures that
|
||||
/// the configuration is valid *in isolation*, e.g. it may check that the user
|
||||
/// set the compat_version field and that required config fields, such as buffer
|
||||
/// are set. This function will be called before \ref rocprofiler_start_config
|
||||
/// but is provided to help the user validate one or more configs without starting
|
||||
/// them
|
||||
///
|
||||
/// \param [in] cfg configuration to validate
|
||||
rocprofiler_status_t
|
||||
rocprofiler_validate_config(const struct rocprofiler_config* cfg);
|
||||
|
||||
/// \brief rocprofiler activates configuration and provides a session identifier
|
||||
/// \param [in] cfg may adjust config or assign values within structs. If error
|
||||
/// occurs, could nullptr valid sub-configs and leave the pointers to
|
||||
/// invalid configs
|
||||
/// \param [out] id the session identifier for this config.
|
||||
rocprofiler_status_t
|
||||
rocprofiler_start_config(struct rocprofiler_config*, rocprofiler_session_id_t* id);
|
||||
|
||||
/// \brief disable the configuration.
|
||||
rocprofiler_status_t rocprofiler_stop_config(rocprofiler_session_id_t);
|
||||
|
||||
///
|
||||
///
|
||||
/// the following 4 functions may be changed to permit removing domain/ops and/or
|
||||
/// identifying domains and operations via strings
|
||||
///
|
||||
///
|
||||
rocprofiler_status_t
|
||||
rocprofiler_domain_set_domain(struct rocprofiler_domain_config*,
|
||||
rocprofiler_tracer_activity_domain_t);
|
||||
|
||||
rocprofiler_status_t
|
||||
rocprofiler_domain_add_domains(struct rocprofiler_domain_config*,
|
||||
rocprofiler_tracer_activity_domain_t*,
|
||||
size_t);
|
||||
|
||||
rocprofiler_status_t
|
||||
rocprofiler_domain_add_op(struct rocprofiler_domain_config*,
|
||||
rocprofiler_tracer_activity_domain_t,
|
||||
uint32_t);
|
||||
|
||||
rocprofiler_status_t
|
||||
rocprofiler_domain_add_ops(struct rocprofiler_domain_config*,
|
||||
rocprofiler_tracer_activity_domain_t,
|
||||
uint32_t*,
|
||||
size_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,142 @@
|
||||
/* Copyright (c) 2022 Advanced Micro Devices, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE. */
|
||||
|
||||
/** \section rocprofiler_plugin_api ROCProfiler Plugin API
|
||||
*
|
||||
* The ROCProfiler Plugin API is used by the ROCProfiler Tool to output all
|
||||
* profiling information. Different implementations of the ROCProfiler Plugin
|
||||
* API can be developed that output the data in different formats. The
|
||||
* ROCProfiler Tool can be configured to load a specific library that supports
|
||||
* the user desired format.
|
||||
*
|
||||
* The API is not thread safe. It is the responsibility of the ROCProfiler Tool
|
||||
* to ensure the operations are synchronized and not called concurrently. There
|
||||
* is no requirement for the ROCProfiler Tool to report trace data in any
|
||||
* specific order. If the format supported by plugin requires specific
|
||||
* ordering, it is the responsibility of the plugin implementation to perform
|
||||
* any necessary sorting.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* ROCProfiler Tool Plugin API interface.
|
||||
*/
|
||||
|
||||
#ifndef ROCPROFILER_PLUGIN_H_
|
||||
#define ROCPROFILER_PLUGIN_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rocprofiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/** \defgroup rocprofiler_plugins ROCProfiler Plugin API Specification
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** \defgroup initialization_group Initialization and Finalization
|
||||
* \ingroup rocprofiler_plugins
|
||||
*
|
||||
* The ROCProfiler Plugin API must be initialized before using any of the
|
||||
* operations to report trace data, and finalized after the last trace data has
|
||||
* been reported.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialize plugin.
|
||||
* Must be called before any other operation.
|
||||
*
|
||||
* @param[in] rocprofiler_major_version The major version of the ROCProfiler API
|
||||
* being used by the ROCProfiler Tool. An error is reported if this does not
|
||||
* match the major version of the ROCProfiler API used to build the plugin
|
||||
* library. This ensures compatibility of the trace data format.
|
||||
* @param[in] rocprofiler_minor_version The minor version of the ROCProfiler API
|
||||
* being used by the ROCProfiler Tool. An error is reported if the
|
||||
* \p rocprofiler_major_version matches and this is greater than the minor
|
||||
* version of the ROCProfiler API used to build the plugin library. This ensures
|
||||
* compatibility of the trace data format.
|
||||
* @param[in] data Pointer to the data passed to the ROCProfiler Plugin by the tool
|
||||
* @return Returns 0 on success and -1 on error.
|
||||
*/
|
||||
ROCPROFILER_EXPORT int
|
||||
rocprofiler_plugin_initialize(uint32_t rocprofiler_major_version,
|
||||
uint32_t rocprofiler_minor_version,
|
||||
void* data);
|
||||
|
||||
/**
|
||||
* Finalize plugin.
|
||||
* This must be called after ::rocprofiler_plugin_initialize and after all
|
||||
* profiling data has been reported by
|
||||
* ::rocprofiler_plugin_write_kernel_records
|
||||
*/
|
||||
ROCPROFILER_EXPORT void
|
||||
rocprofiler_plugin_finalize();
|
||||
|
||||
/** @} */
|
||||
|
||||
/** \defgroup profiling_record_write_functions Profiling data reporting
|
||||
* \ingroup rocprofiler_plugins
|
||||
* Operations to output profiling data.
|
||||
* @{
|
||||
*/
|
||||
|
||||
// TODO(aelwazir): Recheck wording of the description
|
||||
|
||||
/**
|
||||
* Report Buffer Records.
|
||||
*
|
||||
* @param[in] begin Pointer to the first record.
|
||||
* @param[in] end Pointer to one past the last record.
|
||||
* @param[in] session_id Session ID
|
||||
* @param[in] buffer_id Buffer ID
|
||||
* @return Returns 0 on success and -1 on error.
|
||||
*/
|
||||
ROCPROFILER_EXPORT int
|
||||
rocprofiler_plugin_write_buffer_records(const rocprofiler_record_header_t* begin,
|
||||
const rocprofiler_record_header_t* end,
|
||||
rocprofiler_session_id_t session_id,
|
||||
rocprofiler_buffer_id_t buffer_id);
|
||||
|
||||
/**
|
||||
* Report Synchronous Record.
|
||||
*
|
||||
* @param[in] record Synchronous Tracer record.
|
||||
* @param[in] data : api_data
|
||||
* @param[in] tracer_data :Tracer record extra data such as function name and kernel name
|
||||
* @return Returns 0 on success and -1 on error.
|
||||
*/
|
||||
|
||||
ROCPROFILER_EXPORT int
|
||||
rocprofiler_plugin_write_record(rocprofiler_record_tracer_t record);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* ROCPROFILER_PLUGIN_H_ */
|
||||
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
add_subdirectory(common)
|
||||
add_subdirectory(rocprofiler)
|
||||
add_subdirectory(plugins)
|
||||
|
||||
if(ROCPROFILER_BUILD_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
@@ -0,0 +1,26 @@
|
||||
set(common_sources ${CMAKE_CURRENT_LIST_DIR}/config.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/helper.cpp)
|
||||
|
||||
set(common_headers
|
||||
${CMAKE_CURRENT_LIST_DIR}/config.hpp ${CMAKE_CURRENT_LIST_DIR}/defines.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/environment.hpp ${CMAKE_CURRENT_LIST_DIR}/join.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/log.hpp ${CMAKE_CURRENT_LIST_DIR}/helper.hpp)
|
||||
|
||||
add_library(rocprofiler-common-library STATIC)
|
||||
add_library(rocprofiler::rocprofiler-common-library ALIAS rocprofiler-common-library)
|
||||
|
||||
add_subdirectory(container)
|
||||
|
||||
target_sources(rocprofiler-common-library PRIVATE ${common_sources} ${common_headers})
|
||||
target_include_directories(rocprofiler-common-library
|
||||
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/source>)
|
||||
|
||||
target_link_libraries(
|
||||
rocprofiler-common-library
|
||||
PUBLIC rocprofiler::rocprofiler-amd-comgr
|
||||
$<BUILD_INTERFACE:rocprofiler::rocprofiler-build-flags>
|
||||
$<BUILD_INTERFACE:rocprofiler::rocprofiler-memcheck>
|
||||
$<BUILD_INTERFACE:rocprofiler::rocprofiler-stdcxxfs>
|
||||
$<BUILD_INTERFACE:rocprofiler::rocprofiler-dl>)
|
||||
set_target_properties(rocprofiler-common-library PROPERTIES OUTPUT_NAME
|
||||
rocprofiler-common)
|
||||
@@ -0,0 +1,433 @@
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#include "lib/common/config.hpp"
|
||||
#include "lib/common/environment.hpp"
|
||||
#include "lib/common/join.hpp"
|
||||
#include "lib/common/log.hpp"
|
||||
#include "lib/common/helper.hpp"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
#include <filesystem>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::time_t* launch_time = new std::time_t{std::time(nullptr)};
|
||||
|
||||
std::vector<std::string>
|
||||
read_command_line(pid_t _pid)
|
||||
{
|
||||
auto _cmdline = std::vector<std::string>{};
|
||||
auto fcmdline = std::stringstream{};
|
||||
fcmdline << "/proc/" << _pid << "/cmdline";
|
||||
auto ifs = std::ifstream{fcmdline.str().c_str()};
|
||||
if(ifs)
|
||||
{
|
||||
char cstr;
|
||||
std::string sarg;
|
||||
while(!ifs.eof())
|
||||
{
|
||||
ifs >> cstr;
|
||||
if(!ifs.eof())
|
||||
{
|
||||
if(cstr != '\0')
|
||||
{
|
||||
sarg += cstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cmdline.push_back(sarg);
|
||||
sarg = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
ifs.close();
|
||||
}
|
||||
|
||||
return _cmdline;
|
||||
}
|
||||
|
||||
std::string
|
||||
get_local_datetime(const char* dt_format, std::time_t* dt_curr)
|
||||
{
|
||||
char mbstr[512];
|
||||
if(!dt_curr) dt_curr = launch_time;
|
||||
|
||||
if(std::strftime(mbstr, sizeof(mbstr), dt_format, std::localtime(dt_curr)) != 0)
|
||||
return std::string{mbstr};
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
inline bool
|
||||
not_is_space(int ch)
|
||||
{
|
||||
return std::isspace(ch) == 0;
|
||||
}
|
||||
|
||||
inline std::string
|
||||
ltrim(std::string s, bool (*f)(int) = not_is_space)
|
||||
{
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), f));
|
||||
return s;
|
||||
}
|
||||
|
||||
inline std::string
|
||||
rtrim(std::string s, bool (*f)(int) = not_is_space)
|
||||
{
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(), f).base(), s.end());
|
||||
return s;
|
||||
}
|
||||
|
||||
inline std::string
|
||||
trim(std::string s, bool (*f)(int) = not_is_space)
|
||||
{
|
||||
ltrim(s, f);
|
||||
rtrim(s, f);
|
||||
return s;
|
||||
}
|
||||
|
||||
inline std::vector<pid_t>
|
||||
get_siblings(pid_t _id = getppid())
|
||||
{
|
||||
auto _data = std::vector<pid_t>{};
|
||||
|
||||
std::ifstream _ifs{"/proc/" + std::to_string(_id) + "/task/" + std::to_string(_id) +
|
||||
"/children"};
|
||||
while(_ifs)
|
||||
{
|
||||
pid_t _n = 0;
|
||||
_ifs >> _n;
|
||||
if(!_ifs || _n <= 0) break;
|
||||
_data.emplace_back(_n);
|
||||
}
|
||||
return _data;
|
||||
}
|
||||
|
||||
inline auto
|
||||
get_num_siblings(pid_t _id = getppid())
|
||||
{
|
||||
return get_siblings(_id).size();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int
|
||||
get_mpi_size()
|
||||
{
|
||||
static int _v = get_env<int>("OMPI_COMM_WORLD_SIZE",
|
||||
get_env<int>("MV2_COMM_WORLD_SIZE", get_env<int>("MPI_SIZE", 0)));
|
||||
return _v;
|
||||
}
|
||||
|
||||
int
|
||||
get_mpi_rank()
|
||||
{
|
||||
static int _v = get_env<int>("OMPI_COMM_WORLD_RANK",
|
||||
get_env<int>("MV2_COMM_WORLD_RANK", get_env<int>("MPI_RANK", -1)));
|
||||
return _v;
|
||||
}
|
||||
|
||||
std::vector<output_key>
|
||||
output_keys(std::string _tag)
|
||||
{
|
||||
using strpair_t = std::pair<std::string, std::string>;
|
||||
|
||||
auto _cmdline = read_command_line(getpid());
|
||||
|
||||
if(_tag.empty() && !_cmdline.empty()) _tag = ::basename(_cmdline.front().c_str());
|
||||
|
||||
std::string _argv_string = {}; // entire argv cmd
|
||||
std::string _args_string = {}; // cmdline args
|
||||
std::string _argt_string = _tag; // prefix + cmdline args
|
||||
const std::string& _tag0_string = _tag; // only the basic prefix
|
||||
auto _options = std::vector<output_key>{};
|
||||
|
||||
auto _replace = [](auto& _v, const strpair_t& pitr) {
|
||||
auto pos = std::string::npos;
|
||||
while((pos = _v.find(pitr.first)) != std::string::npos)
|
||||
_v.replace(pos, pitr.first.length(), pitr.second);
|
||||
};
|
||||
|
||||
if(_cmdline.size() > 1 && _cmdline.at(1) == "--") _cmdline.erase(_cmdline.begin() + 1);
|
||||
|
||||
for(auto& itr : _cmdline)
|
||||
{
|
||||
itr = trim(itr);
|
||||
_replace(itr, {"/", "_"});
|
||||
while(!itr.empty() && itr.at(0) == '.')
|
||||
itr = itr.substr(1);
|
||||
while(!itr.empty() && itr.at(0) == '_')
|
||||
itr = itr.substr(1);
|
||||
}
|
||||
|
||||
if(!_cmdline.empty())
|
||||
{
|
||||
for(size_t i = 0; i < _cmdline.size(); ++i)
|
||||
{
|
||||
const auto _l = std::string{(i == 0) ? "" : "_"};
|
||||
auto _v = _cmdline.at(i);
|
||||
_argv_string += _l + _v;
|
||||
if(i > 0)
|
||||
{
|
||||
_argt_string += (i > 1) ? (_l + _v) : _v;
|
||||
_args_string += (i > 1) ? (_l + _v) : _v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto* _launch_time = launch_time;
|
||||
auto _time_format = get_env<std::string>("ROCP_TIME_FORMAT", "%F_%H.%M");
|
||||
|
||||
auto _mpi_size = get_env<int>("OMPI_COMM_WORLD_SIZE", get_env<int>("MV2_COMM_WORLD_SIZE", 0));
|
||||
auto _mpi_rank = get_env<int>("OMPI_COMM_WORLD_RANK", get_env<int>("MV2_COMM_WORLD_RANK", -1));
|
||||
|
||||
auto _dmp_size = join("", (_mpi_size) > 0 ? _mpi_size : 1);
|
||||
auto _dmp_rank = join("", (_mpi_rank) > 0 ? _mpi_rank : 0);
|
||||
auto _proc_id = join("", getpid());
|
||||
auto _parent_id = join("", getppid());
|
||||
auto _pgroup_id = join("", getpgid(getpid()));
|
||||
auto _session_id = join("", getsid(getpid()));
|
||||
auto _proc_size = join("", get_num_siblings());
|
||||
auto _pwd_string = get_env<std::string>("PWD", ".");
|
||||
auto _slurm_job_id = get_env<std::string>("SLURM_JOB_ID", "0");
|
||||
auto _slurm_proc_id = get_env("SLURM_PROCID", _dmp_rank);
|
||||
auto _launch_string = get_local_datetime(_time_format.c_str(), _launch_time);
|
||||
|
||||
auto _uniq_id = _proc_id;
|
||||
if(get_env<int32_t>("SLURM_PROCID", -1) >= 0)
|
||||
{
|
||||
_uniq_id = _slurm_proc_id;
|
||||
}
|
||||
else if(_mpi_size > 0 || _mpi_rank >= 0)
|
||||
{
|
||||
_uniq_id = _dmp_rank;
|
||||
}
|
||||
|
||||
for(auto&& itr : std::initializer_list<output_key>{
|
||||
{"%argv%", _argv_string, "Entire command-line condensed into a single string"},
|
||||
{"%argt%",
|
||||
_argt_string,
|
||||
"Similar to `%argv%` except basename of first command line argument"},
|
||||
{"%args%", _args_string, "All command line arguments condensed into a single string"},
|
||||
{"%tag%", _tag0_string, "Basename of first command line argument"}})
|
||||
{
|
||||
_options.emplace_back(itr);
|
||||
}
|
||||
|
||||
if(!_cmdline.empty())
|
||||
{
|
||||
for(size_t i = 0; i < _cmdline.size(); ++i)
|
||||
{
|
||||
auto _v = _cmdline.at(i);
|
||||
_options.emplace_back(join("", "%arg", i, "%"), _v, join("", "Argument #", i));
|
||||
}
|
||||
}
|
||||
|
||||
for(auto&& itr : std::initializer_list<output_key>{
|
||||
{"%pid%", _proc_id, "Process identifier"},
|
||||
{"%ppid%", _parent_id, "Parent process identifier"},
|
||||
{"%pgid%", _pgroup_id, "Process group identifier"},
|
||||
{"%psid%", _session_id, "Process session identifier"},
|
||||
{"%psize%", _proc_size, "Number of sibling process"},
|
||||
{"%job%", _slurm_job_id, "SLURM_JOB_ID env variable"},
|
||||
{"%rank%", _slurm_proc_id, "MPI/UPC++ rank"},
|
||||
{"%size%", _dmp_size, "MPI/UPC++ size"},
|
||||
{"%nid%", _uniq_id, "%rank% if possible, otherwise %pid%"},
|
||||
{"%launch_time%", _launch_string, "Data and/or time of run according to time format"},
|
||||
})
|
||||
{
|
||||
_options.emplace_back(itr);
|
||||
}
|
||||
|
||||
for(auto&& itr : std::initializer_list<output_key>{
|
||||
{"%p", _proc_id, "Shorthand for %pid%"},
|
||||
{"%j", _slurm_job_id, "Shorthand for %job%"},
|
||||
{"%r", _slurm_proc_id, "Shorthand for %rank%"},
|
||||
{"%s", _dmp_size, "Shorthand for %size"},
|
||||
})
|
||||
{
|
||||
_options.emplace_back(itr);
|
||||
}
|
||||
|
||||
return _options;
|
||||
}
|
||||
|
||||
std::string
|
||||
format(std::string _fpath, const std::string& _tag)
|
||||
{
|
||||
if(_fpath.find('%') == std::string::npos && _fpath.find('$') == std::string::npos)
|
||||
return _fpath;
|
||||
|
||||
auto _replace = [](auto& _v, const output_key& pitr) {
|
||||
auto pos = std::string::npos;
|
||||
while((pos = _v.find(pitr.key)) != std::string::npos)
|
||||
_v.replace(pos, pitr.key.length(), pitr.value);
|
||||
};
|
||||
|
||||
for(auto&& itr : output_keys(_tag))
|
||||
_replace(_fpath, itr);
|
||||
|
||||
// environment and configuration variables
|
||||
try
|
||||
{
|
||||
for(const auto& _expr : {std::string{"(.*)%(env|ENV)\\{([A-Z0-9_]+)\\}%(.*)"},
|
||||
std::string{"(.*)\\$(env|ENV)\\{([A-Z0-9_]+)\\}(.*)"}})
|
||||
{
|
||||
std::regex _re{_expr};
|
||||
std::string _cbeg = (_expr.find("(.*)%") == 0) ? "%" : "$";
|
||||
std::string _cend = (_expr.find("(.*)%") == 0) ? "}%" : "}";
|
||||
bool _is_env = (_expr.find("(env|ENV)") != std::string::npos);
|
||||
_cbeg += (_is_env) ? "env{" : "cfg{";
|
||||
while(std::regex_search(_fpath, _re))
|
||||
{
|
||||
auto _var = std::regex_replace(_fpath, _re, "$3");
|
||||
std::string _val = {};
|
||||
if(_is_env)
|
||||
{
|
||||
_val = get_env<std::string>(_var, "");
|
||||
}
|
||||
auto _beg = std::regex_replace(_fpath, _re, "$1");
|
||||
auto _end = std::regex_replace(_fpath, _re, "$4");
|
||||
_fpath = join("", _beg, _val, _end);
|
||||
}
|
||||
}
|
||||
} catch(std::exception& _e)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s[rocprofiler][%s:%i] %s threw exception :: %s\n%s",
|
||||
log::color::dmesg(),
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
__FUNCTION__,
|
||||
_e.what(),
|
||||
log::color::end());
|
||||
}
|
||||
|
||||
// remove %arg<N>% where N >= argc
|
||||
try
|
||||
{
|
||||
std::regex _re{"(.*)%(arg[0-9]+)%([-/_]*)(.*)"};
|
||||
while(std::regex_search(_fpath, _re))
|
||||
_fpath = std::regex_replace(_fpath, _re, "$1$4");
|
||||
} catch(std::exception& _e)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s[rocprofiler][%s:%i] %s threw exception :: %s\n%s",
|
||||
log::color::dmesg(),
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
__FUNCTION__,
|
||||
_e.what(),
|
||||
log::color::end());
|
||||
}
|
||||
|
||||
return _fpath;
|
||||
}
|
||||
|
||||
std::string
|
||||
compose_filename(const config& _cfg)
|
||||
{
|
||||
auto _output_path = _cfg.output_path;
|
||||
auto _output_file = _cfg.output_file;
|
||||
auto _output_ext = _cfg.output_ext;
|
||||
|
||||
if(_output_path.empty()) _output_path = ".";
|
||||
if(_cfg.mpi_size > 0)
|
||||
{
|
||||
if(_cfg.mpi_rank >= 0)
|
||||
{
|
||||
_output_file = join('.', _output_file, _cfg.mpi_rank);
|
||||
}
|
||||
else
|
||||
{
|
||||
_output_file = join('.', _output_file, getpid());
|
||||
}
|
||||
}
|
||||
if(!_output_ext.empty())
|
||||
{
|
||||
if(_output_ext.find('.') == std::string::npos) _output_ext.insert(0, ".");
|
||||
if(_output_file.length() < _output_ext.length() ||
|
||||
_output_file.find(_output_ext) != _output_file.length() - _output_ext.length())
|
||||
_output_file += _output_ext;
|
||||
}
|
||||
|
||||
// join <OUTPUT_PATH>/<OUTPUT_FILE> and replace any keys with values
|
||||
auto _prefix = format(std::filesystem::path{_output_path} / _output_file);
|
||||
|
||||
// return on empty
|
||||
if(_prefix.empty()) return std::string{};
|
||||
|
||||
// get the absolute path
|
||||
auto _fname = std::filesystem::absolute(std::filesystem::path{_prefix});
|
||||
|
||||
// create the directory if necessary
|
||||
auto _fname_path = _fname.parent_path();
|
||||
if(!std::filesystem::exists(_fname_path))
|
||||
std::filesystem::create_directories(_fname.parent_path());
|
||||
|
||||
return _fname.string();
|
||||
}
|
||||
|
||||
std::string
|
||||
format_name(std::string_view _name, const config& _cfg)
|
||||
{
|
||||
if(_cfg.demangle && _cfg.truncate)
|
||||
{
|
||||
return truncate_name(cxx_demangle(_name));
|
||||
}
|
||||
|
||||
if(_cfg.demangle)
|
||||
{
|
||||
return cxx_demangle(_name);
|
||||
}
|
||||
|
||||
if(_cfg.truncate)
|
||||
{
|
||||
return truncate_name(_name);
|
||||
}
|
||||
|
||||
return std::string{_name};
|
||||
}
|
||||
|
||||
void
|
||||
initialize()
|
||||
{
|
||||
(void) get_config<config_context::global>();
|
||||
}
|
||||
|
||||
output_key::output_key(std::string _key, std::string _val, std::string _desc)
|
||||
: key{std::move(_key)}
|
||||
, value{std::move(_val)}
|
||||
, description{std::move(_desc)}
|
||||
{}
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lib/common/environment.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
enum class config_context
|
||||
{
|
||||
global = 0,
|
||||
att_plugin,
|
||||
cli_plugin,
|
||||
ctf_plugin,
|
||||
file_plugin,
|
||||
perfetto_plugin,
|
||||
};
|
||||
|
||||
int
|
||||
get_mpi_size();
|
||||
int
|
||||
get_mpi_rank();
|
||||
|
||||
struct config
|
||||
{
|
||||
bool demangle = get_env("ROCP_DEMANGLE_KERNELS", true);
|
||||
bool truncate = get_env("ROCP_TRUNCATE_KERNELS", false);
|
||||
int mpi_size = get_mpi_size();
|
||||
int mpi_rank = get_mpi_rank();
|
||||
std::string output_path = get_env<std::string>("ROCP_OUTPUT_PATH", ".");
|
||||
std::string output_file = get_env<std::string>("ROCP_OUTPUT_FILE", "results");
|
||||
std::string output_ext = {};
|
||||
};
|
||||
|
||||
template <config_context ContextT = config_context::global>
|
||||
config&
|
||||
get_config()
|
||||
{
|
||||
if constexpr(ContextT == config_context::global)
|
||||
{
|
||||
static auto _v = config{};
|
||||
return _v;
|
||||
}
|
||||
else
|
||||
{
|
||||
// context specific config copied from global config
|
||||
static auto _v = get_config<config_context::global>();
|
||||
return _v;
|
||||
}
|
||||
}
|
||||
|
||||
struct output_key
|
||||
{
|
||||
output_key(std::string _key, std::string _val, std::string _desc = {});
|
||||
|
||||
operator std::pair<std::string, std::string>() const;
|
||||
|
||||
std::string key = {};
|
||||
std::string value = {};
|
||||
std::string description = {};
|
||||
};
|
||||
|
||||
std::vector<output_key>
|
||||
output_keys(std::string _tag = {});
|
||||
std::string
|
||||
compose_filename(const config&);
|
||||
std::string
|
||||
format(std::string _fpath, const std::string& _tag = {});
|
||||
std::string
|
||||
format_name(std::string_view _name, const config& = get_config<>());
|
||||
|
||||
void
|
||||
initialize();
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,10 @@
|
||||
#
|
||||
set(containers_sources)
|
||||
|
||||
set(containers_headers atomic_ring_buffer.hpp c_array.hpp operators.hpp ring_buffer.hpp
|
||||
stable_vector.hpp static_vector.hpp)
|
||||
|
||||
set(containers_sources atomic_ring_buffer.cpp ring_buffer.cpp)
|
||||
|
||||
target_sources(rocprofiler-common-library PRIVATE ${containers_sources}
|
||||
${containers_headers})
|
||||
@@ -0,0 +1,297 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020, The Regents of the University of California,
|
||||
// through Lawrence Berkeley National Laboratory (subject to receipt of any
|
||||
// required approvals from the U.S. Dept. of Energy). All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "atomic_ring_buffer.hpp"
|
||||
#include "lib/common/units.hpp"
|
||||
#include "lib/common/environment.hpp"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace container
|
||||
{
|
||||
namespace base
|
||||
{
|
||||
atomic_ring_buffer::atomic_ring_buffer(size_t _size, bool _use_mmap)
|
||||
{
|
||||
set_use_mmap(_use_mmap);
|
||||
init(_size);
|
||||
}
|
||||
|
||||
atomic_ring_buffer::~atomic_ring_buffer() { destroy(); }
|
||||
|
||||
atomic_ring_buffer::atomic_ring_buffer(const atomic_ring_buffer& rhs)
|
||||
: m_use_mmap{rhs.m_use_mmap}
|
||||
, m_use_mmap_explicit{rhs.m_use_mmap_explicit}
|
||||
{
|
||||
init(rhs.m_size);
|
||||
}
|
||||
|
||||
atomic_ring_buffer::atomic_ring_buffer(atomic_ring_buffer&& rhs) noexcept
|
||||
: m_init{rhs.m_init}
|
||||
, m_use_mmap{rhs.m_use_mmap}
|
||||
, m_use_mmap_explicit{rhs.m_use_mmap_explicit}
|
||||
, m_ptr{rhs.m_ptr}
|
||||
, m_size{rhs.m_size}
|
||||
, m_read_count{rhs.m_read_count.load()}
|
||||
, m_write_count{rhs.m_write_count.load()}
|
||||
{
|
||||
rhs.reset();
|
||||
}
|
||||
|
||||
atomic_ring_buffer&
|
||||
atomic_ring_buffer::operator=(const atomic_ring_buffer& rhs)
|
||||
{
|
||||
if(this == &rhs) return *this;
|
||||
destroy();
|
||||
m_use_mmap = rhs.m_use_mmap;
|
||||
m_use_mmap_explicit = rhs.m_use_mmap_explicit;
|
||||
init(rhs.m_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
atomic_ring_buffer&
|
||||
atomic_ring_buffer::operator=(atomic_ring_buffer&& rhs) noexcept
|
||||
{
|
||||
if(this == &rhs) return *this;
|
||||
destroy();
|
||||
m_init = rhs.m_init;
|
||||
m_use_mmap = rhs.m_use_mmap;
|
||||
m_use_mmap_explicit = rhs.m_use_mmap_explicit;
|
||||
m_ptr = rhs.m_ptr;
|
||||
m_size = rhs.m_size;
|
||||
m_read_count = rhs.m_read_count.load();
|
||||
m_write_count = rhs.m_write_count.load();
|
||||
rhs.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
atomic_ring_buffer::init(size_t _size)
|
||||
{
|
||||
if(m_init)
|
||||
throw std::runtime_error(
|
||||
"tim::base::atomic_ring_buffer::init(size_t) :: already initialized");
|
||||
|
||||
m_init = true;
|
||||
|
||||
// Round up to multiple of page size.
|
||||
_size += units::get_page_size() - ((_size % units::get_page_size() > 0)
|
||||
? (_size % units::get_page_size())
|
||||
: units::get_page_size());
|
||||
|
||||
if((_size % units::get_page_size()) > 0)
|
||||
{
|
||||
std::ostringstream _oss{};
|
||||
_oss << "Error! size is not a multiple of page size: " << _size << " % "
|
||||
<< units::get_page_size() << " = " << (_size % units::get_page_size());
|
||||
throw std::runtime_error(_oss.str());
|
||||
}
|
||||
|
||||
m_size = _size;
|
||||
m_read_count = 0;
|
||||
m_write_count = 0;
|
||||
|
||||
if(!m_use_mmap_explicit) m_use_mmap = get_env("ROCPROFILER_USE_MMAP", m_use_mmap);
|
||||
|
||||
if(!m_use_mmap)
|
||||
{
|
||||
m_ptr = malloc(m_size * sizeof(char));
|
||||
return;
|
||||
}
|
||||
|
||||
// Map twice the buffer size.
|
||||
if((m_ptr =
|
||||
mmap(nullptr, m_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) ==
|
||||
MAP_FAILED)
|
||||
{
|
||||
destroy();
|
||||
auto _err = errno;
|
||||
// TIMEMORY_PRINTF_FATAL(stderr, "Error using mmap: %s\n", strerror(_err));
|
||||
throw std::runtime_error(strerror(_err));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
atomic_ring_buffer::destroy()
|
||||
{
|
||||
if(m_ptr && m_init)
|
||||
{
|
||||
if(!m_use_mmap)
|
||||
{
|
||||
::free(m_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unmap the mapped virtual memmory.
|
||||
auto ret = munmap(m_ptr, m_size);
|
||||
if(ret != 0) perror("munmap");
|
||||
}
|
||||
}
|
||||
m_init = false;
|
||||
m_size = 0;
|
||||
m_read_count = 0;
|
||||
m_write_count = 0;
|
||||
m_ptr = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
atomic_ring_buffer::set_use_mmap(bool _v)
|
||||
{
|
||||
if(m_init)
|
||||
throw std::runtime_error("tim::base::atomic_ring_buffer::set_use_mmap(bool) cannot be "
|
||||
"called after initialization");
|
||||
m_use_mmap = _v;
|
||||
m_use_mmap_explicit = true;
|
||||
}
|
||||
|
||||
std::string
|
||||
atomic_ring_buffer::as_string() const
|
||||
{
|
||||
std::ostringstream ss{};
|
||||
ss << std::boolalpha << "is_initialized: " << is_initialized() << ", capacity: " << capacity()
|
||||
<< ", count: " << count() << ", free: " << free() << ", is_empty: " << is_empty()
|
||||
<< ", is_full: " << is_full() << ", pointer: " << m_ptr << ", read count: " << m_read_count
|
||||
<< ", write count: " << m_write_count;
|
||||
return ss.str();
|
||||
}
|
||||
//
|
||||
|
||||
void*
|
||||
atomic_ring_buffer::request(size_t _length)
|
||||
{
|
||||
if(m_ptr == nullptr || m_size == 0) return nullptr;
|
||||
|
||||
if(is_full()) return retrieve(_length);
|
||||
|
||||
// if write count is at the tail of buffer, bump to the end of buffer
|
||||
size_t _write_count = 0;
|
||||
size_t _offset = 0;
|
||||
do
|
||||
{
|
||||
// Make sure we don't put in more than there's room for, by writing no
|
||||
// more than there is free.
|
||||
if(_length > free()) return nullptr;
|
||||
|
||||
_offset = 0;
|
||||
_write_count = m_write_count.load();
|
||||
auto _modulo = m_size - (_write_count % m_size);
|
||||
if(_modulo < _length) _offset = _modulo;
|
||||
} while(!m_write_count.compare_exchange_strong(
|
||||
_write_count, _write_count + _length + _offset, std::memory_order_seq_cst));
|
||||
|
||||
// pointer in buffer
|
||||
void* _out = write_ptr(_write_count);
|
||||
|
||||
return _out;
|
||||
}
|
||||
//
|
||||
|
||||
void*
|
||||
atomic_ring_buffer::retrieve(size_t _length) const
|
||||
{
|
||||
if(m_ptr == nullptr || m_size == 0) return nullptr;
|
||||
|
||||
// Make sure we don't put in more than there's room for, by writing no
|
||||
// more than there is free.
|
||||
|
||||
// if read count is at the tail of buffer, bump to the end of buffer
|
||||
size_t _read_count = 0;
|
||||
size_t _offset = 0;
|
||||
do
|
||||
{
|
||||
if(_length > count()) return nullptr;
|
||||
_offset = 0;
|
||||
_read_count = m_read_count.load();
|
||||
auto _modulo = m_size - (_read_count % m_size);
|
||||
if(_modulo < _length) _offset = _modulo;
|
||||
} while(!m_read_count.compare_exchange_strong(
|
||||
_read_count, _read_count + _length + _offset, std::memory_order_seq_cst));
|
||||
|
||||
// pointer in buffer
|
||||
void* _out = read_ptr(_read_count);
|
||||
|
||||
return _out;
|
||||
}
|
||||
//
|
||||
|
||||
void
|
||||
atomic_ring_buffer::reset()
|
||||
{
|
||||
m_init = false;
|
||||
m_size = 0;
|
||||
m_ptr = nullptr;
|
||||
m_read_count.store(0);
|
||||
m_write_count.store(0);
|
||||
}
|
||||
//
|
||||
|
||||
void
|
||||
atomic_ring_buffer::save(std::fstream& _fs)
|
||||
{
|
||||
auto _read_count = m_read_count.load();
|
||||
auto _write_count = m_write_count.load();
|
||||
_fs.write(reinterpret_cast<char*>(&m_use_mmap), sizeof(m_use_mmap));
|
||||
_fs.write(reinterpret_cast<char*>(&m_use_mmap_explicit), sizeof(m_use_mmap_explicit));
|
||||
_fs.write(reinterpret_cast<char*>(&m_size), sizeof(m_size));
|
||||
_fs.write(reinterpret_cast<char*>(&_read_count), sizeof(_read_count));
|
||||
_fs.write(reinterpret_cast<char*>(&_write_count), sizeof(_write_count));
|
||||
_fs.write(reinterpret_cast<char*>(m_ptr), m_size * sizeof(char));
|
||||
}
|
||||
//
|
||||
|
||||
void
|
||||
atomic_ring_buffer::load(std::fstream& _fs)
|
||||
{
|
||||
destroy();
|
||||
size_t _read_count = 0;
|
||||
size_t _write_count = 0;
|
||||
|
||||
_fs.read(reinterpret_cast<char*>(&m_use_mmap), sizeof(m_use_mmap));
|
||||
_fs.read(reinterpret_cast<char*>(&m_use_mmap_explicit), sizeof(m_use_mmap_explicit));
|
||||
_fs.read(reinterpret_cast<char*>(&m_size), sizeof(m_size));
|
||||
|
||||
init(m_size);
|
||||
if(!m_ptr) m_ptr = malloc(m_size);
|
||||
|
||||
_fs.read(reinterpret_cast<char*>(&_read_count), sizeof(_read_count));
|
||||
_fs.read(reinterpret_cast<char*>(&_write_count), sizeof(_write_count));
|
||||
_fs.read(reinterpret_cast<char*>(m_ptr), m_size * sizeof(char));
|
||||
|
||||
m_read_count.store(_read_count);
|
||||
m_write_count.store(_write_count);
|
||||
}
|
||||
} // namespace base
|
||||
} // namespace container
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,426 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020, The Regents of the University of California,
|
||||
// through Lawrence Berkeley National Laboratory (subject to receipt of any
|
||||
// required approvals from the U.S. Dept. of Energy). All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lib/common/units.hpp"
|
||||
#include "lib/common/environment.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace container
|
||||
{
|
||||
template <typename Tp>
|
||||
struct atomic_ring_buffer;
|
||||
//
|
||||
namespace base
|
||||
{
|
||||
/// \struct tim::base::atomic_ring_buffer
|
||||
/// \brief Ring buffer implementation, with support for mmap as backend (Linux only).
|
||||
struct atomic_ring_buffer
|
||||
{
|
||||
template <typename Tp>
|
||||
friend struct container::atomic_ring_buffer;
|
||||
|
||||
atomic_ring_buffer() = default;
|
||||
explicit atomic_ring_buffer(bool _use_mmap) { set_use_mmap(_use_mmap); }
|
||||
explicit atomic_ring_buffer(size_t _size) { init(_size); }
|
||||
atomic_ring_buffer(size_t _size, bool _use_mmap);
|
||||
|
||||
~atomic_ring_buffer();
|
||||
|
||||
atomic_ring_buffer(const atomic_ring_buffer&);
|
||||
atomic_ring_buffer& operator=(const atomic_ring_buffer&);
|
||||
|
||||
atomic_ring_buffer(atomic_ring_buffer&&) noexcept;
|
||||
atomic_ring_buffer& operator=(atomic_ring_buffer&&) noexcept;
|
||||
|
||||
/// Returns whether the buffer has been allocated
|
||||
bool is_initialized() const { return m_init; }
|
||||
|
||||
/// Get the total number of bytes supported
|
||||
size_t capacity() const { return m_size; }
|
||||
|
||||
/// Creates new ring buffer.
|
||||
void init(size_t size);
|
||||
|
||||
/// Destroy ring buffer.
|
||||
void destroy();
|
||||
|
||||
/// Request a pointer for writing at least \param n bytes.
|
||||
void* request(size_t n);
|
||||
|
||||
/// Retrieve a pointer for reading at least \param n bytes.
|
||||
void* retrieve(size_t n) const;
|
||||
|
||||
/// Write class-type data to buffer (uses placement new).
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*> write(Tp* in, std::enable_if_t<std::is_class<Tp>::value, int> = 0);
|
||||
|
||||
/// Write non-class-type data to buffer (uses memcpy).
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*> write(Tp* in, std::enable_if_t<!std::is_class<Tp>::value, int> = 0);
|
||||
|
||||
/// Request a pointer to an allocation. This is similar to a "write" except the
|
||||
/// memory is uninitialized. Typically used by allocators. If Tp is a class type,
|
||||
/// be sure to use a placement new instead of a memcpy.
|
||||
template <typename Tp>
|
||||
Tp* request();
|
||||
|
||||
/// Read class-type data from buffer (uses placement new).
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*> read(Tp* _dest,
|
||||
std::enable_if_t<std::is_class<Tp>::value, int> = 0) const;
|
||||
|
||||
/// Read non-class-type data from buffer (uses memcpy).
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*> read(Tp* _dest,
|
||||
std::enable_if_t<!std::is_class<Tp>::value, int> = 0) const;
|
||||
|
||||
/// Retrieve a pointer to the head allocation (read).
|
||||
template <typename Tp>
|
||||
Tp* retrieve() const;
|
||||
|
||||
/// Returns number of bytes currently held by the buffer.
|
||||
size_t count() const { return (m_write_count - m_read_count); }
|
||||
|
||||
/// Returns how many bytes are availiable in the buffer.
|
||||
size_t free() const { return (m_size - count()); }
|
||||
|
||||
/// Returns if the buffer is empty.
|
||||
bool is_empty() const { return (count() == 0); }
|
||||
|
||||
/// Returns if the buffer is full.
|
||||
bool is_full() const { return (count() == m_size); }
|
||||
|
||||
/// explicitly configure to use mmap if avail
|
||||
void set_use_mmap(bool);
|
||||
|
||||
/// query whether using mmap
|
||||
bool get_use_mmap() const { return m_use_mmap; }
|
||||
|
||||
std::string as_string() const;
|
||||
|
||||
void save(std::fstream& _fs);
|
||||
void load(std::fstream& _fs);
|
||||
|
||||
private:
|
||||
/// Returns the current write pointer.
|
||||
void* write_ptr(size_t _write_count) const
|
||||
{
|
||||
return static_cast<char*>(m_ptr) + (_write_count % m_size);
|
||||
}
|
||||
|
||||
/// Returns the current read pointer.
|
||||
void* read_ptr(size_t _read_count) const
|
||||
{
|
||||
return static_cast<char*>(m_ptr) + (_read_count % m_size);
|
||||
}
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
bool m_init = false;
|
||||
bool m_use_mmap = true;
|
||||
bool m_use_mmap_explicit = false;
|
||||
void* m_ptr = nullptr;
|
||||
size_t m_size = 0;
|
||||
mutable std::atomic<size_t> m_read_count = 0;
|
||||
std::atomic<size_t> m_write_count = 0;
|
||||
};
|
||||
//
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*>
|
||||
atomic_ring_buffer::write(Tp* in, std::enable_if_t<std::is_class<Tp>::value, int>)
|
||||
{
|
||||
if(in == nullptr || m_ptr == nullptr) return {0, nullptr};
|
||||
|
||||
auto _length = sizeof(Tp);
|
||||
void* _out_p = request(_length);
|
||||
|
||||
if(_out_p == nullptr) return {0, nullptr};
|
||||
|
||||
// Copy in.
|
||||
new(_out_p) Tp{std::move(*in)};
|
||||
|
||||
// pointer in buffer
|
||||
Tp* _out = reinterpret_cast<Tp*>(_out_p);
|
||||
|
||||
return {_length, _out};
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*>
|
||||
atomic_ring_buffer::write(Tp* in, std::enable_if_t<!std::is_class<Tp>::value, int>)
|
||||
{
|
||||
if(in == nullptr || m_ptr == nullptr) return {0, nullptr};
|
||||
|
||||
auto _length = sizeof(Tp);
|
||||
void* _out_p = request(_length);
|
||||
|
||||
if(_out_p == nullptr) return {0, nullptr};
|
||||
|
||||
// Copy in.
|
||||
memcpy(_out_p, in, _length);
|
||||
|
||||
// pointer in buffer
|
||||
Tp* _out = reinterpret_cast<Tp*>(_out_p);
|
||||
|
||||
return {_length, _out};
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
Tp*
|
||||
atomic_ring_buffer::request()
|
||||
{
|
||||
if(m_ptr == nullptr) return nullptr;
|
||||
|
||||
return request(sizeof(Tp));
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*>
|
||||
atomic_ring_buffer::read(Tp* _dest, std::enable_if_t<std::is_class<Tp>::value, int>) const
|
||||
{
|
||||
if(is_empty() || _dest == nullptr) return {0, nullptr};
|
||||
|
||||
auto _length = sizeof(Tp);
|
||||
void* _out_p = retrieve(_length);
|
||||
|
||||
if(_out_p == nullptr) return {0, nullptr};
|
||||
|
||||
// pointer in buffer
|
||||
Tp* in = reinterpret_cast<Tp*>(_out_p);
|
||||
|
||||
// Copy out for BYTE, nothing magic here.
|
||||
*_dest = *in;
|
||||
|
||||
return {_length, in};
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*>
|
||||
atomic_ring_buffer::read(Tp* _dest, std::enable_if_t<!std::is_class<Tp>::value, int>) const
|
||||
{
|
||||
if(is_empty() || _dest == nullptr) return {0, nullptr};
|
||||
|
||||
auto _length = sizeof(Tp);
|
||||
void* _out_p = retrieve(_length);
|
||||
|
||||
if(_out_p == nullptr) return {0, nullptr};
|
||||
|
||||
// pointer in buffer
|
||||
Tp* in = reinterpret_cast<Tp*>(_out_p);
|
||||
|
||||
using Up = typename std::remove_const<Tp>::type;
|
||||
|
||||
// Copy out for BYTE, nothing magic here.
|
||||
Up* _out = const_cast<Up*>(_dest);
|
||||
memcpy(_out, in, _length);
|
||||
|
||||
return {_length, in};
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
Tp*
|
||||
atomic_ring_buffer::retrieve() const
|
||||
{
|
||||
if(m_ptr == nullptr) return nullptr;
|
||||
|
||||
return retrieve(sizeof(Tp));
|
||||
}
|
||||
//
|
||||
} // namespace base
|
||||
//
|
||||
/// \struct tim::data_storage::atomic_ring_buffer
|
||||
/// \brief Ring buffer wrapper around \ref tim::base::atomic_ring_buffer for data of type
|
||||
/// Tp. If the data object size is larger than the page size (typically 4KB), behavior is
|
||||
/// undefined. During initialization, one requests a minimum number of objects and the
|
||||
/// buffer will support that number of object + the remainder of the page, e.g. if a page
|
||||
/// is 1000 bytes, the object is 1 byte, and the buffer is requested to support 1500
|
||||
/// objects, then an allocation supporting 2000 objects (i.e. 2 pages) will be created.
|
||||
template <typename Tp>
|
||||
struct atomic_ring_buffer : private base::atomic_ring_buffer
|
||||
{
|
||||
using base_type = base::atomic_ring_buffer;
|
||||
|
||||
static size_t get_items_per_page();
|
||||
|
||||
atomic_ring_buffer() = default;
|
||||
~atomic_ring_buffer() = default;
|
||||
|
||||
explicit atomic_ring_buffer(bool _use_mmap)
|
||||
: base_type{_use_mmap}
|
||||
{}
|
||||
|
||||
explicit atomic_ring_buffer(size_t _size)
|
||||
: base_type{_size * sizeof(Tp)}
|
||||
{}
|
||||
|
||||
atomic_ring_buffer(size_t _size, bool _use_mmap)
|
||||
: base_type{_size * sizeof(Tp), _use_mmap}
|
||||
{}
|
||||
|
||||
atomic_ring_buffer(const atomic_ring_buffer&);
|
||||
atomic_ring_buffer(atomic_ring_buffer&&) noexcept = default;
|
||||
|
||||
atomic_ring_buffer& operator=(const atomic_ring_buffer&);
|
||||
atomic_ring_buffer& operator=(atomic_ring_buffer&&) noexcept = default;
|
||||
|
||||
/// Returns whether the buffer has been allocated
|
||||
bool is_initialized() const { return base_type::is_initialized(); }
|
||||
|
||||
/// Get the total number of Tp instances supported
|
||||
size_t capacity() const { return (base_type::capacity()) / sizeof(Tp); }
|
||||
|
||||
/// Creates new ring buffer.
|
||||
void init(size_t _size) { base_type::init(_size * sizeof(Tp)); }
|
||||
|
||||
/// Destroy ring buffer.
|
||||
void destroy() { base_type::destroy(); }
|
||||
|
||||
/// Write data to buffer.
|
||||
size_t data_size() const { return sizeof(Tp); }
|
||||
|
||||
/// Write data to buffer. Return pointer to location of write
|
||||
Tp* write(Tp* in) { return base_type::write<Tp>(in).second; }
|
||||
|
||||
/// Read data from buffer. Return pointer to location of read
|
||||
Tp* read(Tp* _dest) const { return base_type::read<Tp>(_dest).second; }
|
||||
|
||||
/// Get an uninitialized address at tail of buffer.
|
||||
Tp* request() { return base_type::request<Tp>(); }
|
||||
|
||||
/// Read data from head of buffer.
|
||||
Tp* retrieve() { return base_type::retrieve<Tp>(); }
|
||||
|
||||
/// Returns number of Tp instances currently held by the buffer.
|
||||
size_t count() const { return (base_type::count()) / sizeof(Tp); }
|
||||
|
||||
/// Returns how many Tp instances are availiable in the buffer.
|
||||
size_t free() const { return (base_type::free()) / sizeof(Tp); }
|
||||
|
||||
/// Returns if the buffer is empty.
|
||||
bool is_empty() const { return base_type::is_empty(); }
|
||||
|
||||
/// Returns if the buffer is full.
|
||||
bool is_full() const { return (base_type::free() < sizeof(Tp)); }
|
||||
|
||||
template <typename... Args>
|
||||
auto emplace(Args&&... args)
|
||||
{
|
||||
Tp _obj{std::forward<Args>(args)...};
|
||||
return write(&_obj);
|
||||
}
|
||||
|
||||
using base_type::get_use_mmap;
|
||||
using base_type::load;
|
||||
using base_type::save;
|
||||
using base_type::set_use_mmap;
|
||||
|
||||
std::string as_string() const
|
||||
{
|
||||
std::ostringstream ss{};
|
||||
size_t _w = std::log10(base_type::capacity()) + 1;
|
||||
ss << std::boolalpha << std::right << "data size: " << std::setw(_w) << data_size()
|
||||
<< " B, is_initialized: " << std::setw(5) << is_initialized()
|
||||
<< ", is_empty: " << std::setw(5) << is_empty() << ", is_full: " << std::setw(5)
|
||||
<< is_full() << ", capacity: " << std::setw(_w) << capacity()
|
||||
<< ", count: " << std::setw(_w) << count() << ", free: " << std::setw(_w) << free()
|
||||
<< ", raw capacity: " << std::setw(_w) << base_type::capacity()
|
||||
<< " B, raw count: " << std::setw(_w) << base_type::count()
|
||||
<< " B, raw free: " << std::setw(_w) << base_type::free()
|
||||
<< " B, pointer: " << std::setw(15) << base_type::m_ptr
|
||||
<< ", raw read count: " << std::setw(_w) << base_type::m_read_count
|
||||
<< ", raw write count: " << std::setw(_w) << base_type::m_write_count;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const atomic_ring_buffer& obj)
|
||||
{
|
||||
return os << obj.as_string();
|
||||
}
|
||||
};
|
||||
//
|
||||
template <typename Tp>
|
||||
size_t
|
||||
atomic_ring_buffer<Tp>::get_items_per_page()
|
||||
{
|
||||
return std::max<size_t>(units::get_page_size() / sizeof(Tp), 1);
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
atomic_ring_buffer<Tp>::atomic_ring_buffer(const atomic_ring_buffer<Tp>& rhs)
|
||||
: base_type{rhs}
|
||||
{
|
||||
size_t _n = rhs.count();
|
||||
char* _end = static_cast<char*>(rhs.m_ptr) + rhs.m_size;
|
||||
for(size_t i = 0; i < _n; ++i)
|
||||
{
|
||||
char* _addr = static_cast<char*>(rhs.read_ptr(m_read_count)) + (i * sizeof(Tp));
|
||||
if((_addr + sizeof(Tp)) > _end) _addr = static_cast<char*>(rhs.m_ptr);
|
||||
Tp* _in = static_cast<Tp*>(static_cast<void*>(_addr));
|
||||
write(_in);
|
||||
}
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
atomic_ring_buffer<Tp>&
|
||||
atomic_ring_buffer<Tp>::operator=(const atomic_ring_buffer<Tp>& rhs)
|
||||
{
|
||||
if(this == &rhs) return *this;
|
||||
|
||||
base_type::operator=(rhs);
|
||||
size_t _n = rhs.count();
|
||||
char* _end = static_cast<char*>(rhs.m_ptr) + rhs.m_size;
|
||||
for(size_t i = 0; i < _n; ++i)
|
||||
{
|
||||
char* _addr = static_cast<char*>(rhs.read_ptr(m_read_count)) + (i * sizeof(Tp));
|
||||
if((_addr + sizeof(Tp)) > _end) _addr = static_cast<char*>(rhs.m_ptr);
|
||||
Tp* _in = static_cast<Tp*>(static_cast<void*>(_addr));
|
||||
write(_in);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
//
|
||||
} // namespace container
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,136 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace container
|
||||
{
|
||||
template <typename Tp>
|
||||
struct c_array
|
||||
{
|
||||
// Construct an array wrapper from a base pointer and array size
|
||||
c_array(Tp* _base, size_t _size)
|
||||
: m_base{_base}
|
||||
, m_size{_size}
|
||||
{}
|
||||
|
||||
~c_array() = default;
|
||||
c_array(const c_array&) = default;
|
||||
c_array& operator=(const c_array&) = default;
|
||||
c_array& operator=(c_array&&) noexcept = default;
|
||||
|
||||
// Get the size of the wrapped array
|
||||
size_t size() const { return m_size; }
|
||||
|
||||
// Access an element by index
|
||||
Tp& operator[](size_t i) { return m_base[i]; }
|
||||
|
||||
// Access an element by index
|
||||
const Tp& operator[](size_t i) const { return m_base[i]; }
|
||||
|
||||
// Access an element by index with bounds check
|
||||
Tp& at(size_t i)
|
||||
{
|
||||
if(i < m_size) return m_base[i];
|
||||
throw std::out_of_range(std::string{typeid(*this).name()} + std::to_string(i) +
|
||||
" exceeds size " + std::to_string(m_size));
|
||||
}
|
||||
|
||||
// Access an element by index with bounds check
|
||||
const Tp& at(size_t i) const
|
||||
{
|
||||
if(i < m_size) return m_base[i];
|
||||
throw std::out_of_range(std::string{typeid(*this).name()} + std::to_string(i) +
|
||||
" exceeds size " + std::to_string(m_size));
|
||||
}
|
||||
|
||||
// Get a slice of this array, from a start index (inclusive) to end index (exclusive)
|
||||
c_array<Tp> slice(size_t start, size_t end) { return c_array<Tp>(&m_base[start], end - start); }
|
||||
|
||||
void pop_front()
|
||||
{
|
||||
++m_base;
|
||||
--m_size;
|
||||
}
|
||||
|
||||
void pop_back() { --m_size; }
|
||||
|
||||
operator Tp*() const { return m_base; }
|
||||
|
||||
// Iterator class for convenient range-based for loop support
|
||||
template <typename Up>
|
||||
struct iterator
|
||||
{
|
||||
// Start the iterator at a given pointer
|
||||
explicit iterator(Tp* p)
|
||||
: m_ptr{p}
|
||||
{}
|
||||
|
||||
// Advance to the next element
|
||||
void operator++() { ++m_ptr; }
|
||||
void operator++(int) { m_ptr++; }
|
||||
|
||||
// Get the current element
|
||||
Up& operator*() const { return *m_ptr; }
|
||||
|
||||
// Compare iterators
|
||||
bool operator==(const iterator& rhs) const { return m_ptr == rhs.m_ptr; }
|
||||
bool operator!=(const iterator& rhs) const { return m_ptr != rhs.m_ptr; }
|
||||
|
||||
private:
|
||||
Tp* m_ptr = nullptr;
|
||||
};
|
||||
|
||||
// Get an iterator positioned at the beginning of the wrapped array
|
||||
iterator<Tp> begin() { return iterator<Tp>{m_base}; }
|
||||
iterator<const Tp> begin() const { return iterator<const Tp>{m_base}; }
|
||||
|
||||
// Get an iterator positioned at the end of the wrapped array
|
||||
iterator<Tp> end() { return iterator<Tp>{&m_base[m_size]}; }
|
||||
iterator<const Tp> end() const { return iterator<const Tp>{&m_base[m_size]}; }
|
||||
|
||||
private:
|
||||
Tp* m_base = nullptr;
|
||||
size_t m_size = 0;
|
||||
};
|
||||
|
||||
// Function for automatic template argument deduction
|
||||
template <typename Tp>
|
||||
c_array<Tp>
|
||||
wrap_c_array(Tp* base, size_t size)
|
||||
{
|
||||
return c_array<Tp>(base, size);
|
||||
}
|
||||
} // namespace container
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,239 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#define ROCPROFILER_IMPORT_TEMPLATE2(template_name)
|
||||
#define ROCPROFILER_IMPORT_TEMPLATE1(template_name)
|
||||
|
||||
// Import a 2-type-argument operator template into boost (if necessary) and
|
||||
// provide a specialization of 'is_chained_base<>' for it.
|
||||
#define ROCPROFILER_OPERATOR_TEMPLATE2(template_name2) \
|
||||
ROCPROFILER_IMPORT_TEMPLATE2(template_name2) \
|
||||
template <typename T, typename U, typename B> \
|
||||
struct is_chained_base<::rocprofiler::container::template_name2<T, U, B>> \
|
||||
{ \
|
||||
using value = ::rocprofiler::container::true_t; \
|
||||
};
|
||||
|
||||
// Import a 1-type-argument operator template into boost (if necessary) and
|
||||
// provide a specialization of 'is_chained_base<>' for it.
|
||||
#define ROCPROFILER_OPERATOR_TEMPLATE1(template_name1) \
|
||||
ROCPROFILER_IMPORT_TEMPLATE1(template_name1) \
|
||||
template <typename T, typename B> \
|
||||
struct is_chained_base<::rocprofiler::container::template_name1<T, B>> \
|
||||
{ \
|
||||
using value = ::rocprofiler::container::true_t; \
|
||||
};
|
||||
|
||||
#define ROCPROFILER_OPERATOR_TEMPLATE(template_name) \
|
||||
template <typename T, \
|
||||
typename U = T, \
|
||||
typename B = empty_base<T>, \
|
||||
typename O = typename is_chained_base<U>::value> \
|
||||
struct template_name; \
|
||||
\
|
||||
template <typename T, typename U, typename B> \
|
||||
struct template_name<T, U, B, false_t> : template_name##2 < T \
|
||||
, U \
|
||||
, B > \
|
||||
{}; \
|
||||
\
|
||||
template <typename T, typename U> \
|
||||
struct template_name<T, U, empty_base<T>, true_t> : template_name##1 < T \
|
||||
, U > \
|
||||
{}; \
|
||||
\
|
||||
template <typename T, typename B> \
|
||||
struct template_name<T, T, B, false_t> : template_name##1 < T \
|
||||
, B > \
|
||||
{}; \
|
||||
\
|
||||
template <typename T, typename U, typename B, typename O> \
|
||||
struct is_chained_base<template_name<T, U, B, O>> \
|
||||
{ \
|
||||
using value = ::rocprofiler::container::true_t; \
|
||||
}; \
|
||||
\
|
||||
ROCPROFILER_OPERATOR_TEMPLATE2(template_name##2) \
|
||||
ROCPROFILER_OPERATOR_TEMPLATE1(template_name##1)
|
||||
|
||||
#define ROCPROFILER_BINARY_OPERATOR_COMMUTATIVE(NAME, OP) \
|
||||
template <typename T, typename U, typename B = empty_base<T>> \
|
||||
struct NAME##2 : B{friend T operator OP(T lhs, const U& rhs){return lhs OP## = rhs; \
|
||||
} \
|
||||
friend T operator OP(const U& lhs, T rhs) { return rhs OP## = lhs; } \
|
||||
} \
|
||||
; \
|
||||
\
|
||||
template <typename T, typename B = empty_base<T>> \
|
||||
struct NAME##1 : B{friend T operator OP(T lhs, const T& rhs){return lhs OP## = rhs; \
|
||||
} \
|
||||
} \
|
||||
;
|
||||
|
||||
#define ROCPROFILER_BINARY_OPERATOR_NON_COMMUTATIVE(NAME, OP) \
|
||||
template <typename T, typename U, typename B = empty_base<T>> \
|
||||
struct NAME##2 : B{friend T operator OP(T lhs, const U& rhs){return lhs OP## = rhs; \
|
||||
} \
|
||||
} \
|
||||
;
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace container
|
||||
{
|
||||
struct true_t
|
||||
{};
|
||||
|
||||
struct false_t
|
||||
{};
|
||||
|
||||
template <typename T>
|
||||
class empty_base
|
||||
{};
|
||||
|
||||
template <typename T>
|
||||
struct is_chained_base
|
||||
{
|
||||
using value = true_t;
|
||||
};
|
||||
|
||||
ROCPROFILER_BINARY_OPERATOR_COMMUTATIVE(addable, +)
|
||||
ROCPROFILER_BINARY_OPERATOR_NON_COMMUTATIVE(subtractable, -)
|
||||
|
||||
ROCPROFILER_OPERATOR_TEMPLATE(addable)
|
||||
|
||||
template <typename T, typename B = empty_base<T>>
|
||||
struct incrementable : B
|
||||
{
|
||||
friend T operator++(T& x, int)
|
||||
{
|
||||
incrementable_type nrv(x);
|
||||
++x;
|
||||
return nrv;
|
||||
}
|
||||
|
||||
private: // The use of this typedef works around a Borland bug
|
||||
typedef T incrementable_type;
|
||||
};
|
||||
|
||||
template <typename T, typename B = empty_base<T>>
|
||||
struct decrementable : B
|
||||
{
|
||||
friend T operator--(T& x, int)
|
||||
{
|
||||
decrementable_type nrv(x);
|
||||
--x;
|
||||
return nrv;
|
||||
}
|
||||
|
||||
private: // The use of this typedef works around a Borland bug
|
||||
typedef T decrementable_type;
|
||||
};
|
||||
|
||||
template <typename T, typename P, typename B = empty_base<T>>
|
||||
struct dereferenceable : B
|
||||
{
|
||||
P operator->() const { return ::std::addressof(*static_cast<const T&>(*this)); }
|
||||
};
|
||||
|
||||
template <typename T, typename I, typename R, typename B = empty_base<T>>
|
||||
struct indexable : B
|
||||
{
|
||||
R operator[](I n) const { return *(static_cast<const T&>(*this) + n); }
|
||||
};
|
||||
|
||||
template <typename T, typename B = empty_base<T>>
|
||||
struct equality_comparable1 : B
|
||||
{
|
||||
friend bool operator!=(const T& x, const T& y) { return !static_cast<bool>(x == y); }
|
||||
};
|
||||
|
||||
template <typename T, typename P, typename B = empty_base<T>>
|
||||
struct input_iteratable : equality_comparable1<T, incrementable<T, dereferenceable<T, P, B>>>
|
||||
{};
|
||||
|
||||
template <typename T, typename B = empty_base<T>>
|
||||
struct output_iteratable : incrementable<T, B>
|
||||
{};
|
||||
|
||||
template <typename T, typename P, typename B = empty_base<T>>
|
||||
struct forward_iteratable : input_iteratable<T, P, B>
|
||||
{};
|
||||
|
||||
template <typename T, typename P, typename B = empty_base<T>>
|
||||
struct bidirectional_iteratable : forward_iteratable<T, P, decrementable<T, B>>
|
||||
{};
|
||||
|
||||
// template <typename T, typename U, typename B = empty_base<T>>
|
||||
// struct subtractable2;
|
||||
|
||||
template <typename T, typename U, typename B = empty_base<T>>
|
||||
struct additive2 : addable2<T, U, subtractable2<T, U, B>>
|
||||
{};
|
||||
|
||||
template <typename T, typename B = empty_base<T>>
|
||||
struct less_than_comparable1 : B
|
||||
{
|
||||
friend bool operator>(const T& x, const T& y) { return y < x; }
|
||||
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); }
|
||||
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
|
||||
};
|
||||
|
||||
// To avoid repeated derivation from equality_comparable,
|
||||
// which is an indirect base typename of bidirectional_iterable,
|
||||
// random_access_iteratable must not be derived from totally_ordered1
|
||||
// but from less_than_comparable1 only. (Helmut Zeisel, 02-Dec-2001)
|
||||
template <typename T, typename P, typename D, typename R, typename B = empty_base<T>>
|
||||
struct random_access_iteratable
|
||||
: bidirectional_iteratable<T, P, less_than_comparable1<T, additive2<T, D, indexable<T, D, R, B>>>>
|
||||
{};
|
||||
|
||||
template <typename CategoryT,
|
||||
typename Tp,
|
||||
typename DistanceT = std::ptrdiff_t,
|
||||
typename PointerT = Tp*,
|
||||
typename ReferenceT = Tp&>
|
||||
struct iterator_helper
|
||||
{
|
||||
using iterator_category = CategoryT;
|
||||
using value_type = Tp;
|
||||
using difference_type = DistanceT;
|
||||
using pointer = PointerT;
|
||||
using reference = ReferenceT;
|
||||
};
|
||||
|
||||
template <typename T, typename V, typename D = std::ptrdiff_t, typename P = V*, typename R = V&>
|
||||
struct random_access_iterator_helper
|
||||
: random_access_iteratable<T, P, D, R, iterator_helper<std::random_access_iterator_tag, V, D, P, R>>
|
||||
{
|
||||
friend D requires_difference_operator(const T& x, const T& y) { return x - y; }
|
||||
}; // random_access_iterator_helper
|
||||
} // namespace container
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,289 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020, The Regents of the University of California,
|
||||
// through Lawrence Berkeley National Laboratory (subject to receipt of any
|
||||
// required approvals from the U.S. Dept. of Energy). All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "ring_buffer.hpp"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace container
|
||||
{
|
||||
namespace base
|
||||
{
|
||||
ring_buffer::ring_buffer(size_t _size, bool _use_mmap)
|
||||
{
|
||||
set_use_mmap(_use_mmap);
|
||||
init(_size);
|
||||
}
|
||||
|
||||
ring_buffer::~ring_buffer() { destroy(); }
|
||||
|
||||
ring_buffer::ring_buffer(const ring_buffer& rhs)
|
||||
: m_use_mmap{rhs.m_use_mmap}
|
||||
, m_use_mmap_explicit{rhs.m_use_mmap_explicit}
|
||||
{
|
||||
init(rhs.m_size);
|
||||
}
|
||||
|
||||
ring_buffer::ring_buffer(ring_buffer&& rhs) noexcept
|
||||
: m_init{rhs.m_init}
|
||||
, m_use_mmap{rhs.m_use_mmap}
|
||||
, m_use_mmap_explicit{rhs.m_use_mmap_explicit}
|
||||
, m_ptr{rhs.m_ptr}
|
||||
, m_size{rhs.m_size}
|
||||
, m_read_count{rhs.m_read_count}
|
||||
, m_write_count{rhs.m_write_count}
|
||||
{
|
||||
rhs.reset();
|
||||
}
|
||||
|
||||
ring_buffer&
|
||||
ring_buffer::operator=(const ring_buffer& rhs)
|
||||
{
|
||||
if(this == &rhs) return *this;
|
||||
destroy();
|
||||
m_use_mmap = rhs.m_use_mmap;
|
||||
m_use_mmap_explicit = rhs.m_use_mmap_explicit;
|
||||
init(rhs.m_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ring_buffer&
|
||||
ring_buffer::operator=(ring_buffer&& rhs) noexcept
|
||||
{
|
||||
if(this == &rhs) return *this;
|
||||
destroy();
|
||||
m_init = rhs.m_init;
|
||||
m_use_mmap = rhs.m_use_mmap;
|
||||
m_use_mmap_explicit = rhs.m_use_mmap_explicit;
|
||||
m_ptr = rhs.m_ptr;
|
||||
m_size = rhs.m_size;
|
||||
m_read_count = rhs.m_read_count;
|
||||
m_write_count = rhs.m_write_count;
|
||||
rhs.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
ring_buffer::init(size_t _size)
|
||||
{
|
||||
if(m_init)
|
||||
throw std::runtime_error("tim::base::ring_buffer::init(size_t) :: already initialized");
|
||||
|
||||
m_init = true;
|
||||
|
||||
// Round up to multiple of page size.
|
||||
_size += units::get_page_size() - ((_size % units::get_page_size() > 0)
|
||||
? (_size % units::get_page_size())
|
||||
: units::get_page_size());
|
||||
|
||||
if((_size % units::get_page_size()) > 0)
|
||||
{
|
||||
std::ostringstream _oss{};
|
||||
_oss << "Error! size is not a multiple of page size: " << _size << " % "
|
||||
<< units::get_page_size() << " = " << (_size % units::get_page_size());
|
||||
throw std::runtime_error(_oss.str());
|
||||
}
|
||||
|
||||
m_size = _size;
|
||||
m_read_count = 0;
|
||||
m_write_count = 0;
|
||||
|
||||
if(!m_use_mmap_explicit) m_use_mmap = get_env("ROCPROFILER_USE_MMAP", m_use_mmap);
|
||||
|
||||
if(!m_use_mmap)
|
||||
{
|
||||
m_ptr = malloc(m_size * sizeof(char));
|
||||
return;
|
||||
}
|
||||
|
||||
// Map twice the buffer size.
|
||||
if((m_ptr =
|
||||
mmap(nullptr, m_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) ==
|
||||
MAP_FAILED)
|
||||
{
|
||||
destroy();
|
||||
auto _err = errno;
|
||||
// TIMEMORY_PRINTF_FATAL(stderr, "Error using mmap: %s\n", strerror(_err));
|
||||
throw std::runtime_error(strerror(_err));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ring_buffer::destroy()
|
||||
{
|
||||
if(m_ptr && m_init)
|
||||
{
|
||||
if(!m_use_mmap)
|
||||
{
|
||||
::free(m_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unmap the mapped virtual memmory.
|
||||
auto ret = munmap(m_ptr, m_size);
|
||||
if(ret != 0) perror("munmap");
|
||||
}
|
||||
}
|
||||
m_init = false;
|
||||
m_size = 0;
|
||||
m_read_count = 0;
|
||||
m_write_count = 0;
|
||||
m_ptr = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ring_buffer::set_use_mmap(bool _v)
|
||||
{
|
||||
if(!m_init)
|
||||
{
|
||||
m_use_mmap = _v;
|
||||
m_use_mmap_explicit = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("tim::base::ring_buffer::set_use_mmap(bool) cannot be "
|
||||
"called after initialization");
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
ring_buffer::as_string() const
|
||||
{
|
||||
std::ostringstream ss{};
|
||||
ss << std::boolalpha << "is_initialized: " << is_initialized() << ", capacity: " << capacity()
|
||||
<< ", count: " << count() << ", free: " << free() << ", is_empty: " << is_empty()
|
||||
<< ", is_full: " << is_full() << ", pointer: " << m_ptr << ", read count: " << m_read_count
|
||||
<< ", write count: " << m_write_count;
|
||||
return ss.str();
|
||||
}
|
||||
//
|
||||
|
||||
void*
|
||||
ring_buffer::request(size_t _length)
|
||||
{
|
||||
if(m_ptr == nullptr) return nullptr;
|
||||
|
||||
// Make sure we don't put in more than there's room for, by writing no
|
||||
// more than there is free.
|
||||
if(_length > free())
|
||||
throw std::runtime_error("heap-buffer-overflow :: ring buffer is full. read data "
|
||||
"to avoid data corruption");
|
||||
|
||||
// if write count is at the tail of buffer, bump to the end of buffer
|
||||
auto _modulo = m_size - (m_write_count % m_size);
|
||||
if(_modulo < _length) m_write_count += _modulo;
|
||||
|
||||
// pointer in buffer
|
||||
void* _out = write_ptr();
|
||||
|
||||
// Update write count
|
||||
m_write_count += _length;
|
||||
|
||||
return _out;
|
||||
}
|
||||
//
|
||||
|
||||
void*
|
||||
ring_buffer::retrieve(size_t _length)
|
||||
{
|
||||
if(m_ptr == nullptr) return nullptr;
|
||||
|
||||
// Make sure we don't put in more than there's room for, by writing no
|
||||
// more than there is free.
|
||||
if(_length > count()) throw std::runtime_error("ring buffer is empty");
|
||||
|
||||
// if read count is at the tail of buffer, bump to the end of buffer
|
||||
auto _modulo = m_size - (m_read_count % m_size);
|
||||
if(_modulo < _length) m_read_count += _modulo;
|
||||
|
||||
// pointer in buffer
|
||||
void* _out = read_ptr();
|
||||
|
||||
// Update write count
|
||||
m_read_count += _length;
|
||||
|
||||
return _out;
|
||||
}
|
||||
//
|
||||
|
||||
size_t
|
||||
ring_buffer::rewind(size_t n) const
|
||||
{
|
||||
if(n > m_read_count) n = m_read_count;
|
||||
m_read_count -= n;
|
||||
return n;
|
||||
}
|
||||
//
|
||||
|
||||
void
|
||||
ring_buffer::reset()
|
||||
{
|
||||
m_init = false;
|
||||
m_ptr = nullptr;
|
||||
m_size = 0;
|
||||
m_read_count = 0;
|
||||
m_write_count = 0;
|
||||
}
|
||||
//
|
||||
|
||||
void
|
||||
ring_buffer::save(std::fstream& _fs)
|
||||
{
|
||||
_fs.write(reinterpret_cast<char*>(&m_use_mmap), sizeof(m_use_mmap));
|
||||
_fs.write(reinterpret_cast<char*>(&m_use_mmap_explicit), sizeof(m_use_mmap_explicit));
|
||||
_fs.write(reinterpret_cast<char*>(&m_size), sizeof(m_size));
|
||||
_fs.write(reinterpret_cast<char*>(&m_read_count), sizeof(m_read_count));
|
||||
_fs.write(reinterpret_cast<char*>(&m_write_count), sizeof(m_write_count));
|
||||
_fs.write(reinterpret_cast<char*>(m_ptr), m_size * sizeof(char));
|
||||
}
|
||||
//
|
||||
|
||||
void
|
||||
ring_buffer::load(std::fstream& _fs)
|
||||
{
|
||||
destroy();
|
||||
|
||||
_fs.read(reinterpret_cast<char*>(&m_use_mmap), sizeof(m_use_mmap));
|
||||
_fs.read(reinterpret_cast<char*>(&m_use_mmap_explicit), sizeof(m_use_mmap_explicit));
|
||||
_fs.read(reinterpret_cast<char*>(&m_size), sizeof(m_size));
|
||||
|
||||
init(m_size);
|
||||
if(!m_ptr) m_ptr = malloc(m_size);
|
||||
|
||||
_fs.read(reinterpret_cast<char*>(&m_read_count), sizeof(m_read_count));
|
||||
_fs.read(reinterpret_cast<char*>(&m_write_count), sizeof(m_write_count));
|
||||
_fs.read(reinterpret_cast<char*>(m_ptr), m_size * sizeof(char));
|
||||
}
|
||||
} // namespace base
|
||||
} // namespace container
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,495 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020, The Regents of the University of California,
|
||||
// through Lawrence Berkeley National Laboratory (subject to receipt of any
|
||||
// required approvals from the U.S. Dept. of Energy). All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lib/common/environment.hpp"
|
||||
#include "lib/common/units.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace container
|
||||
{
|
||||
template <typename Tp>
|
||||
struct ring_buffer;
|
||||
//
|
||||
namespace base
|
||||
{
|
||||
/// \struct tim::base::ring_buffer
|
||||
/// \brief Ring buffer implementation, with support for mmap as backend (Linux only).
|
||||
struct ring_buffer
|
||||
{
|
||||
template <typename Tp>
|
||||
friend struct container::ring_buffer;
|
||||
|
||||
ring_buffer() = default;
|
||||
explicit ring_buffer(bool _use_mmap) { set_use_mmap(_use_mmap); }
|
||||
explicit ring_buffer(size_t _size) { init(_size); }
|
||||
ring_buffer(size_t _size, bool _use_mmap);
|
||||
|
||||
~ring_buffer();
|
||||
|
||||
ring_buffer(const ring_buffer&);
|
||||
ring_buffer& operator=(const ring_buffer&);
|
||||
|
||||
ring_buffer(ring_buffer&&) noexcept;
|
||||
ring_buffer& operator=(ring_buffer&&) noexcept;
|
||||
|
||||
/// Returns whether the buffer has been allocated
|
||||
bool is_initialized() const { return m_init; }
|
||||
|
||||
/// Get the total number of bytes supported
|
||||
size_t capacity() const { return m_size; }
|
||||
|
||||
/// Creates new ring buffer.
|
||||
void init(size_t size);
|
||||
|
||||
/// Destroy ring buffer.
|
||||
void destroy();
|
||||
|
||||
/// Write class-type data to buffer (uses placement new).
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*> write(Tp* in, std::enable_if_t<std::is_class<Tp>::value, int> = 0);
|
||||
|
||||
/// Write non-class-type data to buffer (uses memcpy).
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*> write(Tp* in, std::enable_if_t<!std::is_class<Tp>::value, int> = 0);
|
||||
|
||||
/// Request a pointer to an allocation. This is similar to a "write" except the
|
||||
/// memory is uninitialized. Typically used by allocators. If Tp is a class type,
|
||||
/// be sure to use a placement new instead of a memcpy.
|
||||
template <typename Tp>
|
||||
Tp* request();
|
||||
|
||||
/// Request a pointer to an allocation for at least \param n bytes.
|
||||
void* request(size_t n);
|
||||
|
||||
/// Read class-type data from buffer (uses placement new).
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*> read(Tp* out, std::enable_if_t<std::is_class<Tp>::value, int> = 0) const;
|
||||
|
||||
/// Read non-class-type data from buffer (uses memcpy).
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*> read(Tp* out,
|
||||
std::enable_if_t<!std::is_class<Tp>::value, int> = 0) const;
|
||||
|
||||
/// Retrieve a pointer to the head allocation (read).
|
||||
template <typename Tp>
|
||||
Tp* retrieve();
|
||||
|
||||
/// Retrieve a pointer to the head allocation of at least \param n bytes (read).
|
||||
void* retrieve(size_t n);
|
||||
|
||||
/// Returns number of bytes currently held by the buffer.
|
||||
size_t count() const { return (m_write_count - m_read_count); }
|
||||
|
||||
/// Returns how many bytes are availiable in the buffer.
|
||||
size_t free() const { return (m_size - count()); }
|
||||
|
||||
/// Returns if the buffer is empty.
|
||||
bool is_empty() const { return (count() == 0); }
|
||||
|
||||
/// Returns if the buffer is full.
|
||||
bool is_full() const { return (count() == m_size); }
|
||||
|
||||
/// Rewind the read position n bytes
|
||||
size_t rewind(size_t n) const;
|
||||
|
||||
/// explicitly configure to use mmap if avail
|
||||
void set_use_mmap(bool);
|
||||
|
||||
/// query whether using mmap
|
||||
bool get_use_mmap() const { return m_use_mmap; }
|
||||
|
||||
std::string as_string() const;
|
||||
|
||||
void save(std::fstream& _fs);
|
||||
void load(std::fstream& _fs);
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const ring_buffer& obj)
|
||||
{
|
||||
return os << obj.as_string();
|
||||
}
|
||||
|
||||
private:
|
||||
/// Returns the current write pointer.
|
||||
void* write_ptr() const { return static_cast<char*>(m_ptr) + (m_write_count % m_size); }
|
||||
|
||||
/// Returns the current read pointer.
|
||||
void* read_ptr() const { return static_cast<char*>(m_ptr) + (m_read_count % m_size); }
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
bool m_init = false;
|
||||
bool m_use_mmap = true;
|
||||
bool m_use_mmap_explicit = false;
|
||||
void* m_ptr = nullptr;
|
||||
size_t m_size = 0;
|
||||
mutable size_t m_read_count = 0;
|
||||
size_t m_write_count = 0;
|
||||
};
|
||||
//
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*>
|
||||
ring_buffer::write(Tp* in, std::enable_if_t<std::is_class<Tp>::value, int>)
|
||||
{
|
||||
if(in == nullptr || m_ptr == nullptr) return {0, nullptr};
|
||||
|
||||
auto _length = sizeof(Tp);
|
||||
|
||||
// Make sure we don't put in more than there's room for, by writing no
|
||||
// more than there is free.
|
||||
if(_length > free())
|
||||
throw std::runtime_error("heap-buffer-overflow :: ring buffer is full. read data "
|
||||
"to avoid data corruption");
|
||||
|
||||
// if write count is at the tail of buffer, bump to the end of buffer
|
||||
auto _modulo = m_size - (m_write_count % m_size);
|
||||
if(_modulo < _length) m_write_count += _modulo;
|
||||
|
||||
// pointer in buffer
|
||||
Tp* out = reinterpret_cast<Tp*>(write_ptr());
|
||||
|
||||
// Copy in.
|
||||
new((void*) out) Tp{std::move(*in)};
|
||||
|
||||
// Update write count
|
||||
m_write_count += _length;
|
||||
|
||||
return {_length, out};
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*>
|
||||
ring_buffer::write(Tp* in, std::enable_if_t<!std::is_class<Tp>::value, int>)
|
||||
{
|
||||
if(in == nullptr || m_ptr == nullptr) return {0, nullptr};
|
||||
|
||||
auto _length = sizeof(Tp);
|
||||
|
||||
// Make sure we don't put in more than there's room for, by writing no
|
||||
// more than there is free.
|
||||
if(_length > free())
|
||||
throw std::runtime_error("heap-buffer-overflow :: ring buffer is full. read data "
|
||||
"to avoid data corruption");
|
||||
|
||||
// if write count is at the tail of buffer, bump to the end of buffer
|
||||
auto _modulo = m_size - (m_write_count % m_size);
|
||||
if(_modulo < _length) m_write_count += _modulo;
|
||||
|
||||
// pointer in buffer
|
||||
Tp* out = reinterpret_cast<Tp*>(write_ptr());
|
||||
|
||||
// Copy in.
|
||||
memcpy((void*) out, in, _length);
|
||||
|
||||
// Update write count
|
||||
m_write_count += _length;
|
||||
|
||||
return {_length, out};
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
Tp*
|
||||
ring_buffer::request()
|
||||
{
|
||||
if(m_ptr == nullptr) return nullptr;
|
||||
|
||||
auto _length = sizeof(Tp);
|
||||
|
||||
// Make sure we don't put in more than there's room for, by writing no
|
||||
// more than there is free.
|
||||
if(_length > free())
|
||||
throw std::runtime_error("heap-buffer-overflow :: ring buffer is full. read data "
|
||||
"to avoid data corruption");
|
||||
|
||||
// if write count is at the tail of buffer, bump to the end of buffer
|
||||
auto _modulo = m_size - (m_write_count % m_size);
|
||||
if(_modulo < _length) m_write_count += _modulo;
|
||||
|
||||
// pointer in buffer
|
||||
Tp* _out = reinterpret_cast<Tp*>(write_ptr());
|
||||
|
||||
// Update write count
|
||||
m_write_count += _length;
|
||||
|
||||
return _out;
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*>
|
||||
ring_buffer::read(Tp* out, std::enable_if_t<std::is_class<Tp>::value, int>) const
|
||||
{
|
||||
if(is_empty() || out == nullptr) return {0, nullptr};
|
||||
|
||||
auto _length = sizeof(Tp);
|
||||
|
||||
// Make sure we do not read out more than there is actually in the buffer.
|
||||
if(_length > count()) throw std::runtime_error("ring buffer is empty");
|
||||
|
||||
// if read count is at the tail of buffer, bump to the end of buffer
|
||||
auto _modulo = m_size - (m_read_count % m_size);
|
||||
if(_modulo < _length) m_read_count += _modulo;
|
||||
|
||||
// pointer in buffer
|
||||
Tp* in = reinterpret_cast<Tp*>(read_ptr());
|
||||
|
||||
// Copy out for BYTE, nothing magic here.
|
||||
*out = *in;
|
||||
|
||||
// Update read count.
|
||||
m_read_count += _length;
|
||||
|
||||
return {_length, in};
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
std::pair<size_t, Tp*>
|
||||
ring_buffer::read(Tp* out, std::enable_if_t<!std::is_class<Tp>::value, int>) const
|
||||
{
|
||||
if(is_empty() || out == nullptr) return {0, nullptr};
|
||||
|
||||
auto _length = sizeof(Tp);
|
||||
|
||||
using Up = typename std::remove_const<Tp>::type;
|
||||
|
||||
// Make sure we do not read out more than there is actually in the buffer.
|
||||
if(_length > count()) throw std::runtime_error("ring buffer is empty");
|
||||
|
||||
// if read count is at the tail of buffer, bump to the end of buffer
|
||||
auto _modulo = m_size - (m_read_count % m_size);
|
||||
if(_modulo < _length) m_read_count += _modulo;
|
||||
|
||||
// pointer in buffer
|
||||
Tp* in = reinterpret_cast<Tp*>(read_ptr());
|
||||
|
||||
// Copy out for BYTE, nothing magic here.
|
||||
Up* _out = const_cast<Up*>(out);
|
||||
memcpy(_out, in, _length);
|
||||
|
||||
// Update read count.
|
||||
m_read_count += _length;
|
||||
|
||||
return {_length, in};
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
Tp*
|
||||
ring_buffer::retrieve()
|
||||
{
|
||||
if(m_ptr == nullptr) return nullptr;
|
||||
|
||||
auto _length = sizeof(Tp);
|
||||
|
||||
// Make sure we don't put in more than there's room for, by writing no
|
||||
// more than there is free.
|
||||
if(_length > count()) throw std::runtime_error("ring buffer is empty");
|
||||
|
||||
// if read count is at the tail of buffer, bump to the end of buffer
|
||||
auto _modulo = m_size - (m_read_count % m_size);
|
||||
if(_modulo < _length) m_read_count += _modulo;
|
||||
|
||||
// pointer in buffer
|
||||
Tp* _out = reinterpret_cast<Tp*>(read_ptr());
|
||||
|
||||
// Update write count
|
||||
m_read_count += _length;
|
||||
|
||||
return _out;
|
||||
}
|
||||
//
|
||||
} // namespace base
|
||||
///
|
||||
/// \struct rocprofiler::container::ring_buffer
|
||||
/// \brief Ring buffer wrapper around \ref tim::base::ring_buffer for data of type Tp. If
|
||||
/// the data object size is larger than the page size (typically 4KB), behavior is
|
||||
/// undefined. During initialization, one requests a minimum number of objects and the
|
||||
/// buffer will support that number of object + the remainder of the page, e.g. if a page
|
||||
/// is 1000 bytes, the object is 1 byte, and the buffer is requested to support 1500
|
||||
/// objects, then an allocation supporting 2000 objects (i.e. 2 pages) will be created.
|
||||
template <typename Tp>
|
||||
struct ring_buffer : private base::ring_buffer
|
||||
{
|
||||
using base_type = base::ring_buffer;
|
||||
|
||||
static size_t get_items_per_page();
|
||||
|
||||
ring_buffer() = default;
|
||||
~ring_buffer() = default;
|
||||
|
||||
explicit ring_buffer(bool _use_mmap)
|
||||
: base_type{_use_mmap}
|
||||
{}
|
||||
|
||||
explicit ring_buffer(size_t _size)
|
||||
: base_type{_size * sizeof(Tp)}
|
||||
{}
|
||||
|
||||
ring_buffer(size_t _size, bool _use_mmap)
|
||||
: base_type{_size * sizeof(Tp), _use_mmap}
|
||||
{}
|
||||
|
||||
ring_buffer(const ring_buffer&);
|
||||
ring_buffer(ring_buffer&&) noexcept = default;
|
||||
|
||||
ring_buffer& operator=(const ring_buffer&);
|
||||
ring_buffer& operator=(ring_buffer&&) noexcept = default;
|
||||
|
||||
/// Returns whether the buffer has been allocated
|
||||
bool is_initialized() const { return base_type::is_initialized(); }
|
||||
|
||||
/// Get the total number of Tp instances supported
|
||||
size_t capacity() const { return (base_type::capacity()) / sizeof(Tp); }
|
||||
|
||||
/// Creates new ring buffer.
|
||||
void init(size_t _size) { base_type::init(_size * sizeof(Tp)); }
|
||||
|
||||
/// Destroy ring buffer.
|
||||
void destroy() { base_type::destroy(); }
|
||||
|
||||
/// Write data to buffer.
|
||||
size_t data_size() const { return sizeof(Tp); }
|
||||
|
||||
/// Write data to buffer. Return pointer to location of write
|
||||
Tp* write(Tp* in) { return base_type::write<Tp>(in).second; }
|
||||
|
||||
/// Read data from buffer. Return pointer to location of read
|
||||
Tp* read(Tp* out) const { return base_type::read<Tp>(out).second; }
|
||||
|
||||
/// Get an uninitialized address at tail of buffer.
|
||||
Tp* request() { return base_type::request<Tp>(); }
|
||||
|
||||
/// Read data from head of buffer.
|
||||
Tp* retrieve() { return base_type::retrieve<Tp>(); }
|
||||
|
||||
/// Returns number of Tp instances currently held by the buffer.
|
||||
size_t count() const { return (base_type::count()) / sizeof(Tp); }
|
||||
|
||||
/// Returns how many Tp instances are availiable in the buffer.
|
||||
size_t free() const { return (base_type::free()) / sizeof(Tp); }
|
||||
|
||||
/// Returns if the buffer is empty.
|
||||
bool is_empty() const { return base_type::is_empty(); }
|
||||
|
||||
/// Returns if the buffer is full.
|
||||
bool is_full() const { return (base_type::free() < sizeof(Tp)); }
|
||||
|
||||
/// Rewinds the read pointer
|
||||
size_t rewind(size_t n) const { return base_type::rewind(n); }
|
||||
|
||||
template <typename... Args>
|
||||
auto emplace(Args&&... args)
|
||||
{
|
||||
Tp _obj{std::forward<Args>(args)...};
|
||||
return write(&_obj);
|
||||
}
|
||||
|
||||
using base_type::get_use_mmap;
|
||||
using base_type::load;
|
||||
using base_type::save;
|
||||
using base_type::set_use_mmap;
|
||||
|
||||
std::string as_string() const
|
||||
{
|
||||
std::ostringstream ss{};
|
||||
size_t _w = std::log10(base_type::capacity()) + 1;
|
||||
ss << std::boolalpha << std::right << "data size: " << std::setw(_w) << data_size()
|
||||
<< " B, is_initialized: " << std::setw(5) << is_initialized()
|
||||
<< ", is_empty: " << std::setw(5) << is_empty() << ", is_full: " << std::setw(5)
|
||||
<< is_full() << ", capacity: " << std::setw(_w) << capacity()
|
||||
<< ", count: " << std::setw(_w) << count() << ", free: " << std::setw(_w) << free()
|
||||
<< ", raw capacity: " << std::setw(_w) << base_type::capacity()
|
||||
<< " B, raw count: " << std::setw(_w) << base_type::count()
|
||||
<< " B, raw free: " << std::setw(_w) << base_type::free()
|
||||
<< " B, pointer: " << std::setw(15) << base_type::m_ptr
|
||||
<< ", raw read count: " << std::setw(_w) << base_type::m_read_count
|
||||
<< ", raw write count: " << std::setw(_w) << base_type::m_write_count;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const ring_buffer& obj)
|
||||
{
|
||||
return os << obj.as_string();
|
||||
}
|
||||
};
|
||||
//
|
||||
template <typename Tp>
|
||||
size_t
|
||||
ring_buffer<Tp>::get_items_per_page()
|
||||
{
|
||||
return std::max<size_t>(units::get_page_size() / sizeof(Tp), 1);
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
ring_buffer<Tp>::ring_buffer(const ring_buffer<Tp>& rhs)
|
||||
: base_type{rhs}
|
||||
{
|
||||
size_t _n = rhs.count();
|
||||
char* _end = static_cast<char*>(rhs.m_ptr) + rhs.m_size;
|
||||
for(size_t i = 0; i < _n; ++i)
|
||||
{
|
||||
char* _addr = static_cast<char*>(rhs.read_ptr()) + (i * sizeof(Tp));
|
||||
if((_addr + sizeof(Tp)) > _end) _addr = static_cast<char*>(rhs.m_ptr);
|
||||
Tp* _in = static_cast<Tp*>(static_cast<void*>(_addr));
|
||||
write(_in);
|
||||
}
|
||||
}
|
||||
//
|
||||
template <typename Tp>
|
||||
ring_buffer<Tp>&
|
||||
ring_buffer<Tp>::operator=(const ring_buffer<Tp>& rhs)
|
||||
{
|
||||
if(this == &rhs) return *this;
|
||||
|
||||
base_type::operator=(rhs);
|
||||
size_t _n = rhs.count();
|
||||
char* _end = static_cast<char*>(rhs.m_ptr) + rhs.m_size;
|
||||
for(size_t i = 0; i < _n; ++i)
|
||||
{
|
||||
char* _addr = static_cast<char*>(rhs.read_ptr()) + (i * sizeof(Tp));
|
||||
if((_addr + sizeof(Tp)) > _end) _addr = static_cast<char*>(rhs.m_ptr);
|
||||
Tp* _in = static_cast<Tp*>(static_cast<void*>(_addr));
|
||||
write(_in);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
//
|
||||
} // namespace container
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,389 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lib/common/container/operators.hpp"
|
||||
#include "lib/common/container/static_vector.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace container
|
||||
{
|
||||
template <typename Tp, size_t ChunkSizeV = 64>
|
||||
class stable_vector
|
||||
{
|
||||
public:
|
||||
using value_type = Tp;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using size_type = size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
static constexpr const size_t chunk_size = ChunkSizeV;
|
||||
|
||||
private:
|
||||
template <size_t N>
|
||||
struct is_pow2
|
||||
{
|
||||
static constexpr bool value = (N & (N - 1)) == 0;
|
||||
};
|
||||
|
||||
static_assert(ChunkSizeV > 0, "ChunkSize needs to be greater than zero");
|
||||
static_assert(is_pow2<ChunkSizeV>::value, "ChunkSize needs to be a power of 2");
|
||||
|
||||
using this_type = stable_vector<Tp, ChunkSizeV>;
|
||||
using const_this_type = const stable_vector<Tp, ChunkSizeV>;
|
||||
|
||||
template <typename ContainerT>
|
||||
struct iterator_base
|
||||
{
|
||||
iterator_base(ContainerT* c = nullptr, size_type i = 0)
|
||||
: m_container(c)
|
||||
, m_index(i)
|
||||
{}
|
||||
|
||||
iterator_base& operator+=(size_type i)
|
||||
{
|
||||
m_index += i;
|
||||
return *this;
|
||||
}
|
||||
iterator_base& operator-=(size_type i)
|
||||
{
|
||||
m_index -= i;
|
||||
return *this;
|
||||
}
|
||||
iterator_base& operator++()
|
||||
{
|
||||
++m_index;
|
||||
return *this;
|
||||
}
|
||||
iterator_base& operator--()
|
||||
{
|
||||
--m_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
difference_type operator-(const iterator_base& it)
|
||||
{
|
||||
assert(m_container == it.m_container);
|
||||
return m_index - it.m_index;
|
||||
}
|
||||
|
||||
bool operator<(const iterator_base& it) const
|
||||
{
|
||||
assert(m_container == it.m_container);
|
||||
return m_index < it.m_index;
|
||||
}
|
||||
bool operator==(const iterator_base& it) const
|
||||
{
|
||||
return m_container == it.m_container && m_index == it.m_index;
|
||||
}
|
||||
|
||||
protected:
|
||||
ContainerT* m_container;
|
||||
size_type m_index;
|
||||
};
|
||||
|
||||
public:
|
||||
struct const_iterator;
|
||||
|
||||
struct iterator
|
||||
: public iterator_base<this_type>
|
||||
//, std::iterator<std::random_access_iterator_tag, value_type>
|
||||
, public random_access_iterator_helper<iterator, value_type>
|
||||
{
|
||||
using iterator_base<this_type>::iterator_base;
|
||||
friend struct const_iterator;
|
||||
|
||||
reference operator*() { return (*this->m_container)[this->m_index]; }
|
||||
};
|
||||
|
||||
struct const_iterator
|
||||
: public iterator_base<const_this_type>
|
||||
//, std::iterator<std::random_access_iterator_tag, const value_type>
|
||||
, public random_access_iterator_helper<const_iterator, const value_type>
|
||||
{
|
||||
using iterator_base<const_this_type>::iterator_base;
|
||||
|
||||
explicit const_iterator(const iterator& it)
|
||||
: iterator_base<const_this_type>(it.m_container, it.m_index)
|
||||
{}
|
||||
|
||||
const_reference operator*() const { return (*this->m_container)[this->m_index]; }
|
||||
|
||||
bool operator==(const const_iterator& it) const
|
||||
{
|
||||
return iterator_base<const_this_type>::operator==(it);
|
||||
}
|
||||
|
||||
friend bool operator==(const iterator& l, const const_iterator& r) { return r == l; }
|
||||
};
|
||||
|
||||
stable_vector() = default;
|
||||
explicit stable_vector(size_type count, const Tp& value);
|
||||
explicit stable_vector(size_type count);
|
||||
|
||||
template <typename InputItrT,
|
||||
typename = std::enable_if_t<
|
||||
std::is_convertible<typename std::iterator_traits<InputItrT>::iterator_category,
|
||||
std::input_iterator_tag>::value>>
|
||||
stable_vector(InputItrT first, InputItrT last);
|
||||
|
||||
explicit stable_vector(std::initializer_list<Tp>);
|
||||
|
||||
stable_vector(const stable_vector& other);
|
||||
stable_vector(stable_vector&& other) noexcept;
|
||||
|
||||
stable_vector& operator=(stable_vector v);
|
||||
|
||||
iterator begin() noexcept { return {this, 0}; }
|
||||
const_iterator begin() const noexcept { return {this, 0}; }
|
||||
const_iterator cbegin() const noexcept { return begin(); }
|
||||
|
||||
iterator end() noexcept { return {this, size()}; }
|
||||
const_iterator end() const noexcept { return {this, size()}; }
|
||||
const_iterator cend() const noexcept { return end(); }
|
||||
|
||||
size_type size() const noexcept
|
||||
{
|
||||
return empty() ? 0 : (m_chunks.size() - 1) * ChunkSizeV + m_chunks.back()->size();
|
||||
}
|
||||
size_type max_size() const noexcept { return std::numeric_limits<size_type>::max(); }
|
||||
size_type capacity() const noexcept { return m_chunks.size() * ChunkSizeV; }
|
||||
|
||||
bool empty() const noexcept { return m_chunks.size() == 0; }
|
||||
|
||||
void reserve(size_type new_capacity);
|
||||
void shrink_to_fit() noexcept {}
|
||||
|
||||
bool operator==(const this_type& c) const
|
||||
{
|
||||
return size() == c.size() && std::equal(cbegin(), cend(), c.cbegin());
|
||||
}
|
||||
bool operator!=(const this_type& c) const { return !operator==(c); }
|
||||
|
||||
void swap(this_type& v) { std::swap(m_chunks, v.m_chunks); }
|
||||
|
||||
friend void swap(this_type& l, this_type& r) { l.swap(r); }
|
||||
|
||||
reference front() { return m_chunks.front()->front(); }
|
||||
const_reference front() const { return front(); }
|
||||
|
||||
reference back() { return m_chunks.back()->back(); }
|
||||
const_reference back() const { return back(); }
|
||||
|
||||
void push_back(const Tp& t);
|
||||
void push_back(Tp&& t);
|
||||
|
||||
template <typename... Args>
|
||||
void emplace_back(Args&&... args);
|
||||
|
||||
reference operator[](size_type i);
|
||||
|
||||
const_reference operator[](size_type i) const;
|
||||
|
||||
reference at(size_type i);
|
||||
|
||||
const_reference at(size_type i) const;
|
||||
|
||||
private:
|
||||
using chunk_type = container::static_vector<Tp, ChunkSizeV, true>;
|
||||
using storage_type = std::vector<std::unique_ptr<chunk_type>>;
|
||||
|
||||
void add_chunk();
|
||||
chunk_type& last_chunk();
|
||||
|
||||
storage_type m_chunks;
|
||||
};
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
stable_vector<Tp, ChunkSizeV>::stable_vector(size_type count, const Tp& value)
|
||||
{
|
||||
for(size_type i = 0; i < count; ++i)
|
||||
{
|
||||
push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
stable_vector<Tp, ChunkSizeV>::stable_vector(size_type count)
|
||||
{
|
||||
for(size_type i = 0; i < count; ++i)
|
||||
{
|
||||
emplace_back();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
template <typename InputItrT, typename>
|
||||
stable_vector<Tp, ChunkSizeV>::stable_vector(InputItrT first, InputItrT last)
|
||||
{
|
||||
for(; first != last; ++first)
|
||||
{
|
||||
push_back(*first);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
stable_vector<Tp, ChunkSizeV>::stable_vector(const stable_vector& other)
|
||||
{
|
||||
for(const auto& chunk : other.m_chunks)
|
||||
{
|
||||
m_chunks.emplace_back(std::make_unique<chunk_type>(*chunk));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
stable_vector<Tp, ChunkSizeV>::stable_vector(stable_vector&& other) noexcept
|
||||
: m_chunks(std::move(other.m_chunks))
|
||||
{}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
stable_vector<Tp, ChunkSizeV>::stable_vector(std::initializer_list<Tp> ilist)
|
||||
{
|
||||
for(const auto& t : ilist)
|
||||
{
|
||||
push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
stable_vector<Tp, ChunkSizeV>&
|
||||
stable_vector<Tp, ChunkSizeV>::operator=(stable_vector v)
|
||||
{
|
||||
swap(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
void
|
||||
stable_vector<Tp, ChunkSizeV>::add_chunk()
|
||||
{
|
||||
m_chunks.emplace_back(std::make_unique<chunk_type>());
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
typename stable_vector<Tp, ChunkSizeV>::chunk_type&
|
||||
stable_vector<Tp, ChunkSizeV>::last_chunk()
|
||||
{
|
||||
if(ROCPROFILER_UNLIKELY(m_chunks.empty() || m_chunks.back()->size() == ChunkSizeV))
|
||||
{
|
||||
add_chunk();
|
||||
}
|
||||
|
||||
return *m_chunks.back();
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
void
|
||||
stable_vector<Tp, ChunkSizeV>::reserve(size_type new_capacity)
|
||||
{
|
||||
const size_t initial_capacity = capacity();
|
||||
for(difference_type i = new_capacity - initial_capacity; i > 0; i -= ChunkSizeV)
|
||||
{
|
||||
add_chunk();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
void
|
||||
stable_vector<Tp, ChunkSizeV>::push_back(const Tp& t)
|
||||
{
|
||||
last_chunk().push_back(t);
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
void
|
||||
stable_vector<Tp, ChunkSizeV>::push_back(Tp&& t)
|
||||
{
|
||||
last_chunk().push_back(std::move(t));
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
template <typename... Args>
|
||||
void
|
||||
stable_vector<Tp, ChunkSizeV>::emplace_back(Args&&... args)
|
||||
{
|
||||
last_chunk().emplace_back(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
typename stable_vector<Tp, ChunkSizeV>::reference
|
||||
stable_vector<Tp, ChunkSizeV>::operator[](size_type i)
|
||||
{
|
||||
return (*m_chunks[i / ChunkSizeV])[i % ChunkSizeV];
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
typename stable_vector<Tp, ChunkSizeV>::const_reference
|
||||
stable_vector<Tp, ChunkSizeV>::operator[](size_type i) const
|
||||
{
|
||||
return const_cast<this_type&>(*this)[i];
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
typename stable_vector<Tp, ChunkSizeV>::reference
|
||||
stable_vector<Tp, ChunkSizeV>::at(size_type i)
|
||||
{
|
||||
if(ROCPROFILER_UNLIKELY(i >= size()))
|
||||
{
|
||||
throw ::rocprofiler::exception<std::out_of_range>("stable_vector::at(" + std::to_string(i) +
|
||||
"). size is " + std::to_string(size()));
|
||||
}
|
||||
|
||||
return operator[](i);
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
typename stable_vector<Tp, ChunkSizeV>::const_reference
|
||||
stable_vector<Tp, ChunkSizeV>::at(size_type i) const
|
||||
{
|
||||
return const_cast<this_type&>(*this).at(i);
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV, typename... Args>
|
||||
auto
|
||||
resize(stable_vector<Tp, ChunkSizeV>& _v, size_t _n, Args&&... args)
|
||||
{
|
||||
if(_n > _v.capacity()) _v.reserve(_n);
|
||||
|
||||
while(_v.size() < _n)
|
||||
_v.emplace_back(std::forward<Args>(args)...);
|
||||
|
||||
return _v.size();
|
||||
}
|
||||
} // namespace container
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,221 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lib/common/container/c_array.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <initializer_list>
|
||||
#include <cstddef>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace container
|
||||
{
|
||||
template <typename Tp, size_t N, bool AtomicSizeV = false>
|
||||
struct static_vector
|
||||
{
|
||||
using count_type = std::conditional_t<AtomicSizeV, std::atomic<size_t>, size_t>;
|
||||
using this_type = static_vector<Tp, N>;
|
||||
using value_type = Tp;
|
||||
|
||||
static_vector() = default;
|
||||
static_vector(const static_vector&) = default;
|
||||
static_vector(static_vector&&) noexcept = default;
|
||||
static_vector& operator=(const static_vector&) = default;
|
||||
static_vector& operator=(static_vector&&) noexcept = default;
|
||||
|
||||
explicit static_vector(size_t _n, Tp _v = {});
|
||||
explicit static_vector(c_array<Tp>&&);
|
||||
|
||||
template <size_t M>
|
||||
explicit static_vector(std::array<Tp, M>&&);
|
||||
|
||||
static_vector& operator=(std::initializer_list<Tp>&& _v);
|
||||
static_vector& operator=(std::pair<std::array<Tp, N>, size_t>&&);
|
||||
|
||||
template <typename... Args>
|
||||
value_type& emplace_back(Args&&... _v);
|
||||
|
||||
template <typename Up>
|
||||
decltype(auto) push_back(Up&& _v)
|
||||
{
|
||||
return emplace_back(Tp{std::forward<Up>(_v)});
|
||||
}
|
||||
|
||||
void pop_back() { --m_size; }
|
||||
|
||||
void clear();
|
||||
void reserve(size_t) noexcept {}
|
||||
void shrink_to_fit() noexcept {}
|
||||
auto capacity() noexcept { return N; }
|
||||
|
||||
size_t size() const { return m_size; }
|
||||
bool empty() const { return (size() == 0); }
|
||||
|
||||
auto begin() { return m_data.begin(); }
|
||||
auto begin() const { return m_data.begin(); }
|
||||
auto cbegin() const { return m_data.cbegin(); }
|
||||
|
||||
auto end() { return m_data.begin() + size(); }
|
||||
auto end() const { return m_data.begin() + size(); }
|
||||
auto cend() const { return m_data.cbegin() + size(); }
|
||||
|
||||
decltype(auto) operator[](size_t _idx) { return m_data[_idx]; }
|
||||
decltype(auto) operator[](size_t _idx) const { return m_data[_idx]; }
|
||||
|
||||
decltype(auto) at(size_t _idx) { return m_data.at(_idx); }
|
||||
decltype(auto) at(size_t _idx) const { return m_data.at(_idx); }
|
||||
|
||||
decltype(auto) front() { return m_data.front(); }
|
||||
decltype(auto) front() const { return m_data.front(); }
|
||||
decltype(auto) back() { return *(m_data.begin() + size() - 1); }
|
||||
decltype(auto) back() const { return *(m_data.begin() + size() - 1); }
|
||||
|
||||
auto* data() { return m_data.data(); }
|
||||
const auto* data() const { return m_data.data(); }
|
||||
|
||||
void swap(this_type& _v);
|
||||
|
||||
friend void swap(this_type& _lhs, this_type& _rhs) { _lhs.swap(_rhs); }
|
||||
|
||||
private:
|
||||
void update_size(size_t);
|
||||
|
||||
private:
|
||||
count_type m_size = count_type{0};
|
||||
std::array<Tp, N> m_data = {};
|
||||
};
|
||||
|
||||
template <typename Tp, size_t N, bool AtomicSizeV>
|
||||
static_vector<Tp, N, AtomicSizeV>::static_vector(size_t _n, Tp _v)
|
||||
{
|
||||
m_data.fill(_v);
|
||||
update_size(_n);
|
||||
}
|
||||
|
||||
template <typename Tp, size_t N, bool AtomicSizeV>
|
||||
static_vector<Tp, N, AtomicSizeV>::static_vector(c_array<Tp>&& _v)
|
||||
{
|
||||
auto _n = std::min<size_t>(N, _v.size());
|
||||
for(size_t i = 0; i < _n; ++i, ++m_size)
|
||||
m_data[i] = _v[i];
|
||||
}
|
||||
|
||||
template <typename Tp, size_t N, bool AtomicSizeV>
|
||||
template <size_t M>
|
||||
static_vector<Tp, N, AtomicSizeV>::static_vector(std::array<Tp, M>&& _v)
|
||||
{
|
||||
auto _n = std::min<size_t>(N, M);
|
||||
for(size_t i = 0; i < _n; ++i, ++m_size)
|
||||
m_data[i] = _v[i];
|
||||
}
|
||||
|
||||
template <typename Tp, size_t N, bool AtomicSizeV>
|
||||
static_vector<Tp, N, AtomicSizeV>&
|
||||
static_vector<Tp, N, AtomicSizeV>::operator=(std::initializer_list<Tp>&& _v)
|
||||
{
|
||||
if(ROCPROFILER_UNLIKELY(_v.size() > N))
|
||||
{
|
||||
throw exception<std::out_of_range>(
|
||||
std::string{"static_vector::operator=(initializer_list) size > "} + std::to_string(N));
|
||||
}
|
||||
|
||||
clear();
|
||||
for(auto&& itr : _v)
|
||||
m_data[m_size++] = itr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Tp, size_t N, bool AtomicSizeV>
|
||||
static_vector<Tp, N, AtomicSizeV>&
|
||||
static_vector<Tp, N, AtomicSizeV>::operator=(std::pair<std::array<Tp, N>, size_t>&& _v)
|
||||
{
|
||||
update_size(0);
|
||||
m_data = std::move(_v.first);
|
||||
update_size(_v.second);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Tp, size_t N, bool AtomicSizeV>
|
||||
void
|
||||
static_vector<Tp, N, AtomicSizeV>::clear()
|
||||
{
|
||||
update_size(0);
|
||||
}
|
||||
|
||||
template <typename Tp, size_t N, bool AtomicSizeV>
|
||||
void
|
||||
static_vector<Tp, N, AtomicSizeV>::swap(this_type& _v)
|
||||
{
|
||||
if constexpr(AtomicSizeV)
|
||||
{
|
||||
auto _t_size = m_size;
|
||||
auto _v_size = _v.m_size;
|
||||
std::swap(m_data, _v.m_data);
|
||||
update_size(_v_size);
|
||||
_v.update_size(_t_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::swap(m_size, _v.m_size);
|
||||
std::swap(m_data, _v.m_data);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tp, size_t N, bool AtomicSizeV>
|
||||
template <typename... Args>
|
||||
Tp&
|
||||
static_vector<Tp, N, AtomicSizeV>::emplace_back(Args&&... _v)
|
||||
{
|
||||
auto _idx = m_size++;
|
||||
if(_idx >= N)
|
||||
{
|
||||
throw exception<std::out_of_range>(
|
||||
std::string{"static_vector::emplace_back - reached capacity "} + std::to_string(N));
|
||||
}
|
||||
|
||||
if constexpr(std::is_assignable<Tp, decltype(std::forward<Args>(_v))...>::value)
|
||||
m_data[_idx] = {std::forward<Args>(_v)...};
|
||||
else
|
||||
m_data[_idx] = Tp{std::forward<Args>(_v)...};
|
||||
return m_data[_idx];
|
||||
}
|
||||
|
||||
template <typename Tp, size_t N, bool AtomicSizeV>
|
||||
void
|
||||
static_vector<Tp, N, AtomicSizeV>::update_size(size_t _n)
|
||||
{
|
||||
if constexpr(AtomicSizeV)
|
||||
m_size.store(_n);
|
||||
else
|
||||
m_size = _n;
|
||||
}
|
||||
} // namespace container
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2018-2023 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ROCPROFILER_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
|
||||
#define ROCPROFILER_VISIBILITY(MODE) ROCPROFILER_ATTRIBUTE(visibility(MODE))
|
||||
#define ROCPROFILER_PUBLIC_API ROCPROFILER_VISIBILITY("default")
|
||||
#define ROCPROFILER_HIDDEN_API ROCPROFILER_VISIBILITY("hidden")
|
||||
#define ROCPROFILER_INTERNAL_API ROCPROFILER_VISIBILITY("internal")
|
||||
#define ROCPROFILER_INLINE ROCPROFILER_ATTRIBUTE(always_inline) inline
|
||||
#define ROCPROFILER_NOINLINE ROCPROFILER_ATTRIBUTE(noinline)
|
||||
#define ROCPROFILER_HOT ROCPROFILER_ATTRIBUTE(hot)
|
||||
#define ROCPROFILER_COLD ROCPROFILER_ATTRIBUTE(cold)
|
||||
#define ROCPROFILER_CONST ROCPROFILER_ATTRIBUTE(const)
|
||||
#define ROCPROFILER_PURE ROCPROFILER_ATTRIBUTE(pure)
|
||||
#define ROCPROFILER_WEAK ROCPROFILER_ATTRIBUTE(weak)
|
||||
#define ROCPROFILER_PACKED ROCPROFILER_ATTRIBUTE(__packed__)
|
||||
#define ROCPROFILER_PACKED_ALIGN(VAL) ROCPROFILER_PACKED ROCPROFILER_ATTRIBUTE(__aligned__(VAL))
|
||||
#define ROCPROFILER_LIKELY(...) __builtin_expect((__VA_ARGS__), 1)
|
||||
#define ROCPROFILER_UNLIKELY(...) __builtin_expect((__VA_ARGS__), 0)
|
||||
|
||||
#if defined(ROCPROFILER_CI) && ROCPROFILER_CI > 0
|
||||
# if defined(NDEBUG)
|
||||
# undef NDEBUG
|
||||
# endif
|
||||
# if !defined(DEBUG)
|
||||
# define DEBUG 1
|
||||
# endif
|
||||
# if defined(__cplusplus)
|
||||
# include <cassert>
|
||||
# else
|
||||
# include <assert.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define ROCPROFILER_STRINGIZE(X) ROCPROFILER_STRINGIZE2(X)
|
||||
#define ROCPROFILER_STRINGIZE2(X) #X
|
||||
#define ROCPROFILER_VAR_NAME_COMBINE(X, Y) X##Y
|
||||
#define ROCPROFILER_VARIABLE(X, Y) ROCPROFILER_VAR_NAME_COMBINE(X, Y)
|
||||
#define ROCPROFILER_LINESTR ROCPROFILER_STRINGIZE(__LINE__)
|
||||
#define ROCPROFILER_ESC(...) __VA_ARGS__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
# if !defined(ROCPROFILER_FOLD_EXPRESSION)
|
||||
# define ROCPROFILER_FOLD_EXPRESSION(...) ((__VA_ARGS__), ...)
|
||||
# endif
|
||||
#endif
|
||||
@@ -0,0 +1,185 @@
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lib/common/log.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <unistd.h>
|
||||
|
||||
#if !defined(ROCPROFILER_ENVIRON_LOG_NAME)
|
||||
# if defined(ROCPROFILER_COMMON_LIBRARY_NAME)
|
||||
# define ROCPROFILER_ENVIRON_LOG_NAME "[" ROCPROFILER_COMMON_LIBRARY_NAME "]"
|
||||
# else
|
||||
# define ROCPROFILER_ENVIRON_LOG_NAME "[environ]"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(ROCPROFILER_ENVIRON_LOG_START)
|
||||
# if defined(ROCPROFILER_COMMON_LIBRARY_LOG_START)
|
||||
# define ROCPROFILER_ENVIRON_LOG_START ROCPROFILER_COMMON_LIBRARY_LOG_START
|
||||
# elif defined(ROCPROFILER_LOG_COLORS_AVAILABLE)
|
||||
# define ROCPROFILER_ENVIRON_LOG_START \
|
||||
fprintf(stderr, "%s", ::rocprofiler::common::log::color::dmesg());
|
||||
# else
|
||||
# define ROCPROFILER_ENVIRON_LOG_START
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(ROCPROFILER_ENVIRON_LOG_END)
|
||||
# if defined(ROCPROFILER_COMMON_LIBRARY_LOG_END)
|
||||
# define ROCPROFILER_ENVIRON_LOG_END ROCPROFILER_COMMON_LIBRARY_LOG_END
|
||||
# elif defined(ROCPROFILER_LOG_COLORS_AVAILABLE)
|
||||
# define ROCPROFILER_ENVIRON_LOG_END \
|
||||
fprintf(stderr, "%s", ::rocprofiler::common::log::color::dmesg());
|
||||
# else
|
||||
# define ROCPROFILER_ENVIRON_LOG_END
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define ROCPROFILER_ENVIRON_LOG(CONDITION, ...) \
|
||||
if(CONDITION) \
|
||||
{ \
|
||||
fflush(stderr); \
|
||||
ROCPROFILER_ENVIRON_LOG_START \
|
||||
fprintf(stderr, "[rocprofiler]" ROCPROFILER_ENVIRON_LOG_NAME "[%i] ", getpid()); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
ROCPROFILER_ENVIRON_LOG_END \
|
||||
fflush(stderr); \
|
||||
}
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
inline std::string
|
||||
get_env_impl(std::string_view env_id, std::string_view _default)
|
||||
{
|
||||
if(env_id.empty()) return std::string{_default};
|
||||
char* env_var = ::std::getenv(env_id.data());
|
||||
if(env_var) return std::string{env_var};
|
||||
return std::string{_default};
|
||||
}
|
||||
|
||||
inline std::string
|
||||
get_env_impl(std::string_view env_id, const char* _default)
|
||||
{
|
||||
return get_env_impl(env_id, std::string_view{_default});
|
||||
}
|
||||
|
||||
inline int
|
||||
get_env_impl(std::string_view env_id, int _default)
|
||||
{
|
||||
if(env_id.empty()) return _default;
|
||||
char* env_var = ::std::getenv(env_id.data());
|
||||
if(env_var)
|
||||
{
|
||||
try
|
||||
{
|
||||
return std::stoi(env_var);
|
||||
} catch(std::exception& _e)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"[rocprofiler][get_env] Exception thrown converting getenv(\"%s\") = "
|
||||
"%s to integer :: %s. Using default value of %i\n",
|
||||
env_id.data(),
|
||||
env_var,
|
||||
_e.what(),
|
||||
_default);
|
||||
}
|
||||
return _default;
|
||||
}
|
||||
return _default;
|
||||
}
|
||||
|
||||
inline bool
|
||||
get_env_impl(std::string_view env_id, bool _default)
|
||||
{
|
||||
if(env_id.empty()) return _default;
|
||||
char* env_var = ::std::getenv(env_id.data());
|
||||
if(env_var)
|
||||
{
|
||||
if(std::string_view{env_var}.empty())
|
||||
{
|
||||
throw std::runtime_error(std::string{"No boolean value provided for "} +
|
||||
std::string{env_id});
|
||||
}
|
||||
|
||||
if(std::string_view{env_var}.find_first_not_of("0123456789") == std::string_view::npos)
|
||||
{
|
||||
return static_cast<bool>(std::stoi(env_var));
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < strlen(env_var); ++i)
|
||||
env_var[i] = tolower(env_var[i]);
|
||||
for(const auto& itr : {"off", "false", "no", "n", "f", "0"})
|
||||
if(strcmp(env_var, itr) == 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
return _default;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <typename Tp>
|
||||
inline auto
|
||||
get_env(std::string_view env_id, Tp&& _default)
|
||||
{
|
||||
if constexpr(std::is_enum<Tp>::value)
|
||||
{
|
||||
using Up = std::underlying_type_t<Tp>;
|
||||
// cast to underlying type -> get_env -> cast to enum type
|
||||
return static_cast<Tp>(get_env_impl(env_id, static_cast<Up>(_default)));
|
||||
}
|
||||
else
|
||||
{
|
||||
return get_env_impl(env_id, std::forward<Tp>(_default));
|
||||
}
|
||||
}
|
||||
|
||||
struct env_config
|
||||
{
|
||||
std::string env_name = {};
|
||||
std::string env_value = {};
|
||||
int override = 0;
|
||||
|
||||
auto operator()(bool _verbose = false) const
|
||||
{
|
||||
if(env_name.empty()) return -1;
|
||||
ROCPROFILER_ENVIRON_LOG(_verbose,
|
||||
"setenv(\"%s\", \"%s\", %i)\n",
|
||||
env_name.c_str(),
|
||||
env_value.c_str(),
|
||||
override);
|
||||
return setenv(env_name.c_str(), env_value.c_str(), override);
|
||||
}
|
||||
};
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,373 @@
|
||||
/* Copyright (c) 2022 Advanced Micro Devices, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE. */
|
||||
|
||||
#include "lib/common/helper.hpp"
|
||||
|
||||
#include <amd_comgr/amd_comgr.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <cxxabi.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#define ENABLE_BACKTRACE
|
||||
#if defined(ENABLE_BACKTRACE)
|
||||
# include <backtrace.h>
|
||||
#endif
|
||||
|
||||
#define amd_comgr_(call) \
|
||||
do \
|
||||
{ \
|
||||
if(amd_comgr_status_t status = amd_comgr_##call; status != AMD_COMGR_STATUS_SUCCESS) \
|
||||
{ \
|
||||
const char* reason = ""; \
|
||||
amd_comgr_status_string(status, &reason); \
|
||||
fprintf(stderr, #call " failed: %s\n", reason); \
|
||||
abort(); \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
std::string
|
||||
cxa_demangle(std::string_view _mangled_name, int* _status)
|
||||
{
|
||||
constexpr size_t buffer_len = 4096;
|
||||
// return the mangled since there is no buffer
|
||||
if(_mangled_name.empty())
|
||||
{
|
||||
*_status = -2;
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
auto _demangled_name = std::string{_mangled_name};
|
||||
|
||||
// PARAMETERS to __cxa_demangle
|
||||
// mangled_name:
|
||||
// A NULL-terminated character string containing the name to be demangled.
|
||||
// buffer:
|
||||
// A region of memory, allocated with malloc, of *length bytes, into which the
|
||||
// demangled name is stored. If output_buffer is not long enough, it is expanded
|
||||
// using realloc. output_buffer may instead be NULL; in that case, the demangled
|
||||
// name is placed in a region of memory allocated with malloc.
|
||||
// _buflen:
|
||||
// If length is non-NULL, the length of the buffer containing the demangled name
|
||||
// is placed in *length.
|
||||
// status:
|
||||
// *status is set to one of the following values
|
||||
size_t _demang_len = 0;
|
||||
char* _demang = abi::__cxa_demangle(_demangled_name.c_str(), nullptr, &_demang_len, _status);
|
||||
switch(*_status)
|
||||
{
|
||||
// 0 : The demangling operation succeeded.
|
||||
// -1 : A memory allocation failure occurred.
|
||||
// -2 : mangled_name is not a valid name under the C++ ABI mangling rules.
|
||||
// -3 : One of the arguments is invalid.
|
||||
case 0:
|
||||
{
|
||||
if(_demang) _demangled_name = std::string{_demang};
|
||||
break;
|
||||
}
|
||||
case -1:
|
||||
{
|
||||
char _msg[buffer_len];
|
||||
::memset(_msg, '\0', buffer_len * sizeof(char));
|
||||
::snprintf(_msg,
|
||||
buffer_len,
|
||||
"memory allocation failure occurred demangling %s",
|
||||
_demangled_name.c_str());
|
||||
::perror(_msg);
|
||||
break;
|
||||
}
|
||||
case -2: break;
|
||||
case -3:
|
||||
{
|
||||
char _msg[buffer_len];
|
||||
::memset(_msg, '\0', buffer_len * sizeof(char));
|
||||
::snprintf(_msg,
|
||||
buffer_len,
|
||||
"Invalid argument in: (\"%s\", nullptr, nullptr, %p)",
|
||||
_demangled_name.c_str(),
|
||||
(void*) _status);
|
||||
::perror(_msg);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
};
|
||||
|
||||
// if it "demangled" but the length is zero, set the status to -2
|
||||
if(_demang_len == 0 && *_status == 0) *_status = -2;
|
||||
|
||||
// free allocated buffer
|
||||
::free(_demang);
|
||||
return _demangled_name;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
#if defined(ENABLE_BACKTRACE)
|
||||
|
||||
// struct BackTraceInfo
|
||||
// {
|
||||
// struct ::backtrace_state* state = nullptr;
|
||||
// std::stringstream sstream{};
|
||||
// int depth = 0;
|
||||
// int error = 0;
|
||||
// };
|
||||
|
||||
// void
|
||||
// errorCallback(void* data, const char* message, int errnum)
|
||||
// {
|
||||
// BackTraceInfo* info = static_cast<BackTraceInfo*>(data);
|
||||
// info->sstream << "ROCProfiler: error: " << message << '(' << errnum << ')';
|
||||
// info->error = 1;
|
||||
// }
|
||||
|
||||
// void
|
||||
// syminfoCallback(void* data,
|
||||
// uintptr_t /* pc */,
|
||||
// const char* symname,
|
||||
// uintptr_t /* symval */,
|
||||
// uintptr_t /* symsize */)
|
||||
// {
|
||||
// BackTraceInfo* info = static_cast<BackTraceInfo*>(data);
|
||||
|
||||
// if(symname == nullptr) return;
|
||||
|
||||
// int status = 0;
|
||||
// auto&& _demangled = cxa_demangle(symname, &status);
|
||||
// info->sstream << ' '
|
||||
// << (status == 0 ? std::string_view{_demangled} : std::string_view{symname});
|
||||
// }
|
||||
|
||||
// int
|
||||
// fullCallback(void* data, uintptr_t pc, const char* filename, int lineno, const char* function)
|
||||
// {
|
||||
// BackTraceInfo* info = static_cast<BackTraceInfo*>(data);
|
||||
|
||||
// info->sstream << std::endl
|
||||
// << " #" << std::dec << info->depth++ << ' ' << "0x" << std::noshowbase
|
||||
// << std::hex << std::setfill('0') << std::setw(sizeof(pc) * 2) << pc;
|
||||
// if(function == nullptr)
|
||||
// {
|
||||
// backtrace_syminfo(info->state, pc, syminfoCallback, errorCallback, data);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// int status = 0;
|
||||
// auto&& _demangled = cxa_demangle(function, &status);
|
||||
// info->sstream << ' '
|
||||
// << (status == 0 ? std::string_view{_demangled} :
|
||||
// std::string_view{function});
|
||||
|
||||
// if(filename != nullptr)
|
||||
// {
|
||||
// info->sstream << " in " << filename;
|
||||
// if(lineno != 0) info->sstream << ':' << std::dec << lineno;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return info->error;
|
||||
// }
|
||||
#endif // defined (ENABLE_BACKTRACE)
|
||||
} // namespace
|
||||
|
||||
/* The function extracts the kernel name from
|
||||
input string. By using the iterators it finds the
|
||||
window in the string which contains only the kernel name.
|
||||
For example 'Foo<int, float>::foo(a[], int (int))' -> 'foo'*/
|
||||
std::string
|
||||
truncate_name(std::string_view name)
|
||||
{
|
||||
auto rit = name.rbegin();
|
||||
auto rend = name.rend();
|
||||
uint32_t counter = 0;
|
||||
char open_token = 0;
|
||||
char close_token = 0;
|
||||
while(rit != rend)
|
||||
{
|
||||
if(counter == 0)
|
||||
{
|
||||
switch(*rit)
|
||||
{
|
||||
case ')':
|
||||
counter = 1;
|
||||
open_token = ')';
|
||||
close_token = '(';
|
||||
break;
|
||||
case '>':
|
||||
counter = 1;
|
||||
open_token = '>';
|
||||
close_token = '<';
|
||||
break;
|
||||
case ']':
|
||||
counter = 1;
|
||||
open_token = ']';
|
||||
close_token = '[';
|
||||
break;
|
||||
case ' ': ++rit; continue;
|
||||
}
|
||||
if(counter == 0) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(*rit == open_token) counter++;
|
||||
if(*rit == close_token) counter--;
|
||||
}
|
||||
++rit;
|
||||
}
|
||||
auto rbeg = rit;
|
||||
while((rit != rend) && (*rit != ' ') && (*rit != ':'))
|
||||
rit++;
|
||||
return std::string{name.substr(rend - rit, rit - rbeg)};
|
||||
}
|
||||
|
||||
// C++ symbol demangle
|
||||
std::string
|
||||
cxx_demangle(std::string_view symbol)
|
||||
{
|
||||
int _status = 0;
|
||||
auto demangled_str = cxa_demangle(symbol, &_status);
|
||||
if(_status == 0)
|
||||
{
|
||||
return demangled_str;
|
||||
}
|
||||
|
||||
amd_comgr_data_t mangled_data;
|
||||
amd_comgr_(create_data(AMD_COMGR_DATA_KIND_BYTES, &mangled_data));
|
||||
amd_comgr_(set_data(mangled_data, symbol.size(), symbol.data()));
|
||||
|
||||
amd_comgr_data_t demangled_data;
|
||||
amd_comgr_(demangle_symbol_name(mangled_data, &demangled_data));
|
||||
|
||||
size_t demangled_size = 0;
|
||||
amd_comgr_(get_data(demangled_data, &demangled_size, nullptr));
|
||||
|
||||
demangled_str.resize(demangled_size);
|
||||
amd_comgr_(get_data(demangled_data, &demangled_size, demangled_str.data()));
|
||||
|
||||
amd_comgr_(release_data(mangled_data));
|
||||
amd_comgr_(release_data(demangled_data));
|
||||
return demangled_str;
|
||||
}
|
||||
|
||||
// check if string has special char
|
||||
bool
|
||||
has_special_char(std::string_view str)
|
||||
{
|
||||
return std::find_if(str.begin(), str.end(), [](unsigned char ch) {
|
||||
return !((isalnum(ch) != 0) || ch == '_' || ch == ':' || ch == ' ');
|
||||
}) != str.end();
|
||||
}
|
||||
|
||||
// check if string has correct counter format
|
||||
bool
|
||||
has_counter_format(std::string_view str)
|
||||
{
|
||||
return std::find_if(str.begin(), str.end(), [](unsigned char ch) {
|
||||
return ((isalnum(ch) != 0) || ch == '_');
|
||||
}) != str.end();
|
||||
}
|
||||
|
||||
// trims the begining of the line for spaces
|
||||
std::string
|
||||
left_trim(std::string_view s)
|
||||
{
|
||||
constexpr std::string_view WHITESPACE = " \n\r\t\f\v";
|
||||
size_t start = s.find_first_not_of(WHITESPACE);
|
||||
if(start == std::string_view::npos) return std::string{};
|
||||
return std::string{s.substr(start)};
|
||||
}
|
||||
|
||||
// trims begining and end of input line in place
|
||||
void
|
||||
trim(std::string& str)
|
||||
{
|
||||
// Remove leading spaces.
|
||||
str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](unsigned char ch) {
|
||||
return std::isspace(ch) == 0;
|
||||
}));
|
||||
// Remove trailing spaces.
|
||||
str.erase(std::find_if(
|
||||
str.rbegin(), str.rend(), [](unsigned char ch) { return std::isspace(ch) == 0; })
|
||||
.base(),
|
||||
str.end());
|
||||
}
|
||||
|
||||
// replace unsuported specail chars with space
|
||||
static void
|
||||
handle_special_chars(std::string& str)
|
||||
{
|
||||
std::set<char> specialChars = {'!', '@', '#', '$', '%', '&', '(', ')', ',',
|
||||
'*', '+', '-', '.', '/', ';', '<', '=', '>',
|
||||
'?', '@', '{', '}', '^', '`', '~', '|', ':'};
|
||||
|
||||
// Iterate over the string and replace any special characters with a space.
|
||||
for(char& i : str)
|
||||
{
|
||||
if(specialChars.find(i) != specialChars.end())
|
||||
{
|
||||
i = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validate input coutners and correct format if needed
|
||||
void
|
||||
validate_counters_format(std::vector<std::string>& counters, std::string line)
|
||||
{
|
||||
// trim line for any white spaces
|
||||
trim(line);
|
||||
|
||||
if(!(line[0] == '#' || line.find("pmc") == std::string::npos))
|
||||
{
|
||||
handle_special_chars(line);
|
||||
|
||||
std::stringstream input_line(line);
|
||||
std::string counter;
|
||||
while(getline(input_line, counter, ' '))
|
||||
{
|
||||
if(counter.substr(0, 3) != "pmc" && has_counter_format(counter))
|
||||
{
|
||||
counters.push_back(counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// raise exception with correct usage if user still managed to corrupt input
|
||||
for(const auto& itr : counters)
|
||||
{
|
||||
if(!has_counter_format(itr))
|
||||
{
|
||||
fprintf(stderr,
|
||||
"[rocprofiler] Bad input metric. usage --> pmc: <counter1> <counter2>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,68 @@
|
||||
/* Copyright (c) 2022 Advanced Micro Devices, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cxxabi.h>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
[[nodiscard]] std::string
|
||||
cxa_demangle(std::string_view _mangled_name, int* _status) __attribute__((nonnull(2)));
|
||||
|
||||
/* The function extracts the kernel name from
|
||||
input string. By using the iterators it finds the
|
||||
window in the string which contains only the kernel name.
|
||||
For example 'Foo<int, float>::foo(a[], int (int))' -> 'foo'*/
|
||||
std::string
|
||||
truncate_name(std::string_view name);
|
||||
|
||||
// C++ symbol demangle
|
||||
std::string
|
||||
cxx_demangle(std::string_view symbol);
|
||||
|
||||
// check if string has special char
|
||||
bool
|
||||
has_special_char(std::string_view str);
|
||||
|
||||
// check if string has correct counter format
|
||||
bool
|
||||
has_counter_format(std::string_view str);
|
||||
|
||||
// trims the begining of the line for spaces
|
||||
std::string
|
||||
left_trim(std::string_view s);
|
||||
|
||||
// validates pmc user input format
|
||||
void
|
||||
validate_counters_format(std::vector<std::string>& counters, std::string line);
|
||||
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,183 @@
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <initializer_list>
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(ROCPROFILER_FOLD_EXPRESSION)
|
||||
# define ROCPROFILER_FOLD_EXPRESSION(...) ((__VA_ARGS__), ...)
|
||||
#endif
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template <typename Tp>
|
||||
struct is_string_impl : std::false_type
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct is_string_impl<std::string> : std::true_type
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct is_string_impl<std::string_view> : std::true_type
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct is_string_impl<const char*> : std::true_type
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct is_string_impl<char*> : std::true_type
|
||||
{};
|
||||
|
||||
template <typename Tp>
|
||||
struct is_string : is_string_impl<std::remove_cv_t<std::decay_t<Tp>>>
|
||||
{};
|
||||
|
||||
template <typename ArgT>
|
||||
auto
|
||||
as_string(ArgT&& _v, std::enable_if_t<is_string<ArgT>::value, int> = 0)
|
||||
{
|
||||
if constexpr(std::is_pointer<std::decay_t<ArgT>>::value)
|
||||
{
|
||||
return (_v == nullptr) ? std::string{"\"\""} : (std::string{"\""} + _v + std::string{"\""});
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string{"\""} + _v + std::string{"\""};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ArgT>
|
||||
auto
|
||||
as_string(ArgT&& _v, std::enable_if_t<!is_string<ArgT>::value, long> = 0)
|
||||
{
|
||||
return _v;
|
||||
}
|
||||
|
||||
template <typename DelimT, typename... Args>
|
||||
auto
|
||||
join(DelimT&& _delim, Args&&... _args)
|
||||
{
|
||||
using delim_type = std::remove_cv_t<std::remove_reference_t<DelimT>>;
|
||||
|
||||
std::stringstream _ss{};
|
||||
_ss << std::boolalpha;
|
||||
|
||||
if constexpr(std::is_same<delim_type, char>::value)
|
||||
{
|
||||
const char _delim_c[2] = {_delim, '\0'};
|
||||
ROCPROFILER_FOLD_EXPRESSION(_ss << _delim_c << _args);
|
||||
auto _ret = _ss.str();
|
||||
return (_ret.length() > 1) ? _ret.substr(1) : std::string{};
|
||||
}
|
||||
else
|
||||
{
|
||||
ROCPROFILER_FOLD_EXPRESSION(_ss << _delim << _args);
|
||||
auto _ret = _ss.str();
|
||||
auto&& _len = std::string{_delim}.length();
|
||||
return (_ret.length() > _len) ? _ret.substr(_len) : std::string{};
|
||||
}
|
||||
}
|
||||
|
||||
struct QuoteStrings
|
||||
{};
|
||||
|
||||
template <typename DelimT, typename... Args>
|
||||
auto
|
||||
join(QuoteStrings&&, DelimT&& _delim, Args&&... _args)
|
||||
{
|
||||
using delim_type = std::remove_cv_t<std::remove_reference_t<DelimT>>;
|
||||
|
||||
std::stringstream _ss{};
|
||||
_ss << std::boolalpha;
|
||||
|
||||
if constexpr(std::is_same<delim_type, char>::value)
|
||||
{
|
||||
const char _delim_c[2] = {_delim, '\0'};
|
||||
ROCPROFILER_FOLD_EXPRESSION(_ss << _delim_c << as_string(_args));
|
||||
auto _ret = _ss.str();
|
||||
return (_ret.length() > 1) ? _ret.substr(1) : std::string{};
|
||||
}
|
||||
else
|
||||
{
|
||||
ROCPROFILER_FOLD_EXPRESSION(_ss << _delim << as_string(_args));
|
||||
auto _ret = _ss.str();
|
||||
auto&& _len = std::string{_delim}.length();
|
||||
return (_ret.length() > _len) ? _ret.substr(_len) : std::string{};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
auto
|
||||
join(std::array<std::string_view, 3>&& _delim, Args&&... _args)
|
||||
{
|
||||
return join("",
|
||||
std::get<0>(_delim),
|
||||
join(std::get<1>(_delim), std::forward<Args>(_args)...),
|
||||
std::get<2>(_delim));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
auto
|
||||
join(QuoteStrings&&, std::array<std::string_view, 3>&& _delim, Args&&... _args)
|
||||
{
|
||||
return join(QuoteStrings{},
|
||||
"",
|
||||
std::get<0>(_delim),
|
||||
join(std::get<1>(_delim), std::forward<Args>(_args)...),
|
||||
std::get<2>(_delim));
|
||||
}
|
||||
|
||||
template <typename DelimB, typename DelimT, typename DelimE, typename... Args>
|
||||
auto
|
||||
join(std::tuple<DelimB, DelimT, DelimE>&& _delim, Args&&... _args)
|
||||
{
|
||||
return join("",
|
||||
std::get<0>(_delim),
|
||||
join(std::get<1>(_delim), std::forward<Args>(_args)...),
|
||||
std::get<2>(_delim));
|
||||
}
|
||||
|
||||
template <typename DelimB, typename DelimT, typename DelimE, typename... Args>
|
||||
auto
|
||||
join(QuoteStrings&&, std::tuple<DelimB, DelimT, DelimE>&& _delim, Args&&... _args)
|
||||
{
|
||||
return join(QuoteStrings{},
|
||||
"",
|
||||
std::get<0>(_delim),
|
||||
join(std::get<1>(_delim), std::forward<Args>(_args)...),
|
||||
std::get<2>(_delim));
|
||||
}
|
||||
} // namespace
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,140 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020, The Regents of the University of California,
|
||||
// through Lawrence Berkeley National Laboratory (subject to receipt of any
|
||||
// required approvals from the U.S. Dept. of Energy). All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR rhs
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR rhsWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR rhs DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef ROCPROFILER_LOG_COLORS_AVAILABLE
|
||||
# define ROCPROFILER_LOG_COLORS_AVAILABLE 1
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace log
|
||||
{
|
||||
bool&
|
||||
monochrome();
|
||||
|
||||
inline bool&
|
||||
monochrome()
|
||||
{
|
||||
static bool _v = []() {
|
||||
auto _val = false;
|
||||
const char* _env_cstr = nullptr;
|
||||
#if defined(ROCPROFILER_LOG_COLORS_ENV)
|
||||
_env_cstr = std::getenv(ROCPROFILER_LOG_COLORS_ENV);
|
||||
#elif defined(ROCPROFILER_PROJECT_NAME)
|
||||
auto _env_name = std::string{ROCPROFILER_PROJECT_NAME} + "_MONOCHROME";
|
||||
for(auto& itr : _env_name)
|
||||
itr = toupper(itr);
|
||||
_env_cstr = std::getenv(_env_name.c_str());
|
||||
#else
|
||||
_env_cstr = std::getenv("ROCPROFILER_MONOCHROME");
|
||||
#endif
|
||||
|
||||
if(!_env_cstr) _env_cstr = std::getenv("MONOCHROME");
|
||||
|
||||
if(_env_cstr)
|
||||
{
|
||||
auto _env = std::string{_env_cstr};
|
||||
|
||||
// check if numeric
|
||||
if(_env.find_first_not_of("0123456789") == std::string::npos)
|
||||
{
|
||||
return _env.length() > 1 || _env[0] != '0';
|
||||
}
|
||||
|
||||
for(auto& itr : _env)
|
||||
itr = tolower(itr);
|
||||
|
||||
// check for matches to acceptable forms of false
|
||||
for(const auto& itr : {"off", "false", "no", "n", "f"})
|
||||
{
|
||||
if(_env == itr) return false;
|
||||
}
|
||||
|
||||
// check for matches to acceptable forms of true
|
||||
for(const auto& itr : {"on", "true", "yes", "y", "t"})
|
||||
{
|
||||
if(_env == itr) return true;
|
||||
}
|
||||
}
|
||||
return _val;
|
||||
}();
|
||||
return _v;
|
||||
}
|
||||
|
||||
namespace color
|
||||
{
|
||||
static constexpr auto info_value = "\033[01;34m";
|
||||
static constexpr auto warning_value = "\033[01;33m";
|
||||
static constexpr auto fatal_value = "\033[01;31m";
|
||||
static constexpr auto source_value = "\033[01;32m";
|
||||
static constexpr auto dmesg_value = "\033[01;37m";
|
||||
static constexpr auto end_value = "\033[0m";
|
||||
|
||||
inline const char*
|
||||
info()
|
||||
{
|
||||
return (log::monochrome()) ? "" : info_value;
|
||||
}
|
||||
|
||||
inline const char*
|
||||
warning()
|
||||
{
|
||||
return (log::monochrome()) ? "" : warning_value;
|
||||
}
|
||||
|
||||
inline const char*
|
||||
fatal()
|
||||
{
|
||||
return (log::monochrome()) ? "" : fatal_value;
|
||||
}
|
||||
|
||||
inline const char*
|
||||
source()
|
||||
{
|
||||
return (log::monochrome()) ? "" : source_value;
|
||||
}
|
||||
|
||||
inline const char*
|
||||
dmesg()
|
||||
{
|
||||
return (log::monochrome()) ? "" : dmesg_value;
|
||||
}
|
||||
|
||||
inline const char*
|
||||
end()
|
||||
{
|
||||
return (log::monochrome()) ? "" : end_value;
|
||||
}
|
||||
} // namespace color
|
||||
} // namespace log
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,376 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020, The Regents of the University of California,
|
||||
// through Lawrence Berkeley National Laboratory (subject to receipt of any
|
||||
// required approvals from the U.S. Dept. of Energy). All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lib/common/environment.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_set>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace units
|
||||
{
|
||||
static constexpr int64_t nsec = 1;
|
||||
static constexpr int64_t usec = 1000 * nsec;
|
||||
static constexpr int64_t msec = 1000 * usec;
|
||||
static constexpr int64_t csec = 10 * msec;
|
||||
static constexpr int64_t dsec = 10 * csec;
|
||||
static constexpr int64_t sec = 10 * dsec;
|
||||
static constexpr int64_t minute = 60 * sec;
|
||||
static constexpr int64_t hour = 60 * minute;
|
||||
|
||||
static constexpr int64_t byte = 1;
|
||||
static constexpr int64_t kilobyte = 1000 * byte;
|
||||
static constexpr int64_t megabyte = 1000 * kilobyte;
|
||||
static constexpr int64_t gigabyte = 1000 * megabyte;
|
||||
static constexpr int64_t terabyte = 1000 * gigabyte;
|
||||
static constexpr int64_t petabyte = 1000 * terabyte;
|
||||
|
||||
static constexpr int64_t kibibyte = 1024 * byte;
|
||||
static constexpr int64_t mebibyte = 1024 * kibibyte;
|
||||
static constexpr int64_t gibibyte = 1024 * mebibyte;
|
||||
static constexpr int64_t tebibyte = 1024 * gibibyte;
|
||||
static constexpr int64_t pebibyte = 1024 * tebibyte;
|
||||
|
||||
static constexpr int64_t B = 1;
|
||||
static constexpr int64_t KB = 1000 * B;
|
||||
static constexpr int64_t MB = 1000 * KB;
|
||||
static constexpr int64_t GB = 1000 * MB;
|
||||
static constexpr int64_t TB = 1000 * GB;
|
||||
static constexpr int64_t PB = 1000 * TB;
|
||||
|
||||
static constexpr int64_t Bi = 1;
|
||||
static constexpr int64_t KiB = 1024 * Bi;
|
||||
static constexpr int64_t MiB = 1024 * KiB;
|
||||
static constexpr int64_t GiB = 1024 * MiB;
|
||||
static constexpr int64_t TiB = 1024 * GiB;
|
||||
static constexpr int64_t PiB = 1024 * TiB;
|
||||
|
||||
static constexpr int64_t nanowatt = 1;
|
||||
static constexpr int64_t microwatt = 1000 * nanowatt;
|
||||
static constexpr int64_t milliwatt = 1000 * microwatt;
|
||||
static constexpr int64_t watt = 1000 * milliwatt;
|
||||
static constexpr int64_t kilowatt = 1000 * watt;
|
||||
static constexpr int64_t megawatt = 1000 * kilowatt;
|
||||
static constexpr int64_t gigawatt = 1000 * megawatt;
|
||||
|
||||
static constexpr int64_t hertz = 1;
|
||||
static constexpr int64_t kilohertz = 1000 * hertz;
|
||||
static constexpr int64_t megahertz = 1000 * kilohertz;
|
||||
static constexpr int64_t gigahertz = 1000 * megahertz;
|
||||
|
||||
static constexpr int64_t Hz = 1;
|
||||
static constexpr int64_t KHz = 1000 * Hz;
|
||||
static constexpr int64_t MHz = 1000 * KHz;
|
||||
static constexpr int64_t GHz = 1000 * MHz;
|
||||
|
||||
inline int64_t
|
||||
get_page_size()
|
||||
{
|
||||
static auto _pagesz = sysconf(_SC_PAGESIZE);
|
||||
return _pagesz;
|
||||
}
|
||||
|
||||
const int64_t clocks_per_sec = sysconf(_SC_CLK_TCK);
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
inline std::string
|
||||
time_repr(int64_t _unit)
|
||||
{
|
||||
switch(_unit)
|
||||
{
|
||||
case nsec: return "nsec"; break;
|
||||
case usec: return "usec"; break;
|
||||
case msec: return "msec"; break;
|
||||
case csec: return "csec"; break;
|
||||
case dsec: return "dsec"; break;
|
||||
case sec: return "sec"; break;
|
||||
default: return "UNK"; break;
|
||||
}
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
inline std::string
|
||||
mem_repr(int64_t _unit)
|
||||
{
|
||||
switch(_unit)
|
||||
{
|
||||
case byte: return "B"; break;
|
||||
case kilobyte: return "KB"; break;
|
||||
case megabyte: return "MB"; break;
|
||||
case gigabyte: return "GB"; break;
|
||||
case terabyte: return "TB"; break;
|
||||
case petabyte: return "PB"; break;
|
||||
case kibibyte: return "KiB"; break;
|
||||
case mebibyte: return "MiB"; break;
|
||||
case gibibyte: return "GiB"; break;
|
||||
case tebibyte: return "TiB"; break;
|
||||
case pebibyte: return "PiB"; break;
|
||||
default: return "UNK"; break;
|
||||
}
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
inline std::string
|
||||
freq_repr(int64_t _unit)
|
||||
{
|
||||
switch(_unit)
|
||||
{
|
||||
case hertz: return "Hz"; break;
|
||||
case kilohertz: return "KHz"; break;
|
||||
case megahertz: return "MHz"; break;
|
||||
case gigahertz: return "GHz"; break;
|
||||
default: return "UNK"; break;
|
||||
}
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
inline std::string
|
||||
power_repr(int64_t _unit)
|
||||
{
|
||||
switch(_unit)
|
||||
{
|
||||
case nanowatt: return "nanowatts"; break;
|
||||
case microwatt: return "microwatts"; break;
|
||||
case milliwatt: return "milliwatts"; break;
|
||||
case watt: return "watts"; break;
|
||||
case kilowatt: return "kilowatts"; break;
|
||||
case megawatt: return "megawatts"; break;
|
||||
case gigawatt: return "gigawatts"; break;
|
||||
default: return "UNK"; break;
|
||||
}
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
inline std::tuple<std::string, int64_t>
|
||||
get_memory_unit(std::string _unit)
|
||||
{
|
||||
using string_t = std::string;
|
||||
using return_type = std::tuple<string_t, int64_t>;
|
||||
using inner_t = std::tuple<string_t, string_t, int64_t>;
|
||||
|
||||
if(_unit.length() == 0) return return_type{"MB", units::megabyte};
|
||||
|
||||
for(auto& itr : _unit)
|
||||
itr = tolower(itr);
|
||||
|
||||
for(const auto& itr : {inner_t{"byte", "b", units::byte},
|
||||
inner_t{"kilobyte", "kb", units::kilobyte},
|
||||
inner_t{"megabyte", "mb", units::megabyte},
|
||||
inner_t{"gigabyte", "gb", units::gigabyte},
|
||||
inner_t{"terabyte", "tb", units::terabyte},
|
||||
inner_t{"petabyte", "pb", units::petabyte},
|
||||
inner_t{"kibibyte", "kib", units::KiB},
|
||||
inner_t{"mebibyte", "mib", units::MiB},
|
||||
inner_t{"gibibyte", "gib", units::GiB},
|
||||
inner_t{"tebibyte", "tib", units::TiB},
|
||||
inner_t{"pebibyte", "pib", units::PiB}})
|
||||
{
|
||||
if(_unit == std::get<0>(itr) || _unit == std::get<1>(itr))
|
||||
{
|
||||
if(std::get<2>(itr) == units::byte)
|
||||
return return_type{std::get<0>(itr), std::get<2>(itr)};
|
||||
return return_type{mem_repr(std::get<2>(itr)), std::get<2>(itr)};
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "Warning!! No memory unit matching \"" << _unit << "\". Using default..."
|
||||
<< std::endl;
|
||||
|
||||
return return_type{"MB", units::megabyte};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
inline std::tuple<std::string, int64_t>
|
||||
get_timing_unit(std::string _unit)
|
||||
{
|
||||
using string_t = std::string;
|
||||
using strset_t = std::unordered_set<string_t>;
|
||||
using return_type = std::tuple<string_t, int64_t>;
|
||||
using inner_t = std::tuple<string_t, strset_t, int64_t>;
|
||||
|
||||
if(_unit.length() == 0) return return_type{"sec", units::sec};
|
||||
|
||||
for(auto& itr : _unit)
|
||||
itr = tolower(itr);
|
||||
|
||||
for(const auto& itr :
|
||||
{inner_t{"nsec", strset_t{"ns", "nanosecond", "nanoseconds"}, units::nsec},
|
||||
inner_t{"usec", strset_t{"us", "microsecond", "microseconds"}, units::usec},
|
||||
inner_t{"msec", strset_t{"ms", "millisecond", "milliseconds"}, units::msec},
|
||||
inner_t{"csec", strset_t{"cs", "centisecond", "centiseconds"}, units::csec},
|
||||
inner_t{"dsec", strset_t{"ds", "decisecond", "deciseconds"}, units::dsec},
|
||||
inner_t{"sec", strset_t{"s", "second", "seconds"}, units::sec},
|
||||
inner_t{"min", strset_t{"minute", "minutes"}, units::minute},
|
||||
inner_t{"hr", strset_t{"hr", "hour", "hours"}, units::hour}})
|
||||
{
|
||||
if(_unit == std::get<0>(itr) || std::get<1>(itr).find(_unit) != std::get<1>(itr).end())
|
||||
{
|
||||
return return_type{time_repr(std::get<2>(itr)), std::get<2>(itr)};
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "Warning!! No timing unit matching \"" << _unit << "\". Using default..."
|
||||
<< std::endl;
|
||||
|
||||
return return_type{"sec", units::sec};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
inline std::tuple<std::string, int64_t>
|
||||
get_frequncy_unit(std::string _unit)
|
||||
{
|
||||
using string_t = std::string;
|
||||
using return_type = std::tuple<string_t, int64_t>;
|
||||
using inner_t = std::tuple<string_t, string_t, int64_t>;
|
||||
|
||||
if(_unit.length() == 0) return return_type{"MHz", units::megahertz};
|
||||
|
||||
for(auto& itr : _unit)
|
||||
itr = tolower(itr);
|
||||
|
||||
for(const auto& itr : {inner_t{"hertz", "hz", units::hertz},
|
||||
inner_t{"kilohertz", "khz", units::kilohertz},
|
||||
inner_t{"megahertz", "mhz", units::megahertz},
|
||||
inner_t{"gigahertz", "ghz", units::gigahertz}})
|
||||
{
|
||||
if(_unit == std::get<0>(itr) || _unit == std::get<1>(itr))
|
||||
{
|
||||
return return_type{freq_repr(std::get<2>(itr)), std::get<2>(itr)};
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "Warning!! No frequency unit matching \"" << _unit << "\". Using default..."
|
||||
<< std::endl;
|
||||
|
||||
return return_type{"MHz", units::megahertz};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
inline std::tuple<std::string, int64_t>
|
||||
get_power_unit(const std::string& _unit)
|
||||
{
|
||||
using string_t = std::string;
|
||||
using return_type = std::tuple<string_t, int64_t>;
|
||||
using inner_t = std::tuple<string_t, string_t, int64_t>;
|
||||
|
||||
if(_unit.length() == 0) return return_type{"watts", units::watt};
|
||||
|
||||
auto _lunit = _unit;
|
||||
for(auto& itr : _lunit)
|
||||
itr = tolower(itr);
|
||||
|
||||
for(const auto& itr : {inner_t{"nanowatt", "nW", units::nanowatt},
|
||||
inner_t{"microwatt", "uW", units::microwatt},
|
||||
inner_t{"milliwatt", "mW", units::milliwatt},
|
||||
inner_t{"watt", "W", units::watt},
|
||||
inner_t{"kilowatt", "KW", units::kilowatt},
|
||||
inner_t{"megawatt", "MW", units::megawatt},
|
||||
inner_t{"gigawatt", "GW", units::gigawatt}})
|
||||
{
|
||||
if(_lunit == std::get<0>(itr) || _lunit + "s" == std::get<0>(itr) ||
|
||||
_unit == std::get<1>(itr))
|
||||
{
|
||||
return return_type{power_repr(std::get<2>(itr)), std::get<2>(itr)};
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "Warning!! No power unit matching \"" << _unit << "\". Using default..."
|
||||
<< std::endl;
|
||||
|
||||
return return_type{"watts", units::watt};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
namespace temperature
|
||||
{
|
||||
enum unit_system : int8_t
|
||||
{
|
||||
Celsius = 0,
|
||||
Fahrenheit,
|
||||
Kelvin
|
||||
};
|
||||
|
||||
template <typename Tp>
|
||||
Tp
|
||||
convert(Tp _v, unit_system _from, unit_system _to)
|
||||
{
|
||||
switch(_from)
|
||||
{
|
||||
case Celsius:
|
||||
{
|
||||
switch(_to)
|
||||
{
|
||||
case Celsius: return _v;
|
||||
case Fahrenheit: return static_cast<Tp>((_v * 1.8) + 32);
|
||||
case Kelvin: return (_v - 273);
|
||||
}
|
||||
}
|
||||
case Fahrenheit:
|
||||
{
|
||||
switch(_to)
|
||||
{
|
||||
case Celsius: return static_cast<Tp>((_v - 32) / 1.8);
|
||||
case Fahrenheit: return _v;
|
||||
case Kelvin: return (_v - 273);
|
||||
}
|
||||
}
|
||||
case Kelvin:
|
||||
{
|
||||
switch(_to)
|
||||
{
|
||||
case Celsius: return (_v + 273);
|
||||
case Fahrenheit: return static_cast<Tp>(((_v + 273) * 1.8) + 32);
|
||||
case Kelvin: return _v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace temperature
|
||||
} // namespace units
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
set(ROCPROFILER_LIB_HEADERS config_helpers.hpp config_internal.hpp tracer.hpp)
|
||||
set(ROCPROFILER_LIB_SOURCES config_internal.cpp rocprofiler_config.cpp)
|
||||
|
||||
add_library(rocprofiler-library SHARED)
|
||||
add_library(rocprofiler::rocprofiler-library ALIAS rocprofiler-library)
|
||||
|
||||
target_sources(rocprofiler-library PRIVATE ${ROCPROFILER_LIB_SOURCES}
|
||||
${ROCPROFILER_LIB_HEADERS})
|
||||
|
||||
add_subdirectory(hsa)
|
||||
|
||||
target_link_libraries(
|
||||
rocprofiler-library
|
||||
PUBLIC rocprofiler::rocprofiler-headers
|
||||
PRIVATE rocprofiler::rocprofiler-build-flags
|
||||
rocprofiler::rocprofiler-memcheck
|
||||
rocprofiler::rocprofiler-common-library
|
||||
rocprofiler::rocprofiler-stdcxxfs
|
||||
rocprofiler::rocprofiler-dl
|
||||
rocprofiler::rocprofiler-hip
|
||||
rocprofiler::rocprofiler-amd-comgr
|
||||
rocprofiler::rocprofiler-hsa-runtime)
|
||||
target_compile_definitions(
|
||||
rocprofiler-library PRIVATE AMD_INTERNAL_BUILD=1 PROF_API_IMPL=1
|
||||
HIP_PROF_HIP_API_STRING=1 __HIP_PLATFORM_AMD__=1)
|
||||
set_target_properties(
|
||||
rocprofiler-library
|
||||
PROPERTIES OUTPUT_NAME rocprofiler64
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
VERSION ${PROJECT_VERSION})
|
||||
@@ -0,0 +1,107 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <rocprofiler/rocprofiler.h>
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace
|
||||
{
|
||||
inline size_t // NOLINTNEXTLINE
|
||||
get_domain_max_op(rocprofiler_tracer_activity_domain_t _domain)
|
||||
{
|
||||
switch(_domain)
|
||||
{
|
||||
case ACTIVITY_DOMAIN_NONE: return -1;
|
||||
case ACTIVITY_DOMAIN_HSA_API: return 0;
|
||||
case ACTIVITY_DOMAIN_HSA_OPS: return 0;
|
||||
case ACTIVITY_DOMAIN_HIP_OPS: return 0;
|
||||
case ACTIVITY_DOMAIN_HIP_API: return 0;
|
||||
case ACTIVITY_DOMAIN_KFD_API: return -1;
|
||||
case ACTIVITY_DOMAIN_EXT_API: return -1;
|
||||
case ACTIVITY_DOMAIN_ROCTX: return 0;
|
||||
case ACTIVITY_DOMAIN_HSA_EVT: return 0;
|
||||
case ACTIVITY_DOMAIN_NUMBER: return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename Tp, size_t N = 8>
|
||||
struct allocator
|
||||
{
|
||||
void construct(Tp* const _p, const Tp& _v) const { ::new((void*) _p) Tp{_v}; }
|
||||
void construct(Tp* const _p, Tp&& _v) const { ::new((void*) _p) Tp{std::move(_v)}; }
|
||||
|
||||
void destroy(Tp* const _p) const { _p->~Tp(); }
|
||||
|
||||
static constexpr auto size = sizeof(Tp);
|
||||
using buffer_value_t = char[size];
|
||||
|
||||
struct buffer_entry
|
||||
{
|
||||
std::atomic_flag flag = ATOMIC_FLAG_INIT;
|
||||
buffer_value_t value = {};
|
||||
|
||||
void* get()
|
||||
{
|
||||
if(flag.test_and_set())
|
||||
{
|
||||
return &value[0];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool reset(void* p)
|
||||
{
|
||||
if(static_cast<void*>(&value[0]) == p)
|
||||
{
|
||||
flag.clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static auto& get_buffer()
|
||||
{
|
||||
static auto _v = std::array<buffer_entry, N>{};
|
||||
return _v;
|
||||
}
|
||||
|
||||
Tp* allocate(const size_t n) const
|
||||
{
|
||||
if(n == 0) return nullptr;
|
||||
|
||||
if(n == 1)
|
||||
{
|
||||
// try an find in buffer for data locality
|
||||
for(auto& itr : get_buffer())
|
||||
{
|
||||
auto* _p = itr.get();
|
||||
if(_p) return static_cast<Tp*>(_p);
|
||||
}
|
||||
}
|
||||
|
||||
auto* _p = new char[n * size];
|
||||
return reinterpret_cast<Tp*>(_p);
|
||||
}
|
||||
|
||||
void deallocate(Tp* const ptr, const size_t /*unused*/) const
|
||||
{
|
||||
for(auto& itr : get_buffer())
|
||||
{
|
||||
if(itr.reset(ptr)) return;
|
||||
}
|
||||
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
Tp* allocate(const size_t n, const void* const /* hint */) const { return allocate(n); }
|
||||
|
||||
void reserve(const size_t) {}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
#include "config_internal.hpp"
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
uint64_t
|
||||
correlation_config::get_unique_record_id()
|
||||
{
|
||||
static auto _v = std::atomic<uint64_t>{};
|
||||
return _v++;
|
||||
}
|
||||
|
||||
bool
|
||||
domain_config::operator()(rocprofiler_tracer_activity_domain_t _domain) const
|
||||
{
|
||||
return ((1 << _domain) & domains) == (1 << _domain);
|
||||
}
|
||||
|
||||
bool
|
||||
domain_config::operator()(rocprofiler_tracer_activity_domain_t _domain, uint32_t _op) const
|
||||
{
|
||||
auto _offset = (_domain * rocprofiler::internal::domain_ops_offset);
|
||||
return (*this)(_domain) && (opcodes.none() || opcodes.test(_offset + _op));
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <rocprofiler/config.h>
|
||||
#include <rocprofiler/rocprofiler.h>
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <bitset>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
// number of bits to reserve all op codes
|
||||
constexpr size_t domain_ops_offset = ROCPROFILER_DOMAIN_OPS_MAX;
|
||||
constexpr size_t reserved_domain_size = ROCPROFILER_DOMAIN_OPS_RESERVED * 8;
|
||||
constexpr size_t max_configs_count = 8;
|
||||
|
||||
struct correlation_config
|
||||
{
|
||||
uint64_t id = 0;
|
||||
uint64_t external_id = 0;
|
||||
::rocprofiler_external_cid_cb_t external_id_callback = nullptr;
|
||||
|
||||
static uint64_t get_unique_record_id();
|
||||
};
|
||||
|
||||
struct domain_config
|
||||
{
|
||||
::rocprofiler_sync_callback_t user_sync_callback = nullptr;
|
||||
int64_t domains = 0;
|
||||
std::bitset<reserved_domain_size> opcodes = {};
|
||||
|
||||
/// check if domain is enabled
|
||||
bool operator()(::rocprofiler_tracer_activity_domain_t) const;
|
||||
|
||||
/// check if op in a domain is enabled
|
||||
bool operator()(::rocprofiler_tracer_activity_domain_t, uint32_t) const;
|
||||
};
|
||||
|
||||
struct buffer_config
|
||||
{
|
||||
::rocprofiler_buffer_callback_t callback = nullptr;
|
||||
uint64_t buffer_size;
|
||||
// Memory::GenericBuffer* buffer = nullptr;
|
||||
uint64_t buffer_idx = 0;
|
||||
};
|
||||
|
||||
using filter_config = ::rocprofiler_filter_config;
|
||||
|
||||
struct config
|
||||
{
|
||||
// size is used to ensure that we never read past the end of the version
|
||||
size_t size = 0; // = sizeof(rocprofiler_config)
|
||||
uint32_t compat_version = 0; // set by user
|
||||
uint32_t api_version = 0; // set by rocprofiler
|
||||
uint64_t session_idx = 0; // session id index
|
||||
void* user_data = nullptr; // user data passed to callbacks
|
||||
correlation_config* correlation_id = nullptr; // &my_cid_config (optional)
|
||||
buffer_config* buffer = nullptr; // = &my_buffer_config (required)
|
||||
domain_config* domain = nullptr; // = &my_domain_config (required)
|
||||
filter_config* filter = nullptr; // = &my_filter_config (optional)
|
||||
};
|
||||
|
||||
std::array<rocprofiler::internal::config*, max_configs_count>&
|
||||
get_registered_configs();
|
||||
|
||||
std::array<std::atomic<rocprofiler::internal::config*>, max_configs_count>&
|
||||
get_active_configs();
|
||||
} // namespace internal
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,10 @@
|
||||
set(ROCPROFILER_LIB_HSA_SOURCES hsa.cpp)
|
||||
set(ROCPROFILER_LIB_HSA_HEADERS hsa.hpp hsa-defines.hpp hsa-types.h hsa-utils.hpp)
|
||||
target_sources(rocprofiler-library PRIVATE ${ROCPROFILER_LIB_HSA_SOURCES}
|
||||
${ROCPROFILER_LIB_HSA_HEADERS})
|
||||
|
||||
# add_executable(rocr-example hsa.cpp rocr.hpp) target_link_libraries(rocr-example PRIVATE
|
||||
# rocprofiler-v2) target_include_directories( rocr-example PRIVATE ${PROJECT_SOURCE_DIR}
|
||||
# ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/src ${PROJECT_BINARY_DIR}/src)
|
||||
# target_compile_definitions( rocr-example PRIVATE AMD_INTERNAL_BUILD PROF_API_IMPL
|
||||
# HIP_PROF_HIP_API_STRING=1 __HIP_PLATFORM_AMD__=1)
|
||||
@@ -0,0 +1,266 @@
|
||||
// Copyright (c) 2018-2023 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define IMPL_DETAIL_EXPAND(X) X
|
||||
#define IMPL_DETAIL_FOR_EACH_NARG(...) \
|
||||
IMPL_DETAIL_FOR_EACH_NARG_(__VA_ARGS__, IMPL_DETAIL_FOR_EACH_RSEQ_N())
|
||||
#define IMPL_DETAIL_FOR_EACH_NARG_(...) IMPL_DETAIL_EXPAND(IMPL_DETAIL_FOR_EACH_ARG_N(__VA_ARGS__))
|
||||
#define IMPL_DETAIL_FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N
|
||||
#define IMPL_DETAIL_FOR_EACH_RSEQ_N() 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
#define IMPL_DETAIL_CONCATENATE(X, Y) X##Y
|
||||
#define IMPL_DETAIL_FOR_EACH_(N, MACRO, PREFIX, ...) \
|
||||
IMPL_DETAIL_EXPAND(IMPL_DETAIL_CONCATENATE(MACRO, N)(PREFIX, __VA_ARGS__))
|
||||
#define IMPL_DETAIL_FOR_EACH(MACRO, PREFIX, ...) \
|
||||
IMPL_DETAIL_FOR_EACH_(IMPL_DETAIL_FOR_EACH_NARG(__VA_ARGS__), MACRO, PREFIX, __VA_ARGS__)
|
||||
|
||||
#define MEMBER_0(...)
|
||||
#define MEMBER_1(PREFIX, FIELD) PREFIX.FIELD
|
||||
#define MEMBER_2(PREFIX, A, B) MEMBER_1(PREFIX, A), MEMBER_1(PREFIX, B)
|
||||
#define MEMBER_3(PREFIX, A, B, C) MEMBER_2(PREFIX, A, B), MEMBER_1(PREFIX, C)
|
||||
#define MEMBER_4(PREFIX, A, B, C, D) MEMBER_3(PREFIX, A, B, C), MEMBER_1(PREFIX, D)
|
||||
#define MEMBER_5(PREFIX, A, B, C, D, E) MEMBER_4(PREFIX, A, B, C, D), MEMBER_1(PREFIX, E)
|
||||
#define MEMBER_6(PREFIX, A, B, C, D, E, F) MEMBER_5(PREFIX, A, B, C, D, E), MEMBER_1(PREFIX, F)
|
||||
#define MEMBER_7(PREFIX, A, B, C, D, E, F, G) \
|
||||
MEMBER_6(PREFIX, A, B, C, D, E, F), MEMBER_1(PREFIX, G)
|
||||
|
||||
#define MEMBER_8(PREFIX, A, B, C, D, E, F, G, H) \
|
||||
MEMBER_7(PREFIX, A, B, C, D, E, F, G), MEMBER_1(PREFIX, H)
|
||||
|
||||
#define MEMBER_9(PREFIX, A, B, C, D, E, F, G, H, I) \
|
||||
MEMBER_8(PREFIX, A, B, C, D, E, F, G, H), MEMBER_1(PREFIX, I)
|
||||
|
||||
#define MEMBER_10(PREFIX, A, B, C, D, E, F, G, H, I, J) \
|
||||
MEMBER_9(PREFIX, A, B, C, D, E, F, G, H, I), MEMBER_1(PREFIX, J)
|
||||
|
||||
#define MEMBER_11(PREFIX, A, B, C, D, E, F, G, H, I, J, K) \
|
||||
MEMBER_10(PREFIX, A, B, C, D, E, F, G, H, I, J), MEMBER_1(PREFIX, K)
|
||||
|
||||
#define MEMBER_12(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L) \
|
||||
MEMBER_11(PREFIX, A, B, C, D, E, F, G, H, I, J, K), MEMBER_1(PREFIX, L)
|
||||
|
||||
#define NAMED_MEMBER_0(...)
|
||||
#define NAMED_MEMBER_1(PREFIX, FIELD) std::make_pair(#FIELD, PREFIX.FIELD)
|
||||
#define NAMED_MEMBER_2(PREFIX, A, B) NAMED_MEMBER_1(PREFIX, A), NAMED_MEMBER_1(PREFIX, B)
|
||||
#define NAMED_MEMBER_3(PREFIX, A, B, C) NAMED_MEMBER_2(PREFIX, A, B), NAMED_MEMBER_1(PREFIX, C)
|
||||
#define NAMED_MEMBER_4(PREFIX, A, B, C, D) \
|
||||
NAMED_MEMBER_3(PREFIX, A, B, C), NAMED_MEMBER_1(PREFIX, D)
|
||||
#define NAMED_MEMBER_5(PREFIX, A, B, C, D, E) \
|
||||
NAMED_MEMBER_4(PREFIX, A, B, C, D), NAMED_MEMBER_1(PREFIX, E)
|
||||
#define NAMED_MEMBER_6(PREFIX, A, B, C, D, E, F) \
|
||||
NAMED_MEMBER_5(PREFIX, A, B, C, D, E), NAMED_MEMBER_1(PREFIX, F)
|
||||
#define NAMED_MEMBER_7(PREFIX, A, B, C, D, E, F, G) \
|
||||
NAMED_MEMBER_6(PREFIX, A, B, C, D, E, F), NAMED_MEMBER_1(PREFIX, G)
|
||||
#define NAMED_MEMBER_8(PREFIX, A, B, C, D, E, F, G, H) \
|
||||
NAMED_MEMBER_7(PREFIX, A, B, C, D, E, F, G), NAMED_MEMBER_1(PREFIX, H)
|
||||
#define NAMED_MEMBER_9(PREFIX, A, B, C, D, E, F, G, H, I) \
|
||||
NAMED_MEMBER_8(PREFIX, A, B, C, D, E, F, G, H), NAMED_MEMBER_1(PREFIX, I)
|
||||
#define NAMED_MEMBER_10(PREFIX, A, B, C, D, E, F, G, H, I, J) \
|
||||
NAMED_MEMBER_9(PREFIX, A, B, C, D, E, F, G, H, I), NAMED_MEMBER_1(PREFIX, J)
|
||||
#define NAMED_MEMBER_11(PREFIX, A, B, C, D, E, F, G, H, I, J, K) \
|
||||
NAMED_MEMBER_10(PREFIX, A, B, C, D, E, F, G, H, I, J), NAMED_MEMBER_1(PREFIX, K)
|
||||
#define NAMED_MEMBER_12(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L) \
|
||||
NAMED_MEMBER_11(PREFIX, A, B, C, D, E, F, G, H, I, J, K), NAMED_MEMBER_1(PREFIX, L)
|
||||
|
||||
/// @def GET_MEMBER_FIELDS
|
||||
/// @param VAR some struct instance
|
||||
/// @param ... The member fields of the struct
|
||||
///
|
||||
/// @brief this macro is used to expand one variable (VAR) + one or more member fields (FIELDS)
|
||||
/// into a sequence of something like: `(VAR.FIELD, ...)`
|
||||
/// For example, `GET_MEMBER_FIELDS(foo, a, b, c)` would transform into `foo.a, foo.b, foo.c`:
|
||||
///
|
||||
/// @code{.cpp}
|
||||
///
|
||||
/// struct Foo
|
||||
/// {
|
||||
/// int a;
|
||||
/// float b;
|
||||
/// double c;
|
||||
/// };
|
||||
///
|
||||
/// // some function taking int, float, and double
|
||||
/// void some_function(int, float, double);
|
||||
///
|
||||
/// // overload to some_function accepting Foo instance and using
|
||||
/// // the args to invoke "real" function
|
||||
/// void some_function(Foo _foo_v)
|
||||
/// {
|
||||
/// some_function(GET_MEMBER_FIELDS(_foo_v, a, b, c));
|
||||
/// }
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
/// Foo _foo_v = {-1, 0.5f, 2.0};
|
||||
/// invoke_some_function(_foo_v);
|
||||
/// }
|
||||
///
|
||||
/// @code
|
||||
#define GET_MEMBER_FIELDS(VAR, ...) IMPL_DETAIL_FOR_EACH(MEMBER_, VAR, __VA_ARGS__)
|
||||
#define GET_NAMED_MEMBER_FIELDS(VAR, ...) IMPL_DETAIL_FOR_EACH(NAMED_MEMBER_, VAR, __VA_ARGS__)
|
||||
|
||||
#define HSA_API_INFO_DEFINITION_0(HSA_DOMAIN, HSA_TABLE, HSA_API_ID, HSA_FUNC, HSA_FUNC_PTR) \
|
||||
namespace rocprofiler \
|
||||
{ \
|
||||
namespace hsa \
|
||||
{ \
|
||||
template <> \
|
||||
struct hsa_api_info<HSA_API_ID> \
|
||||
{ \
|
||||
static constexpr auto domain_idx = HSA_DOMAIN; \
|
||||
static constexpr auto table_idx = HSA_TABLE; \
|
||||
static constexpr auto operation_idx = HSA_API_ID; \
|
||||
static constexpr auto name = #HSA_FUNC; \
|
||||
\
|
||||
using this_type = hsa_api_info<operation_idx>; \
|
||||
using base_type = hsa_api_impl<operation_idx>; \
|
||||
\
|
||||
static auto& get_table() { return hsa_table_lookup<table_idx>{}(); } \
|
||||
\
|
||||
template <typename TableT> \
|
||||
static auto& get_table(TableT& _v) \
|
||||
{ \
|
||||
return hsa_table_lookup<table_idx>{}(_v); \
|
||||
} \
|
||||
\
|
||||
template <typename TableT> \
|
||||
static auto& get_table_func(TableT& _table) \
|
||||
{ \
|
||||
if constexpr(std::is_pointer<TableT>::value) \
|
||||
{ \
|
||||
assert(_table != nullptr && "nullptr to HSA table for " #HSA_FUNC " function"); \
|
||||
return _table->HSA_FUNC_PTR; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
return _table.HSA_FUNC_PTR; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static auto& get_table_func() { return get_table_func(get_table()); } \
|
||||
\
|
||||
template <typename DataT> \
|
||||
static auto& get_api_data_args(DataT& _data) \
|
||||
{ \
|
||||
return _data.api_data.args.HSA_FUNC; \
|
||||
} \
|
||||
\
|
||||
template <typename RetT, typename... Args> \
|
||||
static auto get_functor(RetT (*)(Args...)) \
|
||||
{ \
|
||||
if constexpr(std::is_void<RetT>::value) \
|
||||
return [](Args... args) -> RetT { base_type::functor(args...); }; \
|
||||
else \
|
||||
return [](Args... args) -> RetT { return base_type::functor(args...); }; \
|
||||
} \
|
||||
\
|
||||
static auto get_functor() { return get_functor(get_table_func()); } \
|
||||
\
|
||||
static std::string as_string(hsa_trace_data_t) { return std::string{name} + "()"; } \
|
||||
\
|
||||
static std::string as_named_string(hsa_trace_data_t) { return std::string{name} + "()"; } \
|
||||
\
|
||||
static std::vector<std::pair<std::string, std::string>> as_arg_list(hsa_trace_data_t) \
|
||||
{ \
|
||||
return {}; \
|
||||
} \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define HSA_API_INFO_DEFINITION_V(HSA_DOMAIN, HSA_TABLE, HSA_API_ID, HSA_FUNC, HSA_FUNC_PTR, ...) \
|
||||
namespace rocprofiler \
|
||||
{ \
|
||||
namespace hsa \
|
||||
{ \
|
||||
template <> \
|
||||
struct hsa_api_info<HSA_API_ID> \
|
||||
{ \
|
||||
static constexpr auto domain_idx = HSA_DOMAIN; \
|
||||
static constexpr auto table_idx = HSA_TABLE; \
|
||||
static constexpr auto operation_idx = HSA_API_ID; \
|
||||
static constexpr auto name = #HSA_FUNC; \
|
||||
\
|
||||
using this_type = hsa_api_info<operation_idx>; \
|
||||
using base_type = hsa_api_impl<operation_idx>; \
|
||||
\
|
||||
static auto& get_table() { return hsa_table_lookup<table_idx>{}(); } \
|
||||
\
|
||||
template <typename TableT> \
|
||||
static auto& get_table(TableT& _v) \
|
||||
{ \
|
||||
return hsa_table_lookup<table_idx>{}(_v); \
|
||||
} \
|
||||
\
|
||||
template <typename TableT> \
|
||||
static auto& get_table_func(TableT& _table) \
|
||||
{ \
|
||||
if constexpr(std::is_pointer<TableT>::value) \
|
||||
{ \
|
||||
assert(_table != nullptr && "nullptr to HSA table for " #HSA_FUNC " function"); \
|
||||
return _table->HSA_FUNC_PTR; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
return _table.HSA_FUNC_PTR; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static auto& get_table_func() { return get_table_func(get_table()); } \
|
||||
\
|
||||
template <typename DataT> \
|
||||
static auto& get_api_data_args(DataT& _data) \
|
||||
{ \
|
||||
return _data.api_data.args.HSA_FUNC; \
|
||||
} \
|
||||
\
|
||||
template <typename RetT, typename... Args> \
|
||||
static auto get_functor(RetT (*)(Args...)) \
|
||||
{ \
|
||||
if constexpr(std::is_void<RetT>::value) \
|
||||
return [](Args... args) -> RetT { base_type::functor(args...); }; \
|
||||
else \
|
||||
return [](Args... args) -> RetT { return base_type::functor(args...); }; \
|
||||
} \
|
||||
\
|
||||
static auto get_functor() { return get_functor(get_table_func()); } \
|
||||
\
|
||||
static std::string as_string(hsa_trace_data_t trace_data) \
|
||||
{ \
|
||||
return utils::join(utils::join_args{std::string{name} + "(", ")", ", "}, \
|
||||
GET_MEMBER_FIELDS(get_api_data_args(trace_data), __VA_ARGS__)); \
|
||||
} \
|
||||
\
|
||||
static std::string as_named_string(hsa_trace_data_t trace_data) \
|
||||
{ \
|
||||
return utils::join( \
|
||||
utils::join_args{std::string{name} + "(", ")", ", "}, \
|
||||
GET_NAMED_MEMBER_FIELDS(get_api_data_args(trace_data), __VA_ARGS__)); \
|
||||
} \
|
||||
\
|
||||
static auto as_arg_list(hsa_trace_data_t trace_data) \
|
||||
{ \
|
||||
return utils::stringize( \
|
||||
GET_NAMED_MEMBER_FIELDS(get_api_data_args(trace_data), __VA_ARGS__)); \
|
||||
} \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2018-2023 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace hsa
|
||||
{
|
||||
namespace utils
|
||||
{
|
||||
struct join_args
|
||||
{
|
||||
std::string_view prefix = {};
|
||||
std::string_view suffix = {};
|
||||
std::string_view separator = {};
|
||||
};
|
||||
|
||||
template <typename Tp>
|
||||
auto
|
||||
join_impl(const Tp& _v)
|
||||
{
|
||||
return _v;
|
||||
}
|
||||
|
||||
template <typename LhsT, typename RhsT>
|
||||
auto
|
||||
join_impl(const std::pair<LhsT, RhsT>& _v)
|
||||
{
|
||||
auto _ss = std::stringstream{};
|
||||
_ss << _v.first << "=" << _v.second;
|
||||
return _ss.str();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
auto
|
||||
join(join_args ja, Args... args)
|
||||
{
|
||||
auto _content = std::string{};
|
||||
{
|
||||
auto _ss = std::stringstream{};
|
||||
((_ss << ja.separator << join_impl(args)), ...);
|
||||
auto _v = _ss.str();
|
||||
if(_v.length() > ja.separator.length()) _content = _v.substr(2);
|
||||
}
|
||||
|
||||
return (std::stringstream{} << ja.prefix << _content << ja.suffix).str();
|
||||
}
|
||||
|
||||
template <typename Tp>
|
||||
auto
|
||||
stringize_impl(const Tp& _v)
|
||||
{
|
||||
auto _ss = std::stringstream{};
|
||||
_ss << _v;
|
||||
return _ss.str();
|
||||
}
|
||||
|
||||
template <typename LhsT, typename RhsT>
|
||||
auto
|
||||
stringize_impl(const std::pair<LhsT, RhsT>& _v)
|
||||
{
|
||||
return std::make_pair(stringize_impl(_v.first), stringize_impl(_v.second));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
auto
|
||||
stringize(Args... args)
|
||||
{
|
||||
return std::vector<std::pair<std::string, std::string>>{stringize_impl(args)...};
|
||||
}
|
||||
} // namespace utils
|
||||
} // namespace hsa
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,485 @@
|
||||
// Copyright (c) 2018-2023 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include "hsa.hpp"
|
||||
#include "hsa-types.h"
|
||||
|
||||
#include <hsa/hsa_api_trace.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace hsa
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::atomic<activity_functor_t> report_activity = {};
|
||||
|
||||
auto&
|
||||
get_saved_table()
|
||||
{
|
||||
static auto _core = CoreApiTable{};
|
||||
static auto _amd_ext = AmdExtTable{};
|
||||
static auto _img_ext = ImageExtTable{};
|
||||
static auto _fini_ext = FinalizerExtTable{};
|
||||
static auto _v = []() {
|
||||
_core.version = {
|
||||
HSA_CORE_API_TABLE_MAJOR_VERSION, sizeof(_core), HSA_CORE_API_TABLE_STEP_VERSION, 0};
|
||||
_amd_ext.version = {HSA_AMD_EXT_API_TABLE_MAJOR_VERSION,
|
||||
sizeof(_amd_ext),
|
||||
HSA_AMD_EXT_API_TABLE_STEP_VERSION,
|
||||
0};
|
||||
_img_ext.version = {HSA_IMAGE_API_TABLE_MAJOR_VERSION,
|
||||
sizeof(_img_ext),
|
||||
HSA_IMAGE_API_TABLE_STEP_VERSION,
|
||||
0};
|
||||
_fini_ext.version = {HSA_FINALIZER_API_TABLE_MAJOR_VERSION,
|
||||
sizeof(_fini_ext),
|
||||
HSA_FINALIZER_API_TABLE_STEP_VERSION,
|
||||
0};
|
||||
auto _version = ApiTableVersion{
|
||||
HSA_API_TABLE_MAJOR_VERSION, sizeof(HsaApiTable), HSA_API_TABLE_STEP_VERSION, 0};
|
||||
auto _val = hsa_api_table_t{_version, &_core, &_amd_ext, &_fini_ext, &_img_ext};
|
||||
return _val;
|
||||
}();
|
||||
return _v;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <>
|
||||
struct hsa_table_lookup<HSA_API_TABLE_ID_CoreApi>
|
||||
{
|
||||
auto& operator()(hsa_api_table_t& _v) const { return _v.core_; }
|
||||
auto& operator()(hsa_api_table_t* _v) const { return _v->core_; }
|
||||
auto& operator()() const { return (*this)(get_saved_table()); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hsa_table_lookup<HSA_API_TABLE_ID_AmdExt>
|
||||
{
|
||||
auto& operator()(hsa_api_table_t& _v) const { return _v.amd_ext_; }
|
||||
auto& operator()(hsa_api_table_t* _v) const { return _v->amd_ext_; }
|
||||
auto& operator()() const { return (*this)(get_saved_table()); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hsa_table_lookup<HSA_API_TABLE_ID_ImageExt>
|
||||
{
|
||||
auto& operator()(hsa_api_table_t& _v) const { return _v.image_ext_; }
|
||||
auto& operator()(hsa_api_table_t* _v) const { return _v->image_ext_; }
|
||||
auto& operator()() const { return (*this)(get_saved_table()); }
|
||||
};
|
||||
|
||||
template <typename DataT, typename Tp>
|
||||
void
|
||||
set_data_retval(DataT& _data, Tp _val)
|
||||
{
|
||||
if constexpr(std::is_same<Tp, hsa_signal_value_t>::value)
|
||||
{
|
||||
_data.hsa_signal_value_t_retval = _val;
|
||||
}
|
||||
else if constexpr(std::is_same<Tp, uint64_t>::value)
|
||||
{
|
||||
_data.uint64_t_retval = _val;
|
||||
}
|
||||
else if constexpr(std::is_same<Tp, uint32_t>::value)
|
||||
{
|
||||
_data.uint32_t_retval = _val;
|
||||
}
|
||||
else if constexpr(std::is_same<Tp, hsa_status_t>::value)
|
||||
{
|
||||
_data.hsa_status_t_retval = _val;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(std::is_void<Tp>::value, "Error! unsupported return type");
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t Idx>
|
||||
template <typename DataT, typename DataArgsT, typename... Args>
|
||||
auto
|
||||
hsa_api_impl<Idx>::phase_enter(DataT& _data, DataArgsT& _data_args, Args... args)
|
||||
{
|
||||
using info_type = hsa_api_info<Idx>;
|
||||
|
||||
activity_functor_t _func = report_activity.load(std::memory_order_relaxed);
|
||||
if(_func)
|
||||
{
|
||||
if constexpr(Idx == HSA_API_ID_hsa_amd_memory_async_copy_rect)
|
||||
{
|
||||
auto _tuple = std::make_tuple(args...);
|
||||
_data.api_data.args.hsa_amd_memory_async_copy_rect.dst = std::get<0>(_tuple);
|
||||
_data.api_data.args.hsa_amd_memory_async_copy_rect.dst_offset = std::get<1>(_tuple);
|
||||
_data.api_data.args.hsa_amd_memory_async_copy_rect.src = std::get<2>(_tuple);
|
||||
_data.api_data.args.hsa_amd_memory_async_copy_rect.src_offset = std::get<3>(_tuple);
|
||||
_data.api_data.args.hsa_amd_memory_async_copy_rect.range = std::get<4>(_tuple);
|
||||
_data.api_data.args.hsa_amd_memory_async_copy_rect.range__val = *(std::get<4>(_tuple));
|
||||
_data.api_data.args.hsa_amd_memory_async_copy_rect.copy_agent = std::get<5>(_tuple);
|
||||
_data.api_data.args.hsa_amd_memory_async_copy_rect.dir = std::get<6>(_tuple);
|
||||
_data.api_data.args.hsa_amd_memory_async_copy_rect.num_dep_signals =
|
||||
std::get<7>(_tuple);
|
||||
_data.api_data.args.hsa_amd_memory_async_copy_rect.dep_signals = std::get<8>(_tuple);
|
||||
_data.api_data.args.hsa_amd_memory_async_copy_rect.completion_signal =
|
||||
std::get<9>(_tuple);
|
||||
}
|
||||
else
|
||||
{
|
||||
_data_args = DataArgsT{args...};
|
||||
}
|
||||
if(_func(info_type::domain_idx, info_type::operation_idx, &_data) == 0)
|
||||
{
|
||||
if(_data.phase_enter != nullptr) _data.phase_enter(info_type::operation_idx, &_data);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <size_t Idx>
|
||||
template <typename DataT, typename... Args>
|
||||
auto
|
||||
hsa_api_impl<Idx>::phase_exit(DataT& _data)
|
||||
{
|
||||
using info_type = hsa_api_info<Idx>;
|
||||
|
||||
if(_data.phase_exit != nullptr)
|
||||
{
|
||||
_data.phase_exit(info_type::operation_idx, &_data);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct null_type
|
||||
{};
|
||||
|
||||
template <size_t Idx>
|
||||
template <typename DataT, typename FuncT, typename... Args>
|
||||
auto
|
||||
hsa_api_impl<Idx>::exec(DataT& _data, FuncT&& _func, Args&&... args)
|
||||
{
|
||||
using return_type = std::decay_t<std::invoke_result_t<FuncT, Args...>>;
|
||||
|
||||
if(_func)
|
||||
{
|
||||
static_assert(std::is_void<return_type>::value || std::is_enum<return_type>::value ||
|
||||
std::is_integral<return_type>::value,
|
||||
"Error! unsupported return type");
|
||||
|
||||
if constexpr(std::is_void<return_type>::value)
|
||||
{
|
||||
_func(std::forward<Args>(args)...);
|
||||
return null_type{};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto _ret = _func(std::forward<Args>(args)...);
|
||||
set_data_retval(_data.api_data, _ret);
|
||||
return _ret;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr(std::is_void<return_type>::value)
|
||||
return null_type{};
|
||||
else
|
||||
return return_type{HSA_STATUS_ERROR};
|
||||
}
|
||||
|
||||
template <size_t Idx>
|
||||
template <typename... Args>
|
||||
auto
|
||||
hsa_api_impl<Idx>::functor(Args&&... args)
|
||||
{
|
||||
using info_type = hsa_api_info<Idx>;
|
||||
|
||||
auto trace_data = hsa_trace_data_t{};
|
||||
|
||||
auto _enabled = phase_enter(
|
||||
trace_data, info_type::get_api_data_args(trace_data), std::forward<Args>(args)...);
|
||||
|
||||
auto _ret = exec(trace_data, info_type::get_table_func(), std::forward<Args>(args)...);
|
||||
|
||||
if(_enabled) phase_exit(trace_data);
|
||||
|
||||
if constexpr(!std::is_same<decltype(_ret), null_type>::value)
|
||||
return _ret;
|
||||
else
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
} // namespace hsa
|
||||
} // namespace rocprofiler
|
||||
|
||||
#include "hsa.gen.cpp"
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace hsa
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template <size_t Idx, size_t... IdxTail>
|
||||
const char*
|
||||
hsa_api_name(const uint32_t id, std::index_sequence<Idx, IdxTail...>)
|
||||
{
|
||||
if(Idx == id) return hsa_api_info<Idx>::name;
|
||||
if constexpr(sizeof...(IdxTail) > 0)
|
||||
return hsa_api_name(id, std::index_sequence<IdxTail...>{});
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <size_t Idx, size_t... IdxTail>
|
||||
uint32_t
|
||||
hsa_api_id_by_name(const char* name, std::index_sequence<Idx, IdxTail...>)
|
||||
{
|
||||
if(std::string_view{hsa_api_info<Idx>::name} == std::string_view{name})
|
||||
return hsa_api_info<Idx>::operation_idx;
|
||||
if constexpr(sizeof...(IdxTail) > 0)
|
||||
return hsa_api_id_by_name(name, std::index_sequence<IdxTail...>{});
|
||||
else
|
||||
return HSA_API_ID_NONE;
|
||||
}
|
||||
|
||||
template <size_t Idx, size_t... IdxTail>
|
||||
std::string
|
||||
hsa_api_data_string(const uint32_t id,
|
||||
const hsa_trace_data_t& _data,
|
||||
std::index_sequence<Idx, IdxTail...>)
|
||||
{
|
||||
if(Idx == id) return hsa_api_info<Idx>::as_string(_data);
|
||||
if constexpr(sizeof...(IdxTail) > 0)
|
||||
return hsa_api_data_string(id, _data, std::index_sequence<IdxTail...>{});
|
||||
else
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
template <size_t Idx, size_t... IdxTail>
|
||||
std::string
|
||||
hsa_api_named_data_string(const uint32_t id,
|
||||
const hsa_trace_data_t& _data,
|
||||
std::index_sequence<Idx, IdxTail...>)
|
||||
{
|
||||
if(Idx == id) return hsa_api_info<Idx>::as_named_string(_data);
|
||||
if constexpr(sizeof...(IdxTail) > 0)
|
||||
return hsa_api_named_data_string(id, _data, std::index_sequence<IdxTail...>{});
|
||||
else
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
template <size_t Idx, size_t... IdxTail>
|
||||
void
|
||||
hsa_api_iterate_args(const uint32_t id,
|
||||
const hsa_trace_data_t& _data,
|
||||
int (*_func)(const char*, const char*),
|
||||
std::index_sequence<Idx, IdxTail...>)
|
||||
{
|
||||
if(Idx == id)
|
||||
{
|
||||
for(auto&& itr : hsa_api_info<Idx>::as_arg_list(_data))
|
||||
{
|
||||
_func(itr.first.c_str(), itr.second.c_str());
|
||||
}
|
||||
}
|
||||
if constexpr(sizeof...(IdxTail) > 0)
|
||||
hsa_api_iterate_args(id, _data, _func, std::index_sequence<IdxTail...>{});
|
||||
}
|
||||
|
||||
template <size_t... Idx>
|
||||
void
|
||||
hsa_api_get_ids(std::vector<uint32_t>& _id_list, std::index_sequence<Idx...>)
|
||||
{
|
||||
auto _emplace = [](auto& _vec, uint32_t _v) {
|
||||
if(_v < HSA_API_ID_DISPATCH) _vec.emplace_back(_v);
|
||||
};
|
||||
|
||||
(_emplace(_id_list, hsa_api_info<Idx>::operation_idx), ...);
|
||||
}
|
||||
|
||||
template <size_t... Idx>
|
||||
void
|
||||
hsa_api_get_names(std::vector<const char*>& _name_list, std::index_sequence<Idx...>)
|
||||
{
|
||||
auto _emplace = [](auto& _vec, const char* _v) {
|
||||
if(_v != nullptr && strnlen(_v, 1) > 0) _vec.emplace_back(_v);
|
||||
};
|
||||
|
||||
(_emplace(_name_list, hsa_api_info<Idx>::name), ...);
|
||||
}
|
||||
|
||||
template <size_t... Idx>
|
||||
void
|
||||
hsa_api_update_table(hsa_api_table_t* _orig, std::index_sequence<Idx...>)
|
||||
{
|
||||
auto _update = [](hsa_api_table_t* _orig_v, auto _info) {
|
||||
// 1. get the sub-table containing the function pointer
|
||||
// 2. get reference to function pointer in sub-table
|
||||
// 3. update function pointer with functor
|
||||
auto& _table = _info.get_table(_orig_v);
|
||||
auto& _func = _info.get_table_func(_table);
|
||||
_func = _info.get_functor(_func);
|
||||
};
|
||||
|
||||
(_update(_orig, hsa_api_info<Idx>{}), ...);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// check out the assembly here... this compiles to a switch statement
|
||||
const char*
|
||||
hsa_api_name(uint32_t id)
|
||||
{
|
||||
return hsa_api_name(id, std::make_index_sequence<HSA_API_ID_DISPATCH>{});
|
||||
}
|
||||
|
||||
uint32_t
|
||||
hsa_api_id_by_name(const char* name)
|
||||
{
|
||||
return hsa_api_id_by_name(name, std::make_index_sequence<HSA_API_ID_DISPATCH>{});
|
||||
}
|
||||
|
||||
std::string
|
||||
hsa_api_data_string(uint32_t id, const hsa_trace_data_t& _data)
|
||||
{
|
||||
return hsa_api_data_string(id, _data, std::make_index_sequence<HSA_API_ID_DISPATCH>{});
|
||||
}
|
||||
|
||||
std::string
|
||||
hsa_api_named_data_string(uint32_t id, const hsa_trace_data_t& _data)
|
||||
{
|
||||
return hsa_api_named_data_string(id, _data, std::make_index_sequence<HSA_API_ID_DISPATCH>{});
|
||||
}
|
||||
|
||||
void
|
||||
hsa_api_iterate_args(uint32_t id,
|
||||
const hsa_trace_data_t& _data,
|
||||
int (*_func)(const char*, const char*))
|
||||
{
|
||||
if(_func)
|
||||
hsa_api_iterate_args(id, _data, _func, std::make_index_sequence<HSA_API_ID_DISPATCH>{});
|
||||
}
|
||||
|
||||
std::vector<uint32_t>
|
||||
hsa_api_get_ids()
|
||||
{
|
||||
auto _data = std::vector<uint32_t>{};
|
||||
_data.reserve(HSA_API_ID_DISPATCH);
|
||||
hsa_api_get_ids(_data, std::make_index_sequence<HSA_API_ID_DISPATCH>{});
|
||||
return _data;
|
||||
}
|
||||
|
||||
std::vector<const char*>
|
||||
hsa_api_get_names()
|
||||
{
|
||||
auto _data = std::vector<const char*>{};
|
||||
_data.reserve(HSA_API_ID_DISPATCH);
|
||||
hsa_api_get_names(_data, std::make_index_sequence<HSA_API_ID_DISPATCH>{});
|
||||
return _data;
|
||||
}
|
||||
|
||||
void
|
||||
hsa_api_set_callback(activity_functor_t _func)
|
||||
{
|
||||
auto&& _v = report_activity.load();
|
||||
report_activity.compare_exchange_strong(_v, _func);
|
||||
}
|
||||
|
||||
void
|
||||
hsa_api_update_table(hsa_api_table_t* _orig)
|
||||
{
|
||||
if(_orig) hsa_api_update_table(_orig, std::make_index_sequence<HSA_API_ID_DISPATCH>{});
|
||||
}
|
||||
} // namespace hsa
|
||||
} // namespace rocprofiler
|
||||
|
||||
extern "C" {
|
||||
bool
|
||||
OnLoad(HsaApiTable* table,
|
||||
uint64_t runtime_version,
|
||||
uint64_t failed_tool_count,
|
||||
const char* const* failed_tool_names)
|
||||
{
|
||||
(void) runtime_version;
|
||||
(void) failed_tool_count;
|
||||
(void) failed_tool_names;
|
||||
|
||||
auto& _saved = rocprofiler::hsa::get_saved_table();
|
||||
copyTables(table, &_saved);
|
||||
|
||||
rocprofiler::hsa::hsa_api_update_table(table);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#include <iomanip>
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
rocprofiler::hsa::activity_functor_t _cb =
|
||||
[](rocprofiler_tracer_activity_domain_t domain, uint32_t operation_id, void* data) {
|
||||
const auto* _name = rocprofiler::hsa::hsa_api_name(operation_id);
|
||||
auto _name_id = rocprofiler::hsa::hsa_api_id_by_name(_name);
|
||||
auto& _data = *static_cast<rocprofiler::hsa::hsa_trace_data_t*>(data);
|
||||
std::cout << "[cb] domain=" << domain << ", op_id=" << operation_id << ", data=" << data
|
||||
<< ", name=" << _name << ", name_id=" << _name_id << ", named_string='"
|
||||
<< rocprofiler::hsa::hsa_api_named_data_string(operation_id, _data) << "'"
|
||||
<< "\n";
|
||||
auto _func = [](const char* name, const char* value) {
|
||||
std::cout << " " << std::setw(20) << name << " = " << value << "\n";
|
||||
return 0;
|
||||
};
|
||||
rocprofiler::hsa::hsa_api_iterate_args(operation_id, _data, _func);
|
||||
return 0;
|
||||
};
|
||||
|
||||
rocprofiler::hsa::report_activity.store(_cb);
|
||||
|
||||
{
|
||||
double val = 40;
|
||||
hsa_code_object_t code_object = {};
|
||||
hsa_code_object_info_t attribute = HSA_CODE_OBJECT_INFO_TYPE;
|
||||
void* value = &val;
|
||||
|
||||
auto _func =
|
||||
rocprofiler::hsa::hsa_api_info<HSA_API_ID_hsa_code_object_get_info>::get_functor();
|
||||
_func(code_object, attribute, value);
|
||||
}
|
||||
|
||||
{
|
||||
bool result = false;
|
||||
uint16_t ext = 1;
|
||||
uint16_t major = 4;
|
||||
uint16_t minor = 2;
|
||||
|
||||
auto _func = rocprofiler::hsa::hsa_api_info<
|
||||
HSA_API_ID_hsa_system_extension_supported>::get_functor();
|
||||
_func(ext, major, minor, &result);
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,217 @@
|
||||
// Copyright (c) 2018-2023 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include "hsa.hpp"
|
||||
|
||||
// clang-format off
|
||||
HSA_API_INFO_DEFINITION_0(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_init, hsa_init, hsa_init_fn)
|
||||
HSA_API_INFO_DEFINITION_0(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_shut_down, hsa_shut_down, hsa_shut_down_fn)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_system_get_info, hsa_system_get_info, hsa_system_get_info_fn, attribute, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_system_extension_supported, hsa_system_extension_supported, hsa_system_extension_supported_fn, extension, version_major, version_minor, result)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_system_get_extension_table, hsa_system_get_extension_table, hsa_system_get_extension_table_fn, extension, version_major, version_minor, table)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_iterate_agents, hsa_iterate_agents, hsa_iterate_agents_fn, callback, data)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_agent_get_info, hsa_agent_get_info, hsa_agent_get_info_fn, agent, attribute, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_create, hsa_queue_create, hsa_queue_create_fn, agent, size, type, callback, data, private_segment_size, group_segment_size, queue)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_soft_queue_create, hsa_soft_queue_create, hsa_soft_queue_create_fn, region, size, type, features, doorbell_signal, queue)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_destroy, hsa_queue_destroy, hsa_queue_destroy_fn, queue)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_inactivate, hsa_queue_inactivate, hsa_queue_inactivate_fn, queue)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_load_read_index_scacquire, hsa_queue_load_read_index_scacquire, hsa_queue_load_read_index_scacquire_fn, queue)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_load_read_index_relaxed, hsa_queue_load_read_index_relaxed, hsa_queue_load_read_index_relaxed_fn, queue)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_load_write_index_scacquire, hsa_queue_load_write_index_scacquire, hsa_queue_load_write_index_scacquire_fn, queue)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_load_write_index_relaxed, hsa_queue_load_write_index_relaxed, hsa_queue_load_write_index_relaxed_fn, queue)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_store_write_index_relaxed, hsa_queue_store_write_index_relaxed, hsa_queue_store_write_index_relaxed_fn, queue, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_store_write_index_screlease, hsa_queue_store_write_index_screlease, hsa_queue_store_write_index_screlease_fn, queue, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_cas_write_index_scacq_screl, hsa_queue_cas_write_index_scacq_screl, hsa_queue_cas_write_index_scacq_screl_fn, queue, expected, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_cas_write_index_scacquire, hsa_queue_cas_write_index_scacquire, hsa_queue_cas_write_index_scacquire_fn, queue, expected, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_cas_write_index_relaxed, hsa_queue_cas_write_index_relaxed, hsa_queue_cas_write_index_relaxed_fn, queue, expected, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_cas_write_index_screlease, hsa_queue_cas_write_index_screlease, hsa_queue_cas_write_index_screlease_fn, queue, expected, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_add_write_index_scacq_screl, hsa_queue_add_write_index_scacq_screl, hsa_queue_add_write_index_scacq_screl_fn, queue, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_add_write_index_scacquire, hsa_queue_add_write_index_scacquire, hsa_queue_add_write_index_scacquire_fn, queue, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_add_write_index_relaxed, hsa_queue_add_write_index_relaxed, hsa_queue_add_write_index_relaxed_fn, queue, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_add_write_index_screlease, hsa_queue_add_write_index_screlease, hsa_queue_add_write_index_screlease_fn, queue, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_store_read_index_relaxed, hsa_queue_store_read_index_relaxed, hsa_queue_store_read_index_relaxed_fn, queue, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_queue_store_read_index_screlease, hsa_queue_store_read_index_screlease, hsa_queue_store_read_index_screlease_fn, queue, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_agent_iterate_regions, hsa_agent_iterate_regions, hsa_agent_iterate_regions_fn, agent, callback, data)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_region_get_info, hsa_region_get_info, hsa_region_get_info_fn, region, attribute, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_agent_get_exception_policies, hsa_agent_get_exception_policies, hsa_agent_get_exception_policies_fn, agent, profile, mask)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_agent_extension_supported, hsa_agent_extension_supported, hsa_agent_extension_supported_fn, extension, agent, version_major, version_minor, result)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_memory_register, hsa_memory_register, hsa_memory_register_fn, ptr, size)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_memory_deregister, hsa_memory_deregister, hsa_memory_deregister_fn, ptr, size)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_memory_allocate, hsa_memory_allocate, hsa_memory_allocate_fn, region, size, ptr)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_memory_free, hsa_memory_free, hsa_memory_free_fn, ptr)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_memory_copy, hsa_memory_copy, hsa_memory_copy_fn, dst, src, size)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_memory_assign_agent, hsa_memory_assign_agent, hsa_memory_assign_agent_fn, ptr, agent, access)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_create, hsa_signal_create, hsa_signal_create_fn, initial_value, num_consumers, consumers, signal)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_destroy, hsa_signal_destroy, hsa_signal_destroy_fn, signal)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_load_relaxed, hsa_signal_load_relaxed, hsa_signal_load_relaxed_fn, signal)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_load_scacquire, hsa_signal_load_scacquire, hsa_signal_load_scacquire_fn, signal)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_store_relaxed, hsa_signal_store_relaxed, hsa_signal_store_relaxed_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_store_screlease, hsa_signal_store_screlease, hsa_signal_store_screlease_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_wait_relaxed, hsa_signal_wait_relaxed, hsa_signal_wait_relaxed_fn, signal, condition, compare_value, timeout_hint, wait_state_hint)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_wait_scacquire, hsa_signal_wait_scacquire, hsa_signal_wait_scacquire_fn, signal, condition, compare_value, timeout_hint, wait_state_hint)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_and_relaxed, hsa_signal_and_relaxed, hsa_signal_and_relaxed_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_and_scacquire, hsa_signal_and_scacquire, hsa_signal_and_scacquire_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_and_screlease, hsa_signal_and_screlease, hsa_signal_and_screlease_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_and_scacq_screl, hsa_signal_and_scacq_screl, hsa_signal_and_scacq_screl_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_or_relaxed, hsa_signal_or_relaxed, hsa_signal_or_relaxed_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_or_scacquire, hsa_signal_or_scacquire, hsa_signal_or_scacquire_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_or_screlease, hsa_signal_or_screlease, hsa_signal_or_screlease_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_or_scacq_screl, hsa_signal_or_scacq_screl, hsa_signal_or_scacq_screl_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_xor_relaxed, hsa_signal_xor_relaxed, hsa_signal_xor_relaxed_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_xor_scacquire, hsa_signal_xor_scacquire, hsa_signal_xor_scacquire_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_xor_screlease, hsa_signal_xor_screlease, hsa_signal_xor_screlease_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_xor_scacq_screl, hsa_signal_xor_scacq_screl, hsa_signal_xor_scacq_screl_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_exchange_relaxed, hsa_signal_exchange_relaxed, hsa_signal_exchange_relaxed_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_exchange_scacquire, hsa_signal_exchange_scacquire, hsa_signal_exchange_scacquire_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_exchange_screlease, hsa_signal_exchange_screlease, hsa_signal_exchange_screlease_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_exchange_scacq_screl, hsa_signal_exchange_scacq_screl, hsa_signal_exchange_scacq_screl_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_add_relaxed, hsa_signal_add_relaxed, hsa_signal_add_relaxed_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_add_scacquire, hsa_signal_add_scacquire, hsa_signal_add_scacquire_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_add_screlease, hsa_signal_add_screlease, hsa_signal_add_screlease_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_add_scacq_screl, hsa_signal_add_scacq_screl, hsa_signal_add_scacq_screl_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_subtract_relaxed, hsa_signal_subtract_relaxed, hsa_signal_subtract_relaxed_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_subtract_scacquire, hsa_signal_subtract_scacquire, hsa_signal_subtract_scacquire_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_subtract_screlease, hsa_signal_subtract_screlease, hsa_signal_subtract_screlease_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_subtract_scacq_screl, hsa_signal_subtract_scacq_screl, hsa_signal_subtract_scacq_screl_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_cas_relaxed, hsa_signal_cas_relaxed, hsa_signal_cas_relaxed_fn, signal, expected, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_cas_scacquire, hsa_signal_cas_scacquire, hsa_signal_cas_scacquire_fn, signal, expected, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_cas_screlease, hsa_signal_cas_screlease, hsa_signal_cas_screlease_fn, signal, expected, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_cas_scacq_screl, hsa_signal_cas_scacq_screl, hsa_signal_cas_scacq_screl_fn, signal, expected, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_isa_from_name, hsa_isa_from_name, hsa_isa_from_name_fn, name, isa)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_isa_get_info, hsa_isa_get_info, hsa_isa_get_info_fn, isa, attribute, index, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_isa_compatible, hsa_isa_compatible, hsa_isa_compatible_fn, code_object_isa, agent_isa, result)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_code_object_serialize, hsa_code_object_serialize, hsa_code_object_serialize_fn, code_object, alloc_callback, callback_data, options, serialized_code_object, serialized_code_object_size)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_code_object_deserialize, hsa_code_object_deserialize, hsa_code_object_deserialize_fn, serialized_code_object, serialized_code_object_size, options, code_object)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_code_object_destroy, hsa_code_object_destroy, hsa_code_object_destroy_fn, code_object)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_code_object_get_info, hsa_code_object_get_info, hsa_code_object_get_info_fn, code_object, attribute, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_code_object_get_symbol, hsa_code_object_get_symbol, hsa_code_object_get_symbol_fn, code_object, symbol_name, symbol)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_code_symbol_get_info, hsa_code_symbol_get_info, hsa_code_symbol_get_info_fn, code_symbol, attribute, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_code_object_iterate_symbols, hsa_code_object_iterate_symbols, hsa_code_object_iterate_symbols_fn, code_object, callback, data)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_create, hsa_executable_create, hsa_executable_create_fn, profile, executable_state, options, executable)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_destroy, hsa_executable_destroy, hsa_executable_destroy_fn, executable)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_load_code_object, hsa_executable_load_code_object, hsa_executable_load_code_object_fn, executable, agent, code_object, options)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_freeze, hsa_executable_freeze, hsa_executable_freeze_fn, executable, options)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_get_info, hsa_executable_get_info, hsa_executable_get_info_fn, executable, attribute, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_global_variable_define, hsa_executable_global_variable_define, hsa_executable_global_variable_define_fn, executable, variable_name, address)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_agent_global_variable_define, hsa_executable_agent_global_variable_define, hsa_executable_agent_global_variable_define_fn, executable, agent, variable_name, address)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_readonly_variable_define, hsa_executable_readonly_variable_define, hsa_executable_readonly_variable_define_fn, executable, agent, variable_name, address)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_validate, hsa_executable_validate, hsa_executable_validate_fn, executable, result)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_get_symbol, hsa_executable_get_symbol, hsa_executable_get_symbol_fn, executable, module_name, symbol_name, agent, call_convention, symbol)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_symbol_get_info, hsa_executable_symbol_get_info, hsa_executable_symbol_get_info_fn, executable_symbol, attribute, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_iterate_symbols, hsa_executable_iterate_symbols, hsa_executable_iterate_symbols_fn, executable, callback, data)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_status_string, hsa_status_string, hsa_status_string_fn, status, status_string)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_extension_get_name, hsa_extension_get_name, hsa_extension_get_name_fn, extension, name)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_system_major_extension_supported, hsa_system_major_extension_supported, hsa_system_major_extension_supported_fn, extension, version_major, version_minor, result)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_system_get_major_extension_table, hsa_system_get_major_extension_table, hsa_system_get_major_extension_table_fn, extension, version_major, table_length, table)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_agent_major_extension_supported, hsa_agent_major_extension_supported, hsa_agent_major_extension_supported_fn, extension, agent, version_major, version_minor, result)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_cache_get_info, hsa_cache_get_info, hsa_cache_get_info_fn, cache, attribute, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_agent_iterate_caches, hsa_agent_iterate_caches, hsa_agent_iterate_caches_fn, agent, callback, data)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_silent_store_relaxed, hsa_signal_silent_store_relaxed, hsa_signal_silent_store_relaxed_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_silent_store_screlease, hsa_signal_silent_store_screlease, hsa_signal_silent_store_screlease_fn, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_group_create, hsa_signal_group_create, hsa_signal_group_create_fn, num_signals, signals, num_consumers, consumers, signal_group)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_group_destroy, hsa_signal_group_destroy, hsa_signal_group_destroy_fn, signal_group)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_group_wait_any_scacquire, hsa_signal_group_wait_any_scacquire, hsa_signal_group_wait_any_scacquire_fn, signal_group, conditions, compare_values, wait_state_hint, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_signal_group_wait_any_relaxed, hsa_signal_group_wait_any_relaxed, hsa_signal_group_wait_any_relaxed_fn, signal_group, conditions, compare_values, wait_state_hint, signal, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_agent_iterate_isas, hsa_agent_iterate_isas, hsa_agent_iterate_isas_fn, agent, callback, data)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_isa_get_info_alt, hsa_isa_get_info_alt, hsa_isa_get_info_alt_fn, isa, attribute, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_isa_get_exception_policies, hsa_isa_get_exception_policies, hsa_isa_get_exception_policies_fn, isa, profile, mask)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_isa_get_round_method, hsa_isa_get_round_method, hsa_isa_get_round_method_fn, isa, fp_type, flush_mode, round_method)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_wavefront_get_info, hsa_wavefront_get_info, hsa_wavefront_get_info_fn, wavefront, attribute, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_isa_iterate_wavefronts, hsa_isa_iterate_wavefronts, hsa_isa_iterate_wavefronts_fn, isa, callback, data)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_code_object_get_symbol_from_name, hsa_code_object_get_symbol_from_name, hsa_code_object_get_symbol_from_name_fn, code_object, module_name, symbol_name, symbol)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_code_object_reader_create_from_file, hsa_code_object_reader_create_from_file, hsa_code_object_reader_create_from_file_fn, file, code_object_reader)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_code_object_reader_create_from_memory, hsa_code_object_reader_create_from_memory, hsa_code_object_reader_create_from_memory_fn, code_object, size, code_object_reader)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_code_object_reader_destroy, hsa_code_object_reader_destroy, hsa_code_object_reader_destroy_fn, code_object_reader)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_create_alt, hsa_executable_create_alt, hsa_executable_create_alt_fn, profile, default_float_rounding_mode, options, executable)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_load_program_code_object, hsa_executable_load_program_code_object, hsa_executable_load_program_code_object_fn, executable, code_object_reader, options, loaded_code_object)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_load_agent_code_object, hsa_executable_load_agent_code_object, hsa_executable_load_agent_code_object_fn, executable, agent, code_object_reader, options, loaded_code_object)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_validate_alt, hsa_executable_validate_alt, hsa_executable_validate_alt_fn, executable, options, result)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_get_symbol_by_name, hsa_executable_get_symbol_by_name, hsa_executable_get_symbol_by_name_fn, executable, symbol_name, agent, symbol)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_iterate_agent_symbols, hsa_executable_iterate_agent_symbols, hsa_executable_iterate_agent_symbols_fn, executable, agent, callback, data)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_CoreApi, HSA_API_ID_hsa_executable_iterate_program_symbols, hsa_executable_iterate_program_symbols, hsa_executable_iterate_program_symbols_fn, executable, callback, data)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_coherency_get_type, hsa_amd_coherency_get_type, hsa_amd_coherency_get_type_fn, agent, type)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_coherency_set_type, hsa_amd_coherency_set_type, hsa_amd_coherency_set_type_fn, agent, type)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_profiling_set_profiler_enabled, hsa_amd_profiling_set_profiler_enabled, hsa_amd_profiling_set_profiler_enabled_fn, queue, enable)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_profiling_async_copy_enable, hsa_amd_profiling_async_copy_enable, hsa_amd_profiling_async_copy_enable_fn, enable)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_profiling_get_dispatch_time, hsa_amd_profiling_get_dispatch_time, hsa_amd_profiling_get_dispatch_time_fn, agent, signal, time)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_profiling_get_async_copy_time, hsa_amd_profiling_get_async_copy_time, hsa_amd_profiling_get_async_copy_time_fn, signal, time)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_profiling_convert_tick_to_system_domain, hsa_amd_profiling_convert_tick_to_system_domain, hsa_amd_profiling_convert_tick_to_system_domain_fn, agent, agent_tick, system_tick)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_signal_async_handler, hsa_amd_signal_async_handler, hsa_amd_signal_async_handler_fn, signal, cond, value, handler, arg)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_async_function, hsa_amd_async_function, hsa_amd_async_function_fn, callback, arg)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_signal_wait_any, hsa_amd_signal_wait_any, hsa_amd_signal_wait_any_fn, signal_count, signals, conds, values, timeout_hint, wait_hint, satisfying_value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_queue_cu_set_mask, hsa_amd_queue_cu_set_mask, hsa_amd_queue_cu_set_mask_fn, queue, num_cu_mask_count, cu_mask)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_memory_pool_get_info, hsa_amd_memory_pool_get_info, hsa_amd_memory_pool_get_info_fn, memory_pool, attribute, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_agent_iterate_memory_pools, hsa_amd_agent_iterate_memory_pools, hsa_amd_agent_iterate_memory_pools_fn, agent, callback, data)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_memory_pool_allocate, hsa_amd_memory_pool_allocate, hsa_amd_memory_pool_allocate_fn, memory_pool, size, flags, ptr)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_memory_pool_free, hsa_amd_memory_pool_free, hsa_amd_memory_pool_free_fn, ptr)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_memory_async_copy, hsa_amd_memory_async_copy, hsa_amd_memory_async_copy_fn, dst, dst_agent, src, src_agent, size, num_dep_signals, dep_signals, completion_signal)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_memory_async_copy_on_engine, hsa_amd_memory_async_copy_on_engine, hsa_amd_memory_async_copy_on_engine_fn, dst, dst_agent, src, src_agent, size, num_dep_signals, dep_signals, completion_signal, engine_id, force_copy_on_sdma)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_memory_copy_engine_status, hsa_amd_memory_copy_engine_status, hsa_amd_memory_copy_engine_status_fn, dst_agent, src_agent, engine_ids_mask)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_agent_memory_pool_get_info, hsa_amd_agent_memory_pool_get_info, hsa_amd_agent_memory_pool_get_info_fn, agent, memory_pool, attribute, value)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_agents_allow_access, hsa_amd_agents_allow_access, hsa_amd_agents_allow_access_fn, num_agents, agents, flags, ptr)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_memory_pool_can_migrate, hsa_amd_memory_pool_can_migrate, hsa_amd_memory_pool_can_migrate_fn, src_memory_pool, dst_memory_pool, result)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_memory_migrate, hsa_amd_memory_migrate, hsa_amd_memory_migrate_fn, ptr, memory_pool, flags)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_memory_lock, hsa_amd_memory_lock, hsa_amd_memory_lock_fn, host_ptr, size, agents, num_agent, agent_ptr)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_memory_unlock, hsa_amd_memory_unlock, hsa_amd_memory_unlock_fn, host_ptr)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_memory_fill, hsa_amd_memory_fill, hsa_amd_memory_fill_fn, ptr, value, count)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_interop_map_buffer, hsa_amd_interop_map_buffer, hsa_amd_interop_map_buffer_fn, num_agents, agents, interop_handle, flags, size, ptr, metadata_size, metadata)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_interop_unmap_buffer, hsa_amd_interop_unmap_buffer, hsa_amd_interop_unmap_buffer_fn, ptr)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_image_create, hsa_amd_image_create, hsa_amd_image_create_fn, agent, image_descriptor, image_layout, image_data, access_permission, image)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_pointer_info, hsa_amd_pointer_info, hsa_amd_pointer_info_fn, ptr, info, alloc, num_agents_accessible, accessible)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_pointer_info_set_userdata, hsa_amd_pointer_info_set_userdata, hsa_amd_pointer_info_set_userdata_fn, ptr, userdata)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_ipc_memory_create, hsa_amd_ipc_memory_create, hsa_amd_ipc_memory_create_fn, ptr, len, handle)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_ipc_memory_attach, hsa_amd_ipc_memory_attach, hsa_amd_ipc_memory_attach_fn, handle, len, num_agents, mapping_agents, mapped_ptr)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_ipc_memory_detach, hsa_amd_ipc_memory_detach, hsa_amd_ipc_memory_detach_fn, mapped_ptr)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_signal_create, hsa_amd_signal_create, hsa_amd_signal_create_fn, initial_value, num_consumers, consumers, attributes, signal)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_ipc_signal_create, hsa_amd_ipc_signal_create, hsa_amd_ipc_signal_create_fn, signal, handle)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_ipc_signal_attach, hsa_amd_ipc_signal_attach, hsa_amd_ipc_signal_attach_fn, handle, signal)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_register_system_event_handler, hsa_amd_register_system_event_handler, hsa_amd_register_system_event_handler_fn, callback, data)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_queue_set_priority, hsa_amd_queue_set_priority, hsa_amd_queue_set_priority_fn, queue, priority)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_memory_async_copy_rect, hsa_amd_memory_async_copy_rect, hsa_amd_memory_async_copy_rect_fn, dst, dst_offset, src, src_offset, range, copy_agent, dir, num_dep_signals, dep_signals, completion_signal)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_memory_lock_to_pool, hsa_amd_memory_lock_to_pool, hsa_amd_memory_lock_to_pool_fn, host_ptr, size, agents, num_agent, pool, flags, agent_ptr)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_register_deallocation_callback, hsa_amd_register_deallocation_callback, hsa_amd_register_deallocation_callback_fn, ptr, callback, user_data)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_deregister_deallocation_callback, hsa_amd_deregister_deallocation_callback, hsa_amd_deregister_deallocation_callback_fn, ptr, callback)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_signal_value_pointer, hsa_amd_signal_value_pointer, hsa_amd_signal_value_pointer_fn, signal, value_ptr)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_svm_attributes_set, hsa_amd_svm_attributes_set, hsa_amd_svm_attributes_set_fn, ptr, size, attribute_list, attribute_count)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_svm_attributes_get, hsa_amd_svm_attributes_get, hsa_amd_svm_attributes_get_fn, ptr, size, attribute_list, attribute_count)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_svm_prefetch_async, hsa_amd_svm_prefetch_async, hsa_amd_svm_prefetch_async_fn, ptr, size, agent, num_dep_signals, dep_signals, completion_signal)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_spm_acquire, hsa_amd_spm_acquire, hsa_amd_spm_acquire_fn, preferred_agent)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_spm_release, hsa_amd_spm_release, hsa_amd_spm_release_fn, preferred_agent)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_spm_set_dest_buffer, hsa_amd_spm_set_dest_buffer, hsa_amd_spm_set_dest_buffer_fn, preferred_agent, size_in_bytes, timeout, size_copied, dest, is_data_loss)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_queue_cu_get_mask, hsa_amd_queue_cu_get_mask, hsa_amd_queue_cu_get_mask_fn, queue, num_cu_mask_count, cu_mask)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_portable_export_dmabuf, hsa_amd_portable_export_dmabuf, hsa_amd_portable_export_dmabuf_fn, ptr, size, dmabuf, offset)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_portable_close_dmabuf, hsa_amd_portable_close_dmabuf, hsa_amd_portable_close_dmabuf_fn, dmabuf)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_ImageExt, HSA_API_ID_hsa_ext_image_get_capability, hsa_ext_image_get_capability, hsa_ext_image_get_capability_fn, agent, geometry, image_format, capability_mask)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_ImageExt, HSA_API_ID_hsa_ext_image_data_get_info, hsa_ext_image_data_get_info, hsa_ext_image_data_get_info_fn, agent, image_descriptor, access_permission, image_data_info)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_ImageExt, HSA_API_ID_hsa_ext_image_create, hsa_ext_image_create, hsa_ext_image_create_fn, agent, image_descriptor, image_data, access_permission, image)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_ImageExt, HSA_API_ID_hsa_ext_image_import, hsa_ext_image_import, hsa_ext_image_import_fn, agent, src_memory, src_row_pitch, src_slice_pitch, dst_image, image_region)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_ImageExt, HSA_API_ID_hsa_ext_image_export, hsa_ext_image_export, hsa_ext_image_export_fn, agent, src_image, dst_memory, dst_row_pitch, dst_slice_pitch, image_region)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_ImageExt, HSA_API_ID_hsa_ext_image_copy, hsa_ext_image_copy, hsa_ext_image_copy_fn, agent, src_image, src_offset, dst_image, dst_offset, range)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_ImageExt, HSA_API_ID_hsa_ext_image_clear, hsa_ext_image_clear, hsa_ext_image_clear_fn, agent, image, data, image_region)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_ImageExt, HSA_API_ID_hsa_ext_image_destroy, hsa_ext_image_destroy, hsa_ext_image_destroy_fn, agent, image)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_ImageExt, HSA_API_ID_hsa_ext_sampler_create, hsa_ext_sampler_create, hsa_ext_sampler_create_fn, agent, sampler_descriptor, sampler)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_ImageExt, HSA_API_ID_hsa_ext_sampler_destroy, hsa_ext_sampler_destroy, hsa_ext_sampler_destroy_fn, agent, sampler)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_ImageExt, HSA_API_ID_hsa_ext_image_get_capability_with_layout, hsa_ext_image_get_capability_with_layout, hsa_ext_image_get_capability_with_layout_fn, agent, geometry, image_format, image_data_layout, capability_mask)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_ImageExt, HSA_API_ID_hsa_ext_image_data_get_info_with_layout, hsa_ext_image_data_get_info_with_layout, hsa_ext_image_data_get_info_with_layout_fn, agent, image_descriptor, access_permission, image_data_layout, image_data_row_pitch, image_data_slice_pitch, image_data_info)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_ImageExt, HSA_API_ID_hsa_ext_image_create_with_layout, hsa_ext_image_create_with_layout, hsa_ext_image_create_with_layout_fn, agent, image_descriptor, image_data, access_permission, image_data_layout, image_data_row_pitch, image_data_slice_pitch, image)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_queue_intercept_create, hsa_amd_queue_intercept_create, hsa_amd_queue_intercept_create_fn, agent_handle, size, type, callback, data, private_segment_size, group_segment_size, queue)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_queue_intercept_register, hsa_amd_queue_intercept_register, hsa_amd_queue_intercept_register_fn, queue, callback, user_data)
|
||||
HSA_API_INFO_DEFINITION_V(ACTIVITY_DOMAIN_HSA_API, HSA_API_TABLE_ID_AmdExt, HSA_API_ID_hsa_amd_runtime_queue_create_register, hsa_amd_runtime_queue_create_register, hsa_amd_runtime_queue_create_register_fn, callback, user_data)
|
||||
// clang-format on
|
||||
@@ -0,0 +1,124 @@
|
||||
// Copyright (c) 2018-2023 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lib/common/defines.hpp"
|
||||
#include "lib/rocprofiler/hsa/hsa-defines.hpp"
|
||||
#include "lib/rocprofiler/hsa/hsa-ostream.hpp"
|
||||
#include "lib/rocprofiler/hsa/hsa-types.h"
|
||||
#include "lib/rocprofiler/hsa/hsa-utils.hpp"
|
||||
|
||||
#include <hsa/hsa_api_trace.h>
|
||||
#include <rocprofiler/rocprofiler.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace hsa
|
||||
{
|
||||
using activity_functor_t = int (*)(rocprofiler_tracer_activity_domain_t domain,
|
||||
uint32_t operation_id,
|
||||
void* data);
|
||||
|
||||
using hsa_api_table_t = HsaApiTable;
|
||||
|
||||
struct hsa_trace_data_t
|
||||
{
|
||||
hsa_api_data_t api_data;
|
||||
uint64_t phase_enter_timestamp;
|
||||
uint64_t phase_data;
|
||||
|
||||
void (*phase_enter)(hsa_api_id_t operation_id, hsa_trace_data_t* data);
|
||||
void (*phase_exit)(hsa_api_id_t operation_id, hsa_trace_data_t* data);
|
||||
};
|
||||
|
||||
enum hsa_table_api_id_t
|
||||
{
|
||||
HSA_API_TABLE_ID_CoreApi,
|
||||
HSA_API_TABLE_ID_AmdExt,
|
||||
HSA_API_TABLE_ID_ImageExt,
|
||||
HSA_API_TABLE_ID_NUMBER,
|
||||
};
|
||||
|
||||
template <typename DataT, typename Tp>
|
||||
void
|
||||
set_data_retval(DataT&, Tp);
|
||||
|
||||
template <size_t Idx>
|
||||
struct hsa_table_lookup;
|
||||
|
||||
template <size_t Idx>
|
||||
struct hsa_api_impl
|
||||
{
|
||||
template <typename DataT, typename DataArgsT, typename... Args>
|
||||
static auto phase_enter(DataT& _data, DataArgsT&, Args... args);
|
||||
|
||||
template <typename DataT, typename... Args>
|
||||
static auto phase_exit(DataT& _data);
|
||||
|
||||
template <typename DataT, typename FuncT, typename... Args>
|
||||
static auto exec(DataT& _data, FuncT&&, Args&&... args);
|
||||
|
||||
template <typename... Args>
|
||||
static auto functor(Args&&... args);
|
||||
};
|
||||
|
||||
template <size_t Idx>
|
||||
struct hsa_api_info;
|
||||
|
||||
const char*
|
||||
hsa_api_name(uint32_t id);
|
||||
|
||||
uint32_t
|
||||
hsa_api_id_by_name(const char* name);
|
||||
|
||||
std::string
|
||||
hsa_api_data_string(uint32_t id, const hsa_trace_data_t& _data);
|
||||
|
||||
std::string
|
||||
hsa_api_named_data_string(uint32_t id, const hsa_trace_data_t& _data);
|
||||
|
||||
void
|
||||
hsa_api_iterate_args(uint32_t id,
|
||||
const hsa_trace_data_t& _data,
|
||||
int (*_func)(const char*, const char*));
|
||||
|
||||
std::vector<const char*>
|
||||
hsa_api_get_names();
|
||||
|
||||
std::vector<uint32_t>
|
||||
hsa_api_get_ids();
|
||||
|
||||
void
|
||||
hsa_api_set_callback(activity_functor_t _func);
|
||||
} // namespace hsa
|
||||
} // namespace rocprofiler
|
||||
|
||||
extern "C" {
|
||||
using on_load_t = bool (*)(HsaApiTable*, uint64_t, uint64_t, const char* const*);
|
||||
|
||||
bool
|
||||
OnLoad(HsaApiTable* table,
|
||||
uint64_t runtime_version,
|
||||
uint64_t failed_tool_count,
|
||||
const char* const* failed_tool_names) ROCPROFILER_PUBLIC_API;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,515 @@
|
||||
/* Copyright (c) 2018-2022 Advanced Micro Devices, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <hip/hip_runtime.h>
|
||||
#include <hsa/hsa.h>
|
||||
#include <hsa/hsa_ext_amd.h>
|
||||
#include <rocprofiler/rocprofiler.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rocprofiler_session_id_t session_id;
|
||||
rocprofiler_buffer_id_t buffer_id;
|
||||
} session_buffer_id_t;
|
||||
|
||||
typedef session_buffer_id_t roctracer_pool_t;
|
||||
|
||||
/* Correlation id */
|
||||
typedef uint64_t activity_correlation_id_t;
|
||||
|
||||
typedef uint32_t activity_kind_t;
|
||||
typedef uint32_t activity_op_t;
|
||||
|
||||
typedef uint64_t roctracer_timestamp_t;
|
||||
|
||||
typedef rocprofiler_tracer_activity_domain_t roctracer_domain_t;
|
||||
typedef rocprofiler_tracer_activity_domain_t activity_domain_t;
|
||||
|
||||
// Prof_Protocol
|
||||
/* Activity record type */
|
||||
typedef struct activity_record_s
|
||||
{
|
||||
uint32_t domain; /* activity domain id */
|
||||
activity_kind_t kind; /* activity kind */
|
||||
activity_op_t op; /* activity op */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
activity_correlation_id_t correlation_id; /* activity ID */
|
||||
roctracer_timestamp_t begin_ns; /* host begin timestamp */
|
||||
roctracer_timestamp_t end_ns; /* host end timestamp */
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint32_t se; /* sampled SE */
|
||||
uint64_t cycle; /* sample cycle */
|
||||
uint64_t pc; /* sample PC */
|
||||
} pc_sample;
|
||||
};
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int device_id; /* device id */
|
||||
uint64_t queue_id; /* queue id */
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint32_t process_id; /* device id */
|
||||
uint32_t thread_id; /* thread id */
|
||||
};
|
||||
struct
|
||||
{
|
||||
activity_correlation_id_t external_id; /* external correlation id */
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
size_t bytes; /* data size bytes */
|
||||
const char* kernel_name; /* kernel name */
|
||||
const char* mark_message;
|
||||
};
|
||||
} activity_record_t;
|
||||
|
||||
typedef activity_record_t roctracer_record_t;
|
||||
|
||||
/* Activity sync callback type */
|
||||
typedef void (*activity_sync_callback_t)(activity_domain_t cid,
|
||||
activity_record_t* record,
|
||||
const void* data,
|
||||
void* arg);
|
||||
/* Activity async callback type */
|
||||
typedef void (*activity_async_callback_t)(activity_domain_t op, void* record, void* arg);
|
||||
|
||||
/* API callback type */
|
||||
typedef void (*activity_rtapi_callback_t)(activity_domain_t domain,
|
||||
uint32_t cid,
|
||||
const void* data,
|
||||
void* arg);
|
||||
typedef activity_rtapi_callback_t roctracer_rtapi_callback_t;
|
||||
|
||||
typedef roctracer_timestamp_t (*roctracer_get_timestamp_t)();
|
||||
typedef rocprofiler_timestamp_t (*rocprofiler_get_timestamp_t)();
|
||||
|
||||
typedef uint32_t activity_kind_t;
|
||||
typedef uint32_t activity_op_t;
|
||||
|
||||
/* API callback phase */
|
||||
typedef enum
|
||||
{
|
||||
ACTIVITY_API_PHASE_ENTER = 0,
|
||||
ACTIVITY_API_PHASE_EXIT = 1
|
||||
} activity_api_phase_t;
|
||||
|
||||
const char*
|
||||
roctracer_op_string(uint32_t domain, uint32_t op);
|
||||
|
||||
/* Trace record types */
|
||||
|
||||
/**
|
||||
* Memory pool allocator callback.
|
||||
*
|
||||
* If \p *ptr is NULL, then allocate memory of \p size bytes and save address
|
||||
* in \p *ptr.
|
||||
*
|
||||
* If \p *ptr is non-NULL and size is non-0, then reallocate the memory at \p
|
||||
* *ptr with size \p size and save the address in \p *ptr. The memory will have
|
||||
* been allocated by the same callback.
|
||||
*
|
||||
* If \p *ptr is non-NULL and size is 0, then deallocate the memory at \p *ptr.
|
||||
* The memory will have been allocated by the same callback.
|
||||
*
|
||||
* \p size is the size of the memory allocation or reallocation, or 0 if
|
||||
* deallocating.
|
||||
*
|
||||
* \p arg Argument provided
|
||||
*/
|
||||
typedef void (*roctracer_allocator_t)(char** ptr, size_t size, void* arg);
|
||||
|
||||
/**
|
||||
* Memory pool buffer callback.
|
||||
*
|
||||
* The callback that will be invoked when a memory pool buffer becomes full or
|
||||
* is flushed.
|
||||
*
|
||||
* \p begin pointer to first entry entry in the buffer.
|
||||
*
|
||||
* \p end pointer to one past the end entry in the buffer.
|
||||
*
|
||||
* \p arg the argument specified when the callback was defined.
|
||||
*/
|
||||
typedef void (*roctracer_buffer_callback_t)(const char* begin, const char* end, void* arg);
|
||||
|
||||
/**
|
||||
* Memory pool properties.
|
||||
*
|
||||
* Defines the properties when a tracer memory pool is created.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
* ROC Tracer mode.
|
||||
*/
|
||||
uint32_t mode;
|
||||
|
||||
/**
|
||||
* Size of buffer in bytes.
|
||||
*/
|
||||
size_t buffer_size;
|
||||
|
||||
/**
|
||||
* The allocator function to use to allocate and deallocate the buffer. If
|
||||
* NULL then \p malloc, \p realloc, and \p free are used.
|
||||
*/
|
||||
roctracer_allocator_t alloc_fun;
|
||||
|
||||
/**
|
||||
* The argument to pass when invoking the \p alloc_fun allocator.
|
||||
*/
|
||||
void* alloc_arg;
|
||||
|
||||
/**
|
||||
* The function to call when a buffer becomes full or is flushed.
|
||||
*/
|
||||
roctracer_buffer_callback_t buffer_callback_fun;
|
||||
|
||||
/**
|
||||
* The argument to pass when invoking the \p buffer_callback_fun callback.
|
||||
*/
|
||||
void* buffer_callback_arg;
|
||||
} roctracer_properties_t;
|
||||
|
||||
/**
|
||||
* ROC Tracer API status codes.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
/**
|
||||
* The function has executed successfully.
|
||||
*/
|
||||
ROCTRACER_STATUS_SUCCESS = 0,
|
||||
/**
|
||||
* A generic error has occurred.
|
||||
*/
|
||||
ROCTRACER_STATUS_ERROR = -1,
|
||||
/**
|
||||
* The domain ID is invalid.
|
||||
*/
|
||||
ROCTRACER_STATUS_ERROR_INVALID_DOMAIN_ID = -2,
|
||||
/**
|
||||
* An invalid argument was given to the function.
|
||||
*/
|
||||
ROCTRACER_STATUS_ERROR_INVALID_ARGUMENT = -3,
|
||||
/**
|
||||
* No default pool is defined.
|
||||
*/
|
||||
ROCTRACER_STATUS_ERROR_DEFAULT_POOL_UNDEFINED = -4,
|
||||
/**
|
||||
* The default pool is already defined.
|
||||
*/
|
||||
ROCTRACER_STATUS_ERROR_DEFAULT_POOL_ALREADY_DEFINED = -5,
|
||||
/**
|
||||
* Memory allocation error.
|
||||
*/
|
||||
ROCTRACER_STATUS_ERROR_MEMORY_ALLOCATION = -6,
|
||||
/**
|
||||
* External correlation ID pop mismatch.
|
||||
*/
|
||||
ROCTRACER_STATUS_ERROR_MISMATCHED_EXTERNAL_CORRELATION_ID = -7,
|
||||
/**
|
||||
* The operation is not currently implemented. This error may be reported by
|
||||
* any function. Check the \ref known_limitations section to determine the
|
||||
* status of the library implementation of the interface.
|
||||
*/
|
||||
ROCTRACER_STATUS_ERROR_NOT_IMPLEMENTED = -8,
|
||||
/**
|
||||
* Deprecated error code.
|
||||
*/
|
||||
ROCTRACER_STATUS_UNINIT = 2,
|
||||
/**
|
||||
* Deprecated error code.
|
||||
*/
|
||||
ROCTRACER_STATUS_BREAK = 3,
|
||||
/**
|
||||
* Deprecated error code.
|
||||
*/
|
||||
ROCTRACER_STATUS_BAD_DOMAIN = ROCTRACER_STATUS_ERROR_INVALID_DOMAIN_ID,
|
||||
/**
|
||||
* Deprecated error code.
|
||||
*/
|
||||
ROCTRACER_STATUS_BAD_PARAMETER = ROCTRACER_STATUS_ERROR_INVALID_ARGUMENT,
|
||||
/**
|
||||
* Deprecated error code.
|
||||
*/
|
||||
ROCTRACER_STATUS_HIP_API_ERR = 6,
|
||||
/**
|
||||
* Deprecated error code.
|
||||
*/
|
||||
ROCTRACER_STATUS_HIP_OPS_ERR = 7,
|
||||
/**
|
||||
* Deprecated error code.
|
||||
*/
|
||||
ROCTRACER_STATUS_HCC_OPS_ERR = ROCTRACER_STATUS_HIP_OPS_ERR,
|
||||
/**
|
||||
* Deprecated error code.
|
||||
*/
|
||||
ROCTRACER_STATUS_HSA_ERR = 7,
|
||||
/**
|
||||
* Deprecated error code.
|
||||
*/
|
||||
ROCTRACER_STATUS_ROCTX_ERR = 8,
|
||||
} roctracer_status_t;
|
||||
|
||||
/**
|
||||
* Query textual name of an operation of a domain.
|
||||
* @param[in] domain Domain being queried.
|
||||
* @param[in] op Operation within \p domain.
|
||||
* @param[in] kind \todo Define kind.
|
||||
* @return Returns the NUL terminated string for the operation name, or NULL if
|
||||
* the domain or operation are invalid. The string is owned by the ROC Tracer
|
||||
* library.
|
||||
*/
|
||||
const char*
|
||||
roctracer_op_string(uint32_t domain, uint32_t op, uint32_t kind);
|
||||
|
||||
/**
|
||||
* Query the operation code given a domain and the name of an operation.
|
||||
* @param[in] domain The domain being queried.
|
||||
* @param[in] str The NUL terminated name of the operation name being queried.
|
||||
* @param[out] op The operation code.
|
||||
* @param[out] kind If not NULL then the operation kind code.
|
||||
*/
|
||||
void
|
||||
roctracer_op_code(uint32_t domain, const char* str, uint32_t* op, uint32_t* kind);
|
||||
|
||||
/**
|
||||
* Set the properties of a domain.
|
||||
* @param[in] domain The domain.
|
||||
* @param[in] properties The properties. Each domain defines its own type for
|
||||
* the properties. Some domains require the properties to be set before they
|
||||
* can be enabled.
|
||||
*/
|
||||
void
|
||||
roctracer_set_properties(roctracer_domain_t domain, void* properties);
|
||||
|
||||
/**
|
||||
* Enable runtime API callback for a specific operation of a domain.
|
||||
* @param domain The domain.
|
||||
* @param op The operation ID in \p domain.
|
||||
* @param callback The callback to invoke each time the operation is performed
|
||||
* on entry and exit.
|
||||
* @param pool Value to pass as last argument of \p callback.
|
||||
*/
|
||||
void
|
||||
roctracer_enable_op_callback(roctracer_domain_t domain,
|
||||
uint32_t op,
|
||||
roctracer_rtapi_callback_t callback);
|
||||
|
||||
/**
|
||||
* Enable runtime API callback for all operations of a domain.
|
||||
* @param domain The domain
|
||||
* @param callback The callback to invoke each time the operation is performed
|
||||
* on entry and exit.
|
||||
* @param arg Value to pass as last argument of \p callback.
|
||||
*/
|
||||
void
|
||||
roctracer_enable_domain_callback(roctracer_domain_t domain,
|
||||
roctracer_rtapi_callback_t callback,
|
||||
void* user_data = nullptr);
|
||||
|
||||
/**
|
||||
* Disable runtime API callback for a specific operation of a domain.
|
||||
* @param domain The domain
|
||||
* @param op The operation in \p domain.
|
||||
*/
|
||||
void
|
||||
roctracer_disable_op_callback(roctracer_domain_t domain, uint32_t op);
|
||||
|
||||
/**
|
||||
* Disable runtime API callback for all operations of a domain.
|
||||
* @param domain The domain
|
||||
*/
|
||||
void
|
||||
roctracer_disable_domain_callback(roctracer_domain_t domain);
|
||||
|
||||
/**
|
||||
* Enable activity record logging for a specified operation of a domain using
|
||||
* the default memory pool.
|
||||
* @param[in] domain The domain.
|
||||
* @param[in] op The activity operation ID in \p domain.
|
||||
*/
|
||||
void
|
||||
roctracer_enable_op_activity(roctracer_domain_t domain, uint32_t op, roctracer_pool_t pool);
|
||||
|
||||
/**
|
||||
* Enable activity record logging for all operations of a domain using the
|
||||
* default memory pool.
|
||||
* @param[in] domain The domain.
|
||||
*/
|
||||
void
|
||||
roctracer_enable_domain_activity(roctracer_domain_t domain, roctracer_pool_t pool);
|
||||
|
||||
/**
|
||||
* Disable activity record logging for a specified operation of a domain.
|
||||
* @param[in] domain The domain.
|
||||
* @param[in] op The activity operation ID in \p domain.
|
||||
*/
|
||||
void
|
||||
roctracer_disable_op_activity(roctracer_domain_t domain, uint32_t op);
|
||||
|
||||
/**
|
||||
* Disable activity record logging for all operations of a domain.
|
||||
* @param[in] domain The domain.
|
||||
*/
|
||||
void
|
||||
roctracer_disable_domain_activity(roctracer_domain_t domain);
|
||||
|
||||
// HIP Support
|
||||
typedef enum
|
||||
{
|
||||
HIP_OP_ID_DISPATCH = 0,
|
||||
HIP_OP_ID_COPY = 1,
|
||||
HIP_OP_ID_BARRIER = 2,
|
||||
HIP_OP_ID_NUMBER = 3
|
||||
} hip_op_id_t;
|
||||
|
||||
// HSA Support
|
||||
// HSA OP ID enumeration
|
||||
enum hsa_op_id_t
|
||||
{
|
||||
HSA_OP_ID_DISPATCH = 0,
|
||||
HSA_OP_ID_COPY = 1,
|
||||
HSA_OP_ID_BARRIER = 2,
|
||||
HSA_OP_ID_RESERVED1 = 3,
|
||||
HSA_OP_ID_NUMBER
|
||||
};
|
||||
|
||||
// HSA EVT ID enumeration
|
||||
enum hsa_evt_id_t
|
||||
{
|
||||
HSA_EVT_ID_ALLOCATE = 0, // Memory allocate callback
|
||||
HSA_EVT_ID_DEVICE = 1, // Device assign callback
|
||||
HSA_EVT_ID_MEMCOPY = 2, // Memcopy callback
|
||||
HSA_EVT_ID_SUBMIT = 3, // Packet submission callback
|
||||
HSA_EVT_ID_KSYMBOL = 4, // Loading/unloading of kernel symbol
|
||||
HSA_EVT_ID_CODEOBJ = 5, // Loading/unloading of device code object
|
||||
HSA_EVT_ID_NUMBER
|
||||
};
|
||||
|
||||
struct hsa_ops_properties_t
|
||||
{
|
||||
void* reserved1[4];
|
||||
};
|
||||
|
||||
// ROCTx Support
|
||||
typedef uint64_t roctx_range_id_t;
|
||||
|
||||
/**
|
||||
* ROCTX API ID enumeration
|
||||
*/
|
||||
enum roctx_api_id_t
|
||||
{
|
||||
ROCTX_API_ID_roctxMarkA = 0,
|
||||
ROCTX_API_ID_roctxRangePushA = 1,
|
||||
ROCTX_API_ID_roctxRangePop = 2,
|
||||
ROCTX_API_ID_roctxRangeStartA = 3,
|
||||
ROCTX_API_ID_roctxRangeStop = 4,
|
||||
ROCTX_API_ID_NUMBER,
|
||||
};
|
||||
|
||||
/**
|
||||
* ROCTX callbacks data type
|
||||
*/
|
||||
typedef struct roctx_api_data_s
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
const char* message;
|
||||
roctx_range_id_t id;
|
||||
};
|
||||
struct
|
||||
{
|
||||
const char* message;
|
||||
} roctxMarkA;
|
||||
struct
|
||||
{
|
||||
const char* message;
|
||||
} roctxRangePushA;
|
||||
struct
|
||||
{
|
||||
const char* message;
|
||||
} roctxRangePop;
|
||||
struct
|
||||
{
|
||||
const char* message;
|
||||
roctx_range_id_t id;
|
||||
} roctxRangeStartA;
|
||||
struct
|
||||
{
|
||||
const char* message;
|
||||
roctx_range_id_t id;
|
||||
} roctxRangeStop;
|
||||
} args;
|
||||
} roctx_api_data_t;
|
||||
|
||||
// External Support
|
||||
/* Extension opcodes */
|
||||
typedef enum
|
||||
{
|
||||
ACTIVITY_EXT_OP_MARK = 0,
|
||||
ACTIVITY_EXT_OP_EXTERN_ID = 1
|
||||
} activity_ext_op_t;
|
||||
|
||||
typedef void (*roctracer_start_cb_t)();
|
||||
typedef void (*roctracer_stop_cb_t)();
|
||||
typedef struct
|
||||
{
|
||||
roctracer_start_cb_t start_cb;
|
||||
roctracer_stop_cb_t stop_cb;
|
||||
} roctracer_ext_properties_t;
|
||||
|
||||
// Tracing start
|
||||
void
|
||||
roctracer_start();
|
||||
|
||||
// Tracing stop
|
||||
void
|
||||
roctracer_stop();
|
||||
|
||||
// Notifies that the calling thread is entering an external region.
|
||||
// Push an external correlation id for the calling thread.
|
||||
void
|
||||
roctracer_activity_push_external_correlation_id(activity_correlation_id_t id);
|
||||
|
||||
// Notifies that the calling thread is leaving an external region.
|
||||
// Pop an external correlation id for the calling thread.
|
||||
// 'lastId' returns the last external correlation if not NULL
|
||||
void
|
||||
roctracer_activity_pop_external_correlation_id(activity_correlation_id_t* last_id);
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user