파일
rocm-systems/projects/rocprofiler-sdk/cmake/rocprofiler_utilities.cmake
T
Benjamin Welton 1517a398bf [rocprofiler-sdk] Buffer finalization fixes and HSA ABI 0x09 support (#2318)
* [rocprofiler-sdk] Fix buffer flush ordering and sanitizer CI improvements

Buffer Pool Design
------------------
Replace the fixed array-based double buffer with a dynamic pool design to
fix race conditions that caused "internal correlation id was retired
prematurely" errors.

The original design had a race where flush callbacks could be delivered
out-of-order: when buffer 0 fills and begins flushing, writes go to
buffer 1. If buffer 1 fills before buffer 0's flush completes, the
buffer index wraps back to 0 (which may still be flushing). Independent
flush tasks submitted to the thread pool can complete out of order.

The new pool design:
- Uses a std::deque of buffer instances that grows as needed
- Allocates buffers from the pool when the current buffer needs to flush
- Serializes flushes with a mutex to ensure FIFO callback ordering
- Returns buffers to the pool after flush completion
- Eliminates the race between buffer selection and write operations

New Unit Tests
--------------
- buffer_correlation_ordering.cpp: Tests that API records are always
  delivered before their corresponding retirement records
- buffer_ordering_stress.cpp: Stress tests buffer flush ordering under
  high contention with multiple threads rapidly filling buffers

HSA Tool Hooks
--------------
Added hsa_tool_hooks.cpp/hpp to register an HSA OnUnload callback that
waits for pending flush tasks before tool finalization, preventing
"retired prematurely" errors during HSA shutdown.

Sanitizer Improvements
----------------------
- LSAN: Set fast_unwind_on_malloc=1 to prevent deadlock in libgcc unwinder
- LSAN: Added suppressions for external tools (liblzma, liblsan, seq, strdup)
- TSAN: Added suppression for false positive on C++11 thread-safe static
  initialization in create_write_functor
- ASAN/UBSAN: Added patterns for known issues in HSA runtime, HIP, perfetto
- Disabled attachment tests for sanitizers due to library preloading issues

Other Fixes
-----------
- Thread-trace agent test: Use heap-allocated callback state
- Correlation ID: Refactored reference counting and finalization ordering

* [rocprofiler-sdk] Revert buffer pool design changes

Revert buffer.cpp and buffer.hpp to the original double-buffer
design from develop branch. The pool-based redesign introduced
concerns about:
- Signal safety (mutex vs atomic_flag)
- API changes (flush() return type)
- Complexity of the new design

This revert removes:
- Dynamic buffer pool with std::deque
- std::mutex/condition_variable synchronization
- buffer_correlation_ordering.cpp test
- buffer_ordering_stress.cpp test

The underlying buffer flush ordering issue will need to be
addressed with a different approach that preserves the original
API and synchronization characteristics.

* [rocprofiler-sdk] Consistent fini_status checks to prevent correlation ID creation during finalization

- Revert TOCTOU CAS loop change in sub_ref_count() - not needed with consistent checks
- Add fini_status check in correlation_tracing_service::construct() with ROCP_CI_LOG warning
- Add nullptr checks at all construct() call sites (queue.cpp, async_copy.cpp, memory_allocation.cpp)
- Change all 'get_fini_status() > 0' to '!= 0' for consistent behavior:
  - hsa/queue.cpp (lines 105, 210)
  - hsa/async_copy.cpp (line 344)
  - hsa/hsa_barrier.cpp (line 43)
  - buffer.cpp (lines 107, 138, 185)

This ensures no correlation IDs are created once finalization starts (fini_status != 0),
preventing races between finalization and ongoing tracing operations.

* [rocprofiler-sdk] Replace arrival-order checks with timestamp-based temporal validation

Buffer records are not guaranteed to arrive in any specific order. Tests and
samples should use timestamps for temporal ordering validation instead.

Changes:
- samples/external_correlation_id_request: Replace 'retired prematurely' arrival
  order check with timestamp-based validation that retirement timestamp >=
  max(end_timestamps) for records with the same correlation ID
- tests/external_correlation.cpp: Remove EXPECT_GT(corr_id, last_corr_id) check
- tests/registration.cpp: Remove EXPECT_GT(corr_id, last_corr_id) check
- tests/roctx.cpp: Remove EXPECT_GT(corr_id, last_corr_id) check

Correlation IDs are not guaranteed to be monotonically increasing when records
are sorted by timestamp. Temporal ordering should be validated using the
timestamp fields in each record.

* [rocprofiler-sdk] Revert external/CMakeLists.txt SYSTEM keyword removal

Restore the SYSTEM keyword to target_include_directories for
rocprofiler-sdk-fmt to match develop branch.

* [rccl] Remove orphaned rocSHMEM gitlink

Remove orphaned submodule reference that was introduced during a merge
but never had a corresponding .gitmodules entry, causing CI failures
with "fatal: no submodule mapping found in .gitmodules".

* [rocprofiler-sdk] Add HSA ABI version 0x09 support

Add ABI checks for HSA_AMD_EXT_API_TABLE_STEP_VERSION 0x09 which
introduces hsa_amd_counted_queue_acquire and hsa_amd_counted_queue_release
functions (added in rocr-runtime SWDEV-561708).

* [rocprofiler-sdk] Handle finalized status gracefully in buffer flush operations

This commit consolidates fixes for handling the finalization status during
buffer flush operations across the SDK.

Changes:
- Tool and samples: Handle ROCPROFILER_STATUS_ERROR_FINALIZED gracefully
  when flushing buffers, as this indicates buffers were already flushed
  during finalization (not an error condition)
- HSA handlers (queue.cpp, async_copy.cpp, hsa_barrier.cpp): Use > 0 check
  for fini_status to allow operations during finalization process
- buffer.cpp: Revert fini_status checks to use > 0 for consistency
- correlation_id.cpp: Add fini_status > 0 check with ROCP_TRACE logging
  to prevent correlation ID creation after finalization starts

Files modified:
- source/lib/rocprofiler-sdk-tool/tool.cpp
- tests/tools/json-tool.cpp
- source/lib/rocprofiler-sdk/tests/registration.cpp
- source/lib/rocprofiler-sdk/tests/roctx.cpp
- samples/api_buffered_tracing/client.cpp
- samples/counter_collection/buffered_client.cpp
- samples/counter_collection/device_counting_async_client.cpp
- samples/external_correlation_id_request/client.cpp
- samples/pc_sampling/client.cpp
- source/lib/rocprofiler-sdk/buffer.cpp
- source/lib/rocprofiler-sdk/context/correlation_id.cpp
- source/lib/rocprofiler-sdk/hsa/queue.cpp
- source/lib/rocprofiler-sdk/hsa/async_copy.cpp
- source/lib/rocprofiler-sdk/hsa/hsa_barrier.cpp

* [rocprofiler-sdk] Remove hsa_tool_hooks and simplify buffer flush handling

Remove the hsa_tool_hooks infrastructure and simplify buffer flush calls
in samples and tools. The ERROR_FINALIZED handling was overly complex
and the hsa_tool_hooks OnUnload synchronization is no longer needed.

Changes:
- Remove hsa_tool_hooks.cpp/hpp and related registration.cpp code
- Simplify buffer flush calls in samples to use direct ROCPROFILER_CALL
- Simplify buffer flush in tool.cpp and json-tool.cpp
- Remove ERROR_FINALIZED special handling from test files

Co-Authored-By: Claude <noreply@anthropic.com>

* [rocprofiler-sdk] Fix output_stream move semantics to null source pointers

The default move constructor and move assignment operator for
output_stream did not null out the source's pointers after the move.
This caused double-close when the moved-from temporary was destroyed,
leading to use-after-free crashes (SIGSEGV in std::ostream::sentry).

Co-Authored-By: Claude <noreply@anthropic.com>

* [rocprofiler-sdk] Improve Perfetto trace writer and sanitizer configuration

- generatePerfetto.cpp: Move output_stream into shared_state to prevent
  use-after-free race conditions during Perfetto callback execution
- run-ci.py: Simplify and consolidate sanitizer environment variable
  configuration for better maintainability

Co-Authored-By: Claude <noreply@anthropic.com>

* [rocprofiler-sdk] Revert run-ci.py changes that broke sanitizer suppressions

The previous changes removed MEMCHECK_SANITIZER_OPTIONS which is required
for CTest to properly pass suppression files to the sanitizers during
memcheck runs.

Co-Authored-By: Claude <noreply@anthropic.com>

* Revert "[rccl] Remove orphaned rocSHMEM gitlink"

This reverts commit 1ad21003941355658fff8114fa27768f11a948f7.

* [rocprofiler-sdk] Revert registration.cpp changes

Revert changes to registration.cpp to match develop branch.

Co-Authored-By: Claude <noreply@anthropic.com>

* [rocprofiler-sdk] Remove suppression file content printing from run-ci.py

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix output_stream move ctor/assignment operator

* Fix erroneous revert of registration.cpp

* Fix handling of fini status in correlation ID construction

* [rocprofiler-sdk] Fix OMPT segfault during finalization

Add nullptr checks in OMPT tracing code to handle the case where
correlation_tracing_service::construct() returns nullptr during
finalization. This fixes segfaults in openmp-target-sample and
tests.integration.execute.openmp-tools.

The correlation ID construction now returns nullptr when fini_status > 0,
but the OMPT callbacks were not checking for this, causing crashes when
dereferencing the null pointer during OpenMP runtime shutdown.

Changes:
- event_common(): Return nullptr early if correlation ID is null
- event(): Check for nullptr before calling sub_ref_count()
- ompt_task_create_callback(): Return early if correlation ID is null
- ompt_task_schedule_callback(): Return early if correlation ID is null

* [rocprofiler-sdk] Fix HSA API tracing segfault during finalization

Add nullptr check in hsa_api_impl::functor after correlation ID
construction. During finalization, correlation_service::construct()
returns nullptr, and without this check the code would dereference
the null pointer when accessing corr_id->internal.

This fixes the SEGV at address 0x000000000008 (null + 8 byte offset)
that occurs when HSA async event threads call hsa_signal_destroy
during runtime shutdown after finalization has started.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jonathan R. Madsen <jonathanrmadsen@gmail.com>
2026-01-27 13:27:54 -05:00

1210 라인
43 KiB
CMake

# include guard
include_guard(GLOBAL)
# MacroUtilities - useful macros and functions for generic tasks
#
cmake_policy(PUSH)
cmake_policy(SET CMP0054 NEW)
cmake_policy(SET CMP0057 NEW)
include(CMakeDependentOption)
include(CMakeParseArguments)
# -----------------------------------------------------------------------
# message which handles ROCPROFILER_QUIET_CONFIG settings
# -----------------------------------------------------------------------
#
function(ROCPROFILER_MESSAGE TYPE)
if(NOT ROCPROFILER_QUIET_CONFIG)
message(${TYPE} "[rocprofiler] ${ARGN}")
endif()
endfunction()
# -----------------------------------------------------------------------
# Save a set of variables with the given prefix
# -----------------------------------------------------------------------
macro(ROCPROFILER_SAVE_VARIABLES _PREFIX)
# parse args
cmake_parse_arguments(
SAVE
"" # options
"CONDITION" # single value args
"VARIABLES" # multiple value args
${ARGN})
if(DEFINED SAVE_CONDITION AND NOT "${SAVE_CONDITION}" STREQUAL "")
if(${SAVE_CONDITION})
foreach(_VAR ${SAVE_VARIABLES})
if(DEFINED ${_VAR})
set(${_PREFIX}_${_VAR} "${${_VAR}}")
else()
message(AUTHOR_WARNING "${_VAR} is not defined")
endif()
endforeach()
endif()
else()
foreach(_VAR ${SAVE_VARIABLES})
if(DEFINED ${_VAR})
set(${_PREFIX}_${_VAR} "${${_VAR}}")
else()
message(AUTHOR_WARNING "${_VAR} is not defined")
endif()
endforeach()
endif()
unset(SAVE_CONDITION)
unset(SAVE_VARIABLES)
endmacro()
# -----------------------------------------------------------------------
# Restore a set of variables with the given prefix
# -----------------------------------------------------------------------
macro(ROCPROFILER_RESTORE_VARIABLES _PREFIX)
# parse args
cmake_parse_arguments(
RESTORE
"" # options
"CONDITION" # single value args
"VARIABLES" # multiple value args
${ARGN})
if(DEFINED RESTORE_CONDITION AND NOT "${RESTORE_CONDITION}" STREQUAL "")
if(${RESTORE_CONDITION})
foreach(_VAR ${RESTORE_VARIABLES})
if(DEFINED ${_PREFIX}_${_VAR})
set(${_VAR} ${${_PREFIX}_${_VAR}})
unset(${_PREFIX}_${_VAR})
else()
message(AUTHOR_WARNING "${_PREFIX}_${_VAR} is not defined")
endif()
endforeach()
endif()
else()
foreach(_VAR ${RESTORE_VARIABLES})
if(DEFINED ${_PREFIX}_${_VAR})
set(${_VAR} ${${_PREFIX}_${_VAR}})
unset(${_PREFIX}_${_VAR})
else()
message(AUTHOR_WARNING "${_PREFIX}_${_VAR} is not defined")
endif()
endforeach()
endif()
unset(RESTORE_CONDITION)
unset(RESTORE_VARIABLES)
endmacro()
# -----------------------------------------------------------------------
# function - rocprofiler_capitalize - make a string capitalized (first letter is capital)
# usage: capitalize("SHARED" CShared) message(STATUS "-- CShared is \"${CShared}\"") $ --
# CShared is "Shared"
function(ROCPROFILER_CAPITALIZE str var)
# make string lower
string(TOLOWER "${str}" str)
string(SUBSTRING "${str}" 0 1 _first)
string(TOUPPER "${_first}" _first)
string(SUBSTRING "${str}" 1 -1 _remainder)
string(CONCAT str "${_first}" "${_remainder}")
set(${var}
"${str}"
PARENT_SCOPE)
endfunction()
# ------------------------------------------------------------------------------#
# function rocprofiler_strip_target(<TARGET> [FORCE])
#
# Creates a post-build command which strips a binary. FORCE flag will override
#
function(ROCPROFILER_STRIP_TARGET)
cmake_parse_arguments(STRIP "FORCE" "" "ARGS" ${ARGN})
list(LENGTH STRIP_UNPARSED_ARGUMENTS NUM_UNPARSED)
if(NUM_UNPARSED EQUAL 1)
set(_TARGET "${STRIP_UNPARSED_ARGUMENTS}")
else()
rocprofiler_message(
FATAL_ERROR "rocprofiler_strip_target cannot deduce target from \"${ARGN}\"")
endif()
if(NOT TARGET "${_TARGET}")
rocprofiler_message(
FATAL_ERROR
"rocprofiler_strip_target not provided valid target: \"${_TARGET}\"")
endif()
if(CMAKE_STRIP AND (STRIP_FORCE OR ROCPROFILER_STRIP_LIBRARIES))
add_custom_command(
TARGET ${_TARGET}
POST_BUILD
COMMAND ${CMAKE_STRIP} ${STRIP_ARGS} $<TARGET_FILE:${_TARGET}>
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Stripping ${_TARGET}...")
endif()
endfunction()
# ------------------------------------------------------------------------------#
# function add_rocprofiler_test_target()
#
# Creates a target which runs ctest but depends on all the tests being built.
#
function(ADD_ROCPROFILER_TEST_TARGET)
if(NOT TARGET rocprofiler-test)
add_custom_target(
rocprofiler-test
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR} --target test
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
COMMENT "Running tests...")
endif()
endfunction()
# ----------------------------------------------------------------------------------------#
# macro rocprofiler_checkout_git_submodule()
#
# Run "git submodule update" if a file in a submodule does not exist
#
# ARGS: RECURSIVE (option) -- add "--recursive" flag RELATIVE_PATH (one value) --
# typically the relative path to submodule from PROJECT_SOURCE_DIR WORKING_DIRECTORY (one
# value) -- (default: PROJECT_SOURCE_DIR) TEST_FILE (one value) -- file to check for
# (default: CMakeLists.txt) ADDITIONAL_CMDS (many value) -- any addition commands to pass
#
function(ROCPROFILER_CHECKOUT_GIT_SUBMODULE)
# parse args
cmake_parse_arguments(
CHECKOUT "RECURSIVE"
"RELATIVE_PATH;WORKING_DIRECTORY;TEST_FILE;REPO_URL;REPO_BRANCH"
"ADDITIONAL_CMDS" ${ARGN})
if(NOT CHECKOUT_WORKING_DIRECTORY)
set(CHECKOUT_WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
endif()
if(NOT CHECKOUT_TEST_FILE)
set(CHECKOUT_TEST_FILE "CMakeLists.txt")
endif()
find_package(Git)
set(_DIR "${CHECKOUT_WORKING_DIRECTORY}/${CHECKOUT_RELATIVE_PATH}")
# ensure the (possibly empty) directory exists
if(NOT EXISTS "${_DIR}")
if(NOT CHECKOUT_REPO_URL)
message(FATAL_ERROR "submodule directory does not exist")
endif()
endif()
# if this file exists --> project has been checked out if not exists --> not been
# checked out
set(_TEST_FILE "${_DIR}/${CHECKOUT_TEST_FILE}")
# assuming a .gitmodules file exists
set(_SUBMODULE "${PROJECT_SOURCE_DIR}/.gitmodules")
set(_TEST_FILE_EXISTS OFF)
if(EXISTS "${_TEST_FILE}" AND NOT IS_DIRECTORY "${_TEST_FILE}")
set(_TEST_FILE_EXISTS ON)
endif()
if(_TEST_FILE_EXISTS)
return()
endif()
find_package(Git REQUIRED)
set(_SUBMODULE_EXISTS OFF)
if(EXISTS "${_SUBMODULE}" AND NOT IS_DIRECTORY "${_SUBMODULE}")
set(_SUBMODULE_EXISTS ON)
endif()
set(_HAS_REPO_URL OFF)
if(NOT "${CHECKOUT_REPO_URL}" STREQUAL "")
set(_HAS_REPO_URL ON)
endif()
# if the module has not been checked out
if(NOT _TEST_FILE_EXISTS AND _SUBMODULE_EXISTS)
# perform the checkout
execute_process(
COMMAND ${GIT_EXECUTABLE} submodule update --init ${_RECURSE}
${CHECKOUT_ADDITIONAL_CMDS} ${CHECKOUT_RELATIVE_PATH}
WORKING_DIRECTORY ${CHECKOUT_WORKING_DIRECTORY}
RESULT_VARIABLE RET)
# check the return code
if(RET GREATER 0)
set(_CMD "${GIT_EXECUTABLE} submodule update --init ${_RECURSE}
${CHECKOUT_ADDITIONAL_CMDS} ${CHECKOUT_RELATIVE_PATH}")
message(STATUS "function(rocprofiler_checkout_git_submodule) failed.")
message(FATAL_ERROR "Command: \"${_CMD}\"")
else()
set(_TEST_FILE_EXISTS ON)
endif()
endif()
if(NOT _TEST_FILE_EXISTS AND _HAS_REPO_URL)
message(
STATUS
"Cloning '${CHECKOUT_REPO_URL}' into ${CHECKOUT_WORKING_DIRECTORY}/${CHECKOUT_RELATIVE_PATH}..."
)
# remove the existing directory
if(EXISTS "${_DIR}")
execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory ${_DIR})
endif()
# perform the checkout
execute_process(
COMMAND ${GIT_EXECUTABLE} clone ${CHECKOUT_ADDITIONAL_CMDS}
${CHECKOUT_REPO_URL} ${CHECKOUT_RELATIVE_PATH}
WORKING_DIRECTORY ${CHECKOUT_WORKING_DIRECTORY}
RESULT_VARIABLE RET_CLONE)
if(NOT RET_CLONE EQUAL 0)
message(
SEND_ERROR
"Failed to clone ${CHECKOUT_REPO_URL} into ${CHECKOUT_WORKING_DIRECTORY}/${CHECKOUT_RELATIVE_PATH}"
)
return()
endif()
if(CHECKOUT_REPO_BRANCH)
execute_process(
COMMAND ${GIT_EXECUTABLE} checkout ${CHECKOUT_REPO_BRANCH}
WORKING_DIRECTORY ${CHECKOUT_WORKING_DIRECTORY}/${CHECKOUT_RELATIVE_PATH}
RESULT_VARIABLE RET_BRANCH)
if(NOT RET_BRANCH EQUAL 0)
message(
SEND_ERROR
"Failed to checkout '${CHECKOUT_REPO_BRANCH}' for ${CHECKOUT_REPO_URL} in ${CHECKOUT_WORKING_DIRECTORY}/${CHECKOUT_RELATIVE_PATH}"
)
return()
endif()
endif()
# perform the submodule update
if(CHECKOUT_RECURSIVE
AND EXISTS "${_DIR}"
AND IS_DIRECTORY "${_DIR}")
execute_process(
COMMAND ${GIT_EXECUTABLE} submodule update --init ${_RECURSE}
WORKING_DIRECTORY ${_DIR}
RESULT_VARIABLE RET_RECURSIVE)
if(NOT RET_RECURSIVE EQUAL 0)
message(
SEND_ERROR
"Failed to update submodules for ${CHECKOUT_REPO_URL} in ${CHECKOUT_WORKING_DIRECTORY}/${CHECKOUT_RELATIVE_PATH}"
)
return()
endif()
endif()
set(_TEST_FILE_EXISTS ON)
endif()
if(NOT EXISTS "${_TEST_FILE}" OR NOT _TEST_FILE_EXISTS)
message(
FATAL_ERROR
"Error checking out submodule: '${CHECKOUT_RELATIVE_PATH}' to '${_DIR}'")
endif()
endfunction()
# ----------------------------------------------------------------------------------------#
# try to find a package quietly
#
function(ROCPROFILER_TEST_FIND_PACKAGE PACKAGE_NAME OUTPUT_VAR)
cmake_parse_arguments(PACKAGE "" "" "UNSET" ${ARGN})
find_package(${PACKAGE_NAME} QUIET ${PACKAGE_UNPARSED_ARGUMENTS})
if(NOT ${PACKAGE_NAME}_FOUND)
set(${OUTPUT_VAR}
OFF
PARENT_SCOPE)
else()
set(${OUTPUT_VAR}
ON
PARENT_SCOPE)
endif()
foreach(_ARG ${PACKAGE_UNSET} FIND_PACKAGE_MESSAGE_DETAILS_${PACKAGE_NAME})
unset(${_ARG} CACHE)
endforeach()
endfunction()
# ----------------------------------------------------------------------------------------#
# macro to add an interface lib
#
function(ROCPROFILER_ADD_INTERFACE_LIBRARY _TARGET _DESCRIPT)
set(_ARGS "${ARGN}")
if(IMPORTED IN_LIST _ARGS)
add_library(${_TARGET} INTERFACE IMPORTED)
else()
add_library(${_TARGET} INTERFACE)
endif()
if(NOT PACKAGE_NAME OR "${PACKAGE_NAME}" STREQUAL "")
message(FATAL_ERROR "Set PACKAGE_NAME")
endif()
add_library(${PACKAGE_NAME}::${_TARGET} ALIAS ${_TARGET})
if(NOT "INTERNAL" IN_LIST _ARGS AND NOT "IMPORTED" IN_LIST _ARGS)
install(
TARGETS ${_TARGET}
DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT core
EXPORT rocprofiler-sdk-targets
OPTIONAL)
endif()
endfunction()
# ----------------------------------------------------------------------------------------#
# macro to add an interface lib for nolink targets
#
function(ROCPROFILER_ADD_NOLINK_INTERFACE_LIBRARY _TARGET _DESCRIPT)
rocprofiler_add_interface_library(${_TARGET} "${_DESCRIPT}" ${ARGN})
# this is a nolink target so it's include dirs, etc. should propagate to the headers
# target
target_link_libraries(rocprofiler-sdk-headers INTERFACE $<BUILD_INTERFACE:${_TARGET}>)
endfunction()
# -----------------------------------------------------------------------
# function add_feature(<NAME> <DOCSTRING>) Add a project feature, whose activation is
# specified by the existence of the variable <NAME>, to the list of enabled/disabled
# features, plus a docstring describing the feature
#
function(ROCPROFILER_ADD_FEATURE _var _description)
set(EXTRA_DESC "")
foreach(currentArg ${ARGN})
if(NOT "${currentArg}" STREQUAL "${_var}"
AND NOT "${currentArg}" STREQUAL "${_description}"
AND NOT "${currentArg}" STREQUAL "CMAKE_DEFINE"
AND NOT "${currentArg}" STREQUAL "DOC")
set(EXTRA_DESC "${EXTA_DESC}${currentArg}")
endif()
endforeach()
set_property(GLOBAL APPEND PROPERTY ${PROJECT_NAME}_FEATURES ${_var})
set_property(GLOBAL PROPERTY ${_var}_DESCRIPTION "${_description}${EXTRA_DESC}")
if("CMAKE_DEFINE" IN_LIST ARGN)
set_property(GLOBAL APPEND PROPERTY ${PROJECT_NAME}_CMAKE_DEFINES
"${_var} @${_var}@")
if(ROCPROFILER_BUILD_DOCS)
set_property(
GLOBAL APPEND PROPERTY ${PROJECT_NAME}_CMAKE_OPTIONS_DOC
"${_var}` | ${_description}${EXTRA_DESC} |")
endif()
elseif("DOC" IN_LIST ARGN AND ROCPROFILER_BUILD_DOCS)
set_property(GLOBAL APPEND PROPERTY ${PROJECT_NAME}_CMAKE_OPTIONS_DOC
"${_var}` | ${_description}${EXTRA_DESC} |")
endif()
endfunction()
# ----------------------------------------------------------------------------------------#
# function add_option(<OPTION_NAME> <DOCSRING> <DEFAULT_SETTING> [NO_FEATURE]) Add an
# option and add as a feature if NO_FEATURE is not provided
#
function(ROCPROFILER_ADD_OPTION _NAME _MESSAGE _DEFAULT)
option(${_NAME} "${_MESSAGE}" ${_DEFAULT})
if("NO_FEATURE" IN_LIST ARGN)
mark_as_advanced(${_NAME})
else()
rocprofiler_add_feature(${_NAME} "${_MESSAGE}")
if(ROCPROFILER_BUILD_DOCS)
set_property(GLOBAL APPEND PROPERTY ${PROJECT_NAME}_CMAKE_OPTIONS_DOC
"${_NAME}` | ${_MESSAGE} |")
endif()
endif()
if("ADVANCED" IN_LIST ARGN)
mark_as_advanced(${_NAME})
endif()
if("CMAKE_DEFINE" IN_LIST ARGN)
set_property(GLOBAL APPEND PROPERTY ${PROJECT_NAME}_CMAKE_DEFINES ${_NAME})
endif()
endfunction()
# ----------------------------------------------------------------------------------------#
# function rocprofiler_add_cache_option(<OPTION_NAME> <DOCSRING> <TYPE> <DEFAULT_VALUE>
# [NO_FEATURE] [ADVANCED] [CMAKE_DEFINE])
#
function(ROCPROFILER_ADD_CACHE_OPTION _NAME _DEFAULT _TYPE _MESSAGE)
set(_FORCE)
if("FORCE" IN_LIST ARGN)
set(_FORCE FORCE)
endif()
set(${_NAME}
"${_DEFAULT}"
CACHE ${_TYPE} "${_MESSAGE}" ${_FORCE})
if("NO_FEATURE" IN_LIST ARGN)
mark_as_advanced(${_NAME})
else()
rocprofiler_add_feature(${_NAME} "${_MESSAGE}")
if(ROCPROFILER_BUILD_DOCS)
set_property(GLOBAL APPEND PROPERTY ${PROJECT_NAME}_CMAKE_OPTIONS_DOC
"${_NAME}` | ${_MESSAGE} |")
endif()
endif()
if("ADVANCED" IN_LIST ARGN)
mark_as_advanced(${_NAME})
endif()
if("CMAKE_DEFINE" IN_LIST ARGN)
set_property(GLOBAL APPEND PROPERTY ${PROJECT_NAME}_CMAKE_DEFINES ${_NAME})
endif()
endfunction()
# ----------------------------------------------------------------------------------------#
# function rocprofiler_report_feature_changes() :: print changes in features
#
function(ROCPROFILER_REPORT_FEATURE_CHANGES)
get_property(_features GLOBAL PROPERTY ${PROJECT_NAME}_FEATURES)
if(NOT "${_features}" STREQUAL "")
list(REMOVE_DUPLICATES _features)
list(SORT _features)
endif()
foreach(_feature ${_features})
if("${ARGN}" STREQUAL "")
rocprofiler_watch_for_change(${_feature})
elseif("${_feature}" IN_LIST ARGN)
rocprofiler_watch_for_change(${_feature})
endif()
endforeach()
endfunction()
# ----------------------------------------------------------------------------------------#
# function print_enabled_features() Print enabled features plus their docstrings.
#
function(ROCPROFILER_PRINT_ENABLED_FEATURES)
set(_basemsg "The following features are defined/enabled (+):")
set(_currentFeatureText "${_basemsg}")
get_property(_features GLOBAL PROPERTY ${PROJECT_NAME}_FEATURES)
if(NOT "${_features}" STREQUAL "")
list(REMOVE_DUPLICATES _features)
list(SORT _features)
endif()
foreach(_feature ${_features})
if(${_feature})
# add feature to text
set(_currentFeatureText "${_currentFeatureText}\n ${_feature}")
# get description
get_property(_desc GLOBAL PROPERTY ${_feature}_DESCRIPTION)
# print description, if not standard ON/OFF, print what is set to
if(_desc)
if(NOT "${${_feature}}" STREQUAL "ON" AND NOT "${${_feature}}" STREQUAL
"TRUE")
set(_currentFeatureText
"${_currentFeatureText}: ${_desc} -- [\"${${_feature}}\"]")
else()
string(REGEX REPLACE "^${PROJECT_NAME}_USE_" "" _feature_tmp
"${_feature}")
string(TOLOWER "${_feature_tmp}" _feature_tmp_l)
rocprofiler_capitalize("${_feature_tmp}" _feature_tmp_c)
foreach(_var _feature _feature_tmp _feature_tmp_l _feature_tmp_c)
set(_ver "${${${_var}}_VERSION}")
if(NOT "${_ver}" STREQUAL "")
set(_desc "${_desc} -- [found version ${_ver}]")
break()
endif()
unset(_ver)
endforeach()
set(_currentFeatureText "${_currentFeatureText}: ${_desc}")
endif()
set(_desc NOTFOUND)
endif()
endif()
endforeach()
if(NOT "${_currentFeatureText}" STREQUAL "${_basemsg}")
message(STATUS "${_currentFeatureText}\n")
endif()
endfunction()
# ----------------------------------------------------------------------------------------#
# function print_disabled_features() Print disabled features plus their docstrings.
#
function(ROCPROFILER_PRINT_DISABLED_FEATURES)
set(_basemsg "The following features are NOT defined/enabled (-):")
set(_currentFeatureText "${_basemsg}")
get_property(_features GLOBAL PROPERTY ${PROJECT_NAME}_FEATURES)
if(NOT "${_features}" STREQUAL "")
list(REMOVE_DUPLICATES _features)
list(SORT _features)
endif()
foreach(_feature ${_features})
if(NOT ${_feature})
set(_currentFeatureText "${_currentFeatureText}\n ${_feature}")
get_property(_desc GLOBAL PROPERTY ${_feature}_DESCRIPTION)
if(_desc)
set(_currentFeatureText "${_currentFeatureText}: ${_desc}")
set(_desc NOTFOUND)
endif(_desc)
endif()
endforeach(_feature)
if(NOT "${_currentFeatureText}" STREQUAL "${_basemsg}")
message(STATUS "${_currentFeatureText}\n")
endif()
endfunction()
# ----------------------------------------------------------------------------------------#
# function print_features() Print all features plus their docstrings.
#
function(ROCPROFILER_PRINT_FEATURES)
rocprofiler_report_feature_changes()
rocprofiler_print_enabled_features()
rocprofiler_print_disabled_features()
endfunction()
# ----------------------------------------------------------------------------------------#
# this function is provided to easily select which files use alternative compiler:
#
# GLOBAL --> all files TARGET --> all files in a target SOURCE --> specific
# source files DIRECTORY --> all files in directory PROJECT --> all files/targets in
# a project/subproject
#
function(rocprofiler_custom_compilation)
cmake_parse_arguments(COMP "GLOBAL;PROJECT" "COMPILER" "DIRECTORY;TARGET;SOURCE"
${ARGN})
# find rocprofiler-launch-compiler
find_program(
ROCPROFILER_COMPILE_LAUNCHER
NAMES rocprofiler-launch-compiler
HINTS ${PROJECT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}
PATHS ${PROJECT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}
PATH_SUFFIXES scripts bin)
if(NOT COMP_COMPILER)
message(
FATAL_ERROR "rocprofiler_custom_compilation not provided COMPILER argument")
endif()
if(NOT ROCPROFILER_COMPILE_LAUNCHER)
message(
FATAL_ERROR
"rocprofiler could not find 'rocprofiler-launch-compiler'. Please set '-DROCPROFILER_COMPILE_LAUNCHER=/path/to/launcher'"
)
endif()
if(COMP_GLOBAL)
# if global, don't bother setting others
set_property(
GLOBAL
PROPERTY
RULE_LAUNCH_COMPILE
"${ROCPROFILER_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}")
set_property(
GLOBAL
PROPERTY
RULE_LAUNCH_LINK
"${ROCPROFILER_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}")
else()
foreach(_TYPE PROJECT DIRECTORY TARGET SOURCE)
# make project/subproject scoping easy, e.g.
# rocprofiler_custom_compilation(PROJECT) after project(...)
if("${_TYPE}" STREQUAL "PROJECT" AND COMP_${_TYPE})
list(APPEND COMP_DIRECTORY ${PROJECT_SOURCE_DIR})
unset(COMP_${_TYPE})
endif()
# set the properties if defined
if(COMP_${_TYPE})
foreach(_VAL ${COMP_${_TYPE}})
set_property(
${_TYPE} ${_VAL}
PROPERTY
RULE_LAUNCH_COMPILE
"${ROCPROFILER_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}"
)
set_property(
${_TYPE} ${_VAL}
PROPERTY
RULE_LAUNCH_LINK
"${ROCPROFILER_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}"
)
endforeach()
endif()
endforeach()
endif()
endfunction()
function(ROCPROFILER_WATCH_FOR_CHANGE _var)
list(LENGTH ARGN _NUM_EXTRA_ARGS)
if(_NUM_EXTRA_ARGS EQUAL 1)
set(_VAR ${ARGN})
else()
set(_VAR)
endif()
macro(update_var _VAL)
if(_VAR)
set(${_VAR}
${_VAL}
PARENT_SCOPE)
endif()
endmacro()
update_var(OFF)
set(_rocprofiler_watch_var_name ROCPROFILER_WATCH_VALUE_${_var})
if(DEFINED ${_rocprofiler_watch_var_name})
if("${${_var}}" STREQUAL "${${_rocprofiler_watch_var_name}}")
return()
else()
rocprofiler_message(
STATUS
"${_var} changed :: ${${_rocprofiler_watch_var_name}} --> ${${_var}}")
update_var(ON)
endif()
else()
if(NOT "${${_var}}" STREQUAL "")
rocprofiler_message(STATUS "${_var} :: ${${_var}}")
update_var(ON)
endif()
endif()
# store the value for the next run
set(${_rocprofiler_watch_var_name}
"${${_var}}"
CACHE INTERNAL "Last value of ${_var}" FORCE)
endfunction()
function(ROCPROFILER_DIRECTORY)
cmake_parse_arguments(F "MKDIR;FAIL;FORCE" "PREFIX;OUTPUT_VARIABLE;WORKING_DIRECTORY"
"PATHS" ${ARGN})
if(F_PREFIX AND NOT IS_ABSOLUTE "${F_PREFIX}")
if(F_WORKING_DIRECTORY)
rocprofiler_message(
STATUS
"PREFIX was specified as a relative path, using working directory + prefix :: '${F_WORKING_DIRECTORY}/${F_PREFIX}'..."
)
set(F_PREFIX ${F_WORKING_DIRECTORY}/${F_PREFIX})
else()
rocprofiler_message(
FATAL_ERROR
"PREFIX was specified but it is not an absolute path: ${F_PREFIX}")
endif()
endif()
if(NOT F_WORKING_DIRECTORY)
set(F_WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
endif()
foreach(_PATH ${F_PREFIX} ${F_PATHS})
if(F_PREFIX AND NOT "${_PATH}" STREQUAL "${F_PREFIX}")
# if path is relative, set to prefix + path
if(NOT IS_ABSOLUTE "${_PATH}")
set(_PATH ${F_PREFIX}/${_PATH})
endif()
list(APPEND _OUTPUT_VAR ${_PATH})
elseif(NOT F_PREFIX)
list(APPEND _OUTPUT_VAR ${_PATH})
endif()
if(NOT EXISTS "${_PATH}" AND F_FAIL)
rocprofiler_message(FATAL_ERROR "Directory '${_PATH}' does not exist")
elseif(NOT IS_DIRECTORY "${_PATH}" AND F_FAIL)
rocprofiler_message(FATAL_ERROR "'${_PATH}' exists but is not a directory")
elseif(NOT EXISTS "${_PATH}" AND F_MKDIR)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${_PATH}
WORKING_DIRECTORY ${F_WORKING_DIRECTORY})
elseif(
EXISTS "${_PATH}"
AND NOT IS_DIRECTORY "${_PATH}"
AND F_MKDIR)
if(F_FORCE)
execute_process(COMMAND ${CMAKE_COMMAND} -E rm ${_PATH}
WORKING_DIRECTORY ${F_WORKING_DIRECTORY})
endif()
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${_PATH}
WORKING_DIRECTORY ${F_WORKING_DIRECTORY})
endif()
endforeach()
if(F_OUTPUT_VARIABLE)
set(${F_OUTPUT_VARIABLE}
"${_OUTPUT_VAR}"
PARENT_SCOPE)
endif()
endfunction()
function(ROCPROFILER_CHECK_PYTHON_DIRS_AND_VERSIONS)
cmake_parse_arguments(F "FAIL;UNSET" "RESULT_VARIABLE;OUTPUT_VARIABLE" "" ${ARGN})
list(LENGTH ROCPROFILER_PYTHON_VERSIONS _NUM_PYTHON_VERSIONS)
list(LENGTH ROCPROFILER_PYTHON_ROOT_DIRS _NUM_PYTHON_ROOT_DIRS)
if(NOT _NUM_PYTHON_VERSIONS EQUAL _NUM_PYTHON_ROOT_DIRS)
set(_RET 1)
else()
set(_RET 0)
if(F_OUTPUT_VARIABLE)
set(${F_OUTPUT_VARIABLE}
${_NUM_PYTHON_VERSIONS}
PARENT_SCOPE)
endif()
endif()
if(F_RESULT_VARIABLE)
set(${F_RESULT_VARIABLE}
${_RET}
PARENT_SCOPE)
endif()
if(NOT ${_RET} EQUAL 0)
if(F_FAIL)
rocprofiler_message(
WARNING
"Error! Number of python versions : ${_NUM_PYTHON_VERSIONS}. VERSIONS :: ${ROCPROFILER_PYTHON_VERSIONS}"
)
rocprofiler_message(
WARNING
"Error! Number of python root directories : ${_NUM_PYTHON_ROOT_DIRS}. ROOT DIRS :: ${ROCPROFILER_PYTHON_ROOT_DIRS}"
)
rocprofiler_message(
FATAL_ERROR
"Error! Number of python versions != number of python root directories")
elseif(F_UNSET)
unset(ROCPROFILER_PYTHON_VERSIONS CACHE)
unset(ROCPROFILER_PYTHON_ROOT_DIRS CACHE)
if(F_OUTPUT_VARIABLE)
set(${F_OUTPUT_VARIABLE} 0)
endif()
endif()
endif()
endfunction()
# ----------------------------------------------------------------------------
# Console scripts
#
function(ROCPROFILER_PYTHON_CONSOLE_SCRIPT SCRIPT_NAME SCRIPT_SUBMODULE)
set(options)
set(args VERSION ROOT_DIR)
set(kwargs)
cmake_parse_arguments(ARG "${options}" "${args}" "${kwargs}" ${ARGN})
if(ARG_VERSION AND ARG_ROOT_DIR)
set(Python3_ROOT_DIR "${ARG_ROOT_DIR}")
find_package(Python3 ${ARG_VERSION} EXACT QUIET MODULE COMPONENTS Interpreter)
set(PYTHON_EXECUTABLE "${Python3_EXECUTABLE}")
execute_process(COMMAND ${Python3_EXECUTABLE} -m pip install pandas)
configure_file(${PROJECT_SOURCE_DIR}/cmake/Templates/console-script.in
${PROJECT_BINARY_DIR}/bin/${SCRIPT_NAME}-${ARG_VERSION} @ONLY)
if(CMAKE_INSTALL_PYTHONDIR)
install(
PROGRAMS ${PROJECT_BINARY_DIR}/bin/${SCRIPT_NAME}-${ARG_VERSION}
DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT python
OPTIONAL)
endif()
if(ROCPROFILER_BUILD_TESTING OR ROCPROFILER_BUILD_PYTHON)
add_test(
NAME ${SCRIPT_NAME}-console-script-test-${ARG_VERSION}
COMMAND ${PROJECT_BINARY_DIR}/bin/${SCRIPT_NAME}-${ARG_VERSION} --help
WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
set_tests_properties(
${SCRIPT_NAME}-console-script-test-${ARG_VERSION}
PROPERTIES LABELS "python;python-${ARG_VERSION};console-script")
add_test(
NAME ${SCRIPT_NAME}-generic-console-script-test-${ARG_VERSION}
COMMAND ${PROJECT_BINARY_DIR}/bin/${SCRIPT_NAME} --help
WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
set_tests_properties(
${SCRIPT_NAME}-generic-console-script-test-${ARG_VERSION}
PROPERTIES ENVIRONMENT "PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}" LABELS
"python;python-${ARG_VERSION};console-script")
endif()
else()
set(PYTHON_EXECUTABLE "python3")
configure_file(${PROJECT_SOURCE_DIR}/cmake/Templates/console-script.in
${PROJECT_BINARY_DIR}/bin/${SCRIPT_NAME} @ONLY)
if(CMAKE_INSTALL_PYTHONDIR)
install(
PROGRAMS ${PROJECT_BINARY_DIR}/bin/${SCRIPT_NAME}
DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT python
OPTIONAL)
endif()
endif()
endfunction()
function(ROCPROFILER_FIND_STATIC_LIBRARY)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX})
find_library(${ARGN})
endfunction()
function(ROCPROFILER_FIND_SHARED_LIBRARY)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX})
find_library(${ARGN})
endfunction()
function(ROCPROFILER_BUILDTREE_TPL _TPL_TARGET _NEW_NAME _BUILD_TREE_DIR)
get_target_property(_TPL_VERSION ${_TPL_TARGET} VERSION)
get_target_property(_TPL_SOVERSION ${_TPL_TARGET} SOVERSION)
get_target_property(_TPL_NAME ${_TPL_TARGET} OUTPUT_NAME)
set(_TPL_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX})
set(_TPL_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
foreach(_TAIL ${_TPL_SUFFIX} ${_TPL_SUFFIX}.${_TPL_SOVERSION}
${_TPL_SUFFIX}.${_TPL_VERSION})
set(_INP ${_TPL_PREFIX}${_TPL_NAME}${_TAIL})
set(_OUT ${_TPL_PREFIX}${_NEW_NAME}${_TAIL})
endforeach()
string(REPLACE " " "-" _TAIL "${ARGN}")
# build tree symbolic links
add_custom_target(
${_NEW_NAME}-build-tree-library${_TAIL} ALL
${CMAKE_COMMAND} -E create_symlink $<TARGET_FILE:${_TPL_TARGET}>
${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_VERSION}
COMMAND
${CMAKE_COMMAND} -E create_symlink
${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_VERSION}
${_BUILD_TREE_DIR}/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_SOVERSION}
COMMAND
${CMAKE_COMMAND} -E create_symlink
${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_SOVERSION}
${_BUILD_TREE_DIR}/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}
WORKING_DIRECTORY ${_BUILD_TREE_DIR}
DEPENDS ${_TPL_TARGET}
COMMENT "Creating ${_NEW_NAME} from ${_TPL_TARGET}...")
endfunction()
function(ROCPROFILER_INSTALL_TPL _TPL_TARGET _NEW_NAME _BUILD_TREE_DIR _COMPONENT)
get_target_property(_TPL_VERSION ${_TPL_TARGET} VERSION)
get_target_property(_TPL_SOVERSION ${_TPL_TARGET} SOVERSION)
get_target_property(_TPL_NAME ${_TPL_TARGET} OUTPUT_NAME)
set(_TPL_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX})
set(_TPL_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
foreach(_TAIL ${_TPL_SUFFIX} ${_TPL_SUFFIX}.${_TPL_SOVERSION}
${_TPL_SUFFIX}.${_TPL_VERSION})
set(_INP ${_TPL_PREFIX}${_TPL_NAME}${_TAIL})
set(_OUT ${_TPL_PREFIX}${_NEW_NAME}${_TAIL})
endforeach()
# build tree symbolic links
rocprofiler_buildtree_tpl("${_TPL_TARGET}" "${_NEW_NAME}" "${_BUILD_TREE_DIR}"
${ARGN})
install(
FILES $<TARGET_FILE:${_TPL_TARGET}>
DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT ${_COMPONENT}
RENAME ${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_VERSION})
install(
FILES
${_BUILD_TREE_DIR}/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_SOVERSION}
${_BUILD_TREE_DIR}/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}
DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT ${_COMPONENT})
endfunction()
function(COMPUTE_POW2_CEIL _OUTPUT _VALUE)
find_package(Python3 COMPONENTS Interpreter)
if(Python3_FOUND)
execute_process(
COMMAND
${Python3_EXECUTABLE} -c
"VALUE = ${_VALUE}; ispow2 = lambda x: x if (x and (not(x & (x - 1)))) else None; v = list(filter(ispow2, [x for x in range(VALUE, VALUE**2)])); print(v[0])"
RESULT_VARIABLE _POW2_RET
OUTPUT_VARIABLE _POW2_OUT
ERROR_VARIABLE _POW2_ERR
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(_POW2_RET EQUAL 0)
set(${_OUTPUT}
${_POW2_OUT}
PARENT_SCOPE)
else()
set(${_OUTPUT}
"-1"
PARENT_SCOPE)
endif()
else()
set(${_OUTPUT}
"-1"
PARENT_SCOPE)
endif()
endfunction()
# ----------------------------------------------------------------------------
# Parses headers in hsa/hsa_api_trace*.h for API table version numbers
#
function(rocprofiler_parse_hsa_api_table_versions _TARGET)
get_target_property(HSA_API_TRACE_HEADER_PATH ${_TARGET}
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES)
if(HSA_API_TRACE_HEADER AND NOT EXISTS "${HSA_API_TRACE_HEADER}")
unset(HSA_API_TRACE_HEADER CACHE)
endif()
find_file(
HSA_API_TRACE_HEADER
NAMES hsa_api_trace_version.h hsa_api_trace.h
HINTS ${HSA_API_TRACE_HEADER_PATH}
PATHS ${HSA_API_TRACE_HEADER_PATH}
PATH_SUFFIXES hsa
NO_DEFAULT_PATH)
if(EXISTS "${HSA_API_TRACE_HEADER}")
file(READ "${HSA_API_TRACE_HEADER}" HSA_API_TRACE_HEADER_CONTENTS)
string(REPLACE "\n" ";" HSA_API_TRACE_HEADER_CONTENTS
"${HSA_API_TRACE_HEADER_CONTENTS}")
foreach(_LINE ${HSA_API_TRACE_HEADER_CONTENTS})
if("${_LINE}" MATCHES ".*define HSA_.*_(MAJOR|STEP)_VERSION .*")
# message(STATUS "LINE: ${_LINE}")
string(
REGEX
REPLACE
"#[ ]*define HSA_([A-Z_]*)API_TABLE_(MAJOR|STEP)_VERSION [ ]*(0x[0-9A-Fa-f]+)"
"HSA_\\1API_TABLE_\\2_VERSION"
_VAR
"${_LINE}")
string(
REGEX
REPLACE
"#[ ]*define HSA_([A-Z_]*)API_TABLE_(MAJOR|STEP)_VERSION [ ]*(0x[0-9A-Fa-f]+)"
"\\3"
_VAL
"${_LINE}")
# used with cmakedefine in source/include/rocprofiler-sdk/ext_version.h.in
if(_VAR AND _VAL)
set(ROCPROFILER_${_VAR}
"${_VAL}"
PARENT_SCOPE)
endif()
endif()
endforeach()
endif()
endfunction()
# ----------------------------------------------------------------------------
# Configures and installs the setup-env.sh and modulefile
#
function(rocprofiler_install_env_setup_files)
# parse args
cmake_parse_arguments(
RIEF "" "NAME;VERSION;SOURCE_DIR;BINARY_DIR;INSTALL_DIR;COMPONENT" "" ${ARGN})
if(NOT RIEF_NAME OR NOT RIEF_INSTALL_DIR)
message(SEND_ERROR "Missing NAME / INSTALL_DIR arguments")
return()
endif()
set(PACKAGE_NAME "${RIEF_NAME}")
string(REPLACE "-" "_" PACKAGE_NAME_UNDERSCORED "${RIEF_NAME}")
foreach(_TYPE VERSION SOURCE_DIR BINARY_DIR)
if(NOT RIEF_${_TYPE})
set(RIEF_${_TYPE} "${PROJECT_${_TYPE}}")
endif()
endforeach()
if(NOT RIEF_COMPONENT)
set(RIEF_COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME})
endif()
configure_file(
${RIEF_SOURCE_DIR}/cmake/Templates/setup-env.sh.in
${RIEF_BINARY_DIR}/${RIEF_INSTALL_DIR}/${PACKAGE_NAME}/setup-env.sh @ONLY)
configure_file(
${RIEF_SOURCE_DIR}/cmake/Templates/modulefile.in
${RIEF_BINARY_DIR}/${RIEF_INSTALL_DIR}/modulefiles/${PACKAGE_NAME}/${RIEF_VERSION}
@ONLY)
install(
FILES ${RIEF_BINARY_DIR}/${RIEF_INSTALL_DIR}/${PACKAGE_NAME}/setup-env.sh
DESTINATION ${RIEF_INSTALL_DIR}/${PACKAGE_NAME}
COMPONENT ${RIEF_COMPONENT})
install(
FILES
${RIEF_BINARY_DIR}/${RIEF_INSTALL_DIR}/modulefiles/${PACKAGE_NAME}/${RIEF_VERSION}
DESTINATION ${RIEF_INSTALL_DIR}/modulefiles/${PACKAGE_NAME}
COMPONENT ${RIEF_COMPONENT})
endfunction()
# ----------------------------------------------------------------------------
# Adds a unit test subdirectory
#
function(rocprofiler_add_unit_test)
cmake_policy(PUSH)
if(POLICY CMP0174)
cmake_policy(SET CMP0174 OLD)
endif()
# parse args
set(_FLAG_OPTS)
set(_SINGLE_OPTS
"TARGET"
"TEST_LIST"
"TEST_PREFIX"
"TIMEOUT"
"LABELS"
"DISABLED"
"PASS_REGULAR_EXPRESSION"
"FAIL_REGULAR_EXPRESSION"
"SKIP_REGULAR_EXPRESSION")
set(_MULTI_OPTS "SOURCES" "ENVIRONMENT" "DISABLE_TESTS")
cmake_parse_arguments(RAUT "${_FLAG_OPTS}" "${_SINGLE_OPTS}" "${_MULTI_OPTS}" ${ARGN})
include(GoogleTest)
macro(set_arg_if_empty _VAR)
if(NOT ${_VAR})
set(${_VAR} ${ARGN})
endif()
endmacro()
foreach(_VAR TARGET SOURCES)
if(NOT RAUT_${_VAR})
message(
FATAL_ERROR "rocprofiler_add_unit_test missing required argument: ${_VAR}"
)
endif()
endforeach()
set_arg_if_empty(RAUT_TIMEOUT 45)
set_arg_if_empty(RAUT_LABELS "unittests")
set_arg_if_empty(RAUT_TEST_LIST "${RAUT_TARGET}_TESTS")
set_arg_if_empty(RAUT_FAIL_REGULAR_EXPRESSION "${ROCPROFILER_DEFAULT_FAIL_REGEX}")
set_arg_if_empty(RAUT_DISABLED "OFF")
set_arg_if_empty(RAUT_TEST_PREFIX "unit.")
set(_DISABLE_TESTS_SOURCE "")
if(RAUT_DISABLE_TESTS)
foreach(_TEST ${RAUT_DISABLE_TESTS})
list(APPEND _DISABLE_TESTS_SOURCE "${RAUT_TEST_PREFIX}${_TEST}")
endforeach()
endif()
if(NOT "unittests" IN_LIST RAUT_LABELS)
list(APPEND RAUT_LABELS "unittests")
endif()
gtest_add_tests(
TARGET ${RAUT_TARGET}
SOURCES ${RAUT_SOURCES}
TEST_LIST ${RAUT_TEST_LIST}
TEST_PREFIX ${RAUT_TEST_PREFIX}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties(
${${RAUT_TEST_LIST}}
PROPERTIES TIMEOUT
${RAUT_TIMEOUT}
LABELS
"${RAUT_LABELS}"
FAIL_REGULAR_EXPRESSION
"${RAUT_FAIL_REGULAR_EXPRESSION}"
PASS_REGULAR_EXPRESSION
"${RAUT_PASS_REGULAR_EXPRESSION}"
SKIP_REGULAR_EXPRESSION
"${RAUT_SKIP_REGULAR_EXPRESSION}"
ENVIRONMENT
"${RAUT_ENVIRONMENT}"
DISABLED
${RAUT_DISABLED})
if(_DISABLE_TESTS_SOURCE)
set_tests_properties(${_DISABLE_TESTS_SOURCE} PROPERTIES DISABLED ON)
endif()
install(
TARGETS ${RAUT_TARGET}
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PACKAGE_NAME}/tests/unit-tests/bin
COMPONENT tests
EXPORT rocprofiler-sdk-tests-targets)
get_property(
_ROCP_SDK_TEST_TARGETS
DIRECTORY ${CMAKE_SOURCE_DIR}
PROPERTY rocprofiler-sdk-tests-targets)
if(RAUT_TARGET IN_LIST _ROCP_SDK_TEST_TARGETS)
message(
FATAL_ERROR
"Target ${RAUT_TARGET} already exists in rocprofiler-sdk-tests-targets")
endif()
set_property(
DIRECTORY ${CMAKE_SOURCE_DIR}
APPEND
PROPERTY rocprofiler-sdk-tests-targets ${RAUT_TARGET})
string(REPLACE "-" "_" _PACKAGE_NAME_UNDERSCORED "${CMAKE_PROJECT_NAME}")
set(RAUT_TEST_PREFIX "${_PACKAGE_NAME_UNDERSCORED}.${RAUT_TEST_PREFIX}")
set(_DISABLE_TESTS_INSTALLED "")
if(RAUT_DISABLE_TESTS)
foreach(_TEST ${RAUT_DISABLE_TESTS})
list(APPEND _DISABLE_TESTS_INSTALLED "${RAUT_TEST_PREFIX}${_TEST}")
endforeach()
endif()
set(RAUT_DISABLE_TESTS "${_DISABLE_TESTS_INSTALLED}")
configure_file(
${CMAKE_SOURCE_DIR}/cmake/Templates/unit-test.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/${PACKAGE_NAME}/tests/unit-tests/${RAUT_TARGET}.cmake
@ONLY)
install(
FILES ${RAUT_SOURCES}
DESTINATION
${CMAKE_INSTALL_DATAROOTDIR}/${PACKAGE_NAME}/tests/unit-tests/${RAUT_TARGET}
COMPONENT tests)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/${PACKAGE_NAME}/tests/unit-tests/${RAUT_TARGET}.cmake
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PACKAGE_NAME}/tests/unit-tests
COMPONENT tests)
cmake_policy(POP)
endfunction()
# gets the user local python bin directory from `python3 -m pip install --user ...`
#
function(_rocprofiler_get_python_user_bin _OUT)
find_package(Python3 QUIET)
# default to empty
set(_VAL)
if(Python3_FOUND)
execute_process(
COMMAND ${Python3_EXECUTABLE} -m site --user-base
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
OUTPUT_VARIABLE _PYTHON_USER_BASE
RESULT_VARIABLE _PYTHON_USER_BASE_RET
OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
# if successful, check the bin dir
if(_PYTHON_USER_BASE_RET EQUAL 0)
set(_PYTHON_USER_BIN "${_PYTHON_USER_BASE}/bin")
if(EXISTS "${_PYTHON_USER_BIN}")
set(_VAL "${_PYTHON_USER_BIN}")
endif()
endif()
endif()
# return value
set(${_OUT}
"${_VAL}"
PARENT_SCOPE)
endfunction()
cmake_policy(POP)