From fa4295db6b8c0c3b091aec8d8dffc6dffcd4754b Mon Sep 17 00:00:00 2001 From: "Jonathan R. Madsen" Date: Thu, 17 Aug 2023 14:59:24 -0500 Subject: [PATCH] Initial Implementation: include (#10) * Initial Implementation: include * Initial Implementation: lib details (#11) * Initial Implementation: lib details * Initial Implementation: lib (#12) * Initial Implementation: lib * Initial Implementation: source (#13) * Initial Implementation: source * Initial Implementation: samples (#14) * Initial Implementation: samples * Initial Implementation: tests (#15) * Initial Implementation: tests * Initial Implementation: scripts (#16) * Initial Implementation: scripts * Initial Implementation: cmake (#17) * Initial Implementation: cmake * Initial Implementation: top-level files (#18) * Initial Implementation: top-level files - clang-format - clang-tidy - cmake-format - ignore build and cache directories - main CMakeLists.txt - pyproject.toml (python formatting) - VERSION file * Initial Implementation: workflow (#19) * Fix unused variable - rocprofiler_register_warn_level --- .clang-format | 114 +++ .clang-tidy | 55 + .cmake-format.yaml | 318 ++++++ .github/workflows/continuous-integration.yml | 172 ++++ .github/workflows/formatting.yml | 146 +++ .gitignore | 4 + CMakeLists.txt | 110 ++ VERSION | 1 + cmake/Templates/modulefile.in | 16 + .../rocprofiler-register-config.cmake.in | 32 + cmake/Templates/setup-env.sh.in | 23 + .../rocprofiler_register_build_settings.cmake | 107 ++ cmake/rocprofiler_register_compilers.cmake | 352 +++++++ .../rocprofiler_register_config_install.cmake | 87 ++ ...cprofiler_register_config_interfaces.cmake | 67 ++ ...ocprofiler_register_config_packaging.cmake | 100 ++ cmake/rocprofiler_register_formatting.cmake | 104 ++ cmake/rocprofiler_register_interfaces.cmake | 34 + cmake/rocprofiler_register_linting.cmake | 47 + cmake/rocprofiler_register_memcheck.cmake | 40 + cmake/rocprofiler_register_options.cmake | 90 ++ cmake/rocprofiler_register_utilities.cmake | 941 ++++++++++++++++++ pyproject.toml | 25 + samples/CMakeLists.txt | 6 + samples/library-implementation/CMakeLists.txt | 18 + samples/library-implementation/demo.cpp | 120 +++ samples/library-implementation/demo.hpp | 37 + scripts/address-sanitizer-suppr.txt | 3 + scripts/leak-sanitizer-suppr.txt | 3 + scripts/run-ci.py | 463 +++++++++ scripts/thread-sanitizer-suppr.txt | 3 + source/CMakeLists.txt | 11 + source/include/CMakeLists.txt | 4 + .../rocprofiler-register/CMakeLists.txt | 13 + .../rocprofiler-register.h | 188 ++++ .../include/rocprofiler-register/version.h.in | 103 ++ source/lib/CMakeLists.txt | 4 + .../lib/rocprofiler-register/CMakeLists.txt | 36 + .../details/CMakeLists.txt | 10 + .../lib/rocprofiler-register/details/dl.cpp | 125 +++ .../lib/rocprofiler-register/details/dl.hpp | 60 ++ .../details/environment.hpp | 191 ++++ .../lib/rocprofiler-register/details/join.hpp | 184 ++++ .../lib/rocprofiler-register/details/log.hpp | 518 ++++++++++ .../rocprofiler-register/details/utility.cpp | 127 +++ .../rocprofiler-register/details/utility.hpp | 44 + .../rocprofiler_register.c | 24 + .../rocprofiler_register.cpp | 374 +++++++ tests/CMakeLists.txt | 465 +++++++++ tests/amdhip/CMakeLists.txt | 39 + tests/amdhip/amdhip.cpp | 154 +++ tests/amdhip/amdhip.hpp | 40 + tests/common/fwd.h | 31 + tests/common/fwd.hpp | 101 ++ tests/hsa-runtime/CMakeLists.txt | 35 + tests/hsa-runtime/hsa-runtime.cpp | 149 +++ tests/hsa-runtime/hsa-runtime.hpp | 40 + tests/rocprofiler/CMakeLists.txt | 14 + tests/rocprofiler/rocprofiler.cpp | 135 +++ tests/roctx/CMakeLists.txt | 19 + tests/roctx/roctx.cpp | 170 ++++ tests/roctx/roctx.hpp | 46 + tests/start-up-test/CMakeLists.txt | 3 + tests/test-amdhip-ctor-mt.cpp | 72 ++ tests/test-amdhip-ctor.cpp | 42 + tests/test-amdhip-hsart-roctx.cpp | 43 + tests/test-amdhip-roctx-mt.cpp | 72 ++ tests/test-amdhip-roctx.cpp | 43 + 68 files changed, 7367 insertions(+) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 .cmake-format.yaml create mode 100644 .github/workflows/continuous-integration.yml create mode 100644 .github/workflows/formatting.yml create mode 100644 CMakeLists.txt create mode 100644 VERSION create mode 100644 cmake/Templates/modulefile.in create mode 100644 cmake/Templates/rocprofiler-register-config.cmake.in create mode 100644 cmake/Templates/setup-env.sh.in create mode 100644 cmake/rocprofiler_register_build_settings.cmake create mode 100644 cmake/rocprofiler_register_compilers.cmake create mode 100644 cmake/rocprofiler_register_config_install.cmake create mode 100644 cmake/rocprofiler_register_config_interfaces.cmake create mode 100644 cmake/rocprofiler_register_config_packaging.cmake create mode 100644 cmake/rocprofiler_register_formatting.cmake create mode 100644 cmake/rocprofiler_register_interfaces.cmake create mode 100644 cmake/rocprofiler_register_linting.cmake create mode 100644 cmake/rocprofiler_register_memcheck.cmake create mode 100644 cmake/rocprofiler_register_options.cmake create mode 100644 cmake/rocprofiler_register_utilities.cmake create mode 100644 pyproject.toml create mode 100644 samples/CMakeLists.txt create mode 100644 samples/library-implementation/CMakeLists.txt create mode 100644 samples/library-implementation/demo.cpp create mode 100644 samples/library-implementation/demo.hpp create mode 100644 scripts/address-sanitizer-suppr.txt create mode 100644 scripts/leak-sanitizer-suppr.txt create mode 100755 scripts/run-ci.py create mode 100644 scripts/thread-sanitizer-suppr.txt create mode 100644 source/CMakeLists.txt create mode 100644 source/include/CMakeLists.txt create mode 100644 source/include/rocprofiler-register/CMakeLists.txt create mode 100644 source/include/rocprofiler-register/rocprofiler-register.h create mode 100644 source/include/rocprofiler-register/version.h.in create mode 100644 source/lib/CMakeLists.txt create mode 100644 source/lib/rocprofiler-register/CMakeLists.txt create mode 100644 source/lib/rocprofiler-register/details/CMakeLists.txt create mode 100644 source/lib/rocprofiler-register/details/dl.cpp create mode 100644 source/lib/rocprofiler-register/details/dl.hpp create mode 100644 source/lib/rocprofiler-register/details/environment.hpp create mode 100644 source/lib/rocprofiler-register/details/join.hpp create mode 100644 source/lib/rocprofiler-register/details/log.hpp create mode 100644 source/lib/rocprofiler-register/details/utility.cpp create mode 100644 source/lib/rocprofiler-register/details/utility.hpp create mode 100644 source/lib/rocprofiler-register/rocprofiler_register.c create mode 100644 source/lib/rocprofiler-register/rocprofiler_register.cpp create mode 100644 tests/CMakeLists.txt create mode 100644 tests/amdhip/CMakeLists.txt create mode 100644 tests/amdhip/amdhip.cpp create mode 100644 tests/amdhip/amdhip.hpp create mode 100644 tests/common/fwd.h create mode 100644 tests/common/fwd.hpp create mode 100644 tests/hsa-runtime/CMakeLists.txt create mode 100644 tests/hsa-runtime/hsa-runtime.cpp create mode 100644 tests/hsa-runtime/hsa-runtime.hpp create mode 100644 tests/rocprofiler/CMakeLists.txt create mode 100644 tests/rocprofiler/rocprofiler.cpp create mode 100644 tests/roctx/CMakeLists.txt create mode 100644 tests/roctx/roctx.cpp create mode 100644 tests/roctx/roctx.hpp create mode 100644 tests/start-up-test/CMakeLists.txt create mode 100644 tests/test-amdhip-ctor-mt.cpp create mode 100644 tests/test-amdhip-ctor.cpp create mode 100644 tests/test-amdhip-hsart-roctx.cpp create mode 100644 tests/test-amdhip-roctx-mt.cpp create mode 100644 tests/test-amdhip-roctx.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..8293545c39 --- /dev/null +++ b/.clang-format @@ -0,0 +1,114 @@ +# clang-format v11 +--- +Language: Cpp +BasedOnStyle: Google +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: true +AlignConsecutiveAssignments: true +AlignConsecutiveBitFields: true +AlignConsecutiveDeclarations: true +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: TopLevel +AlwaysBreakAfterReturnType: TopLevel +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: false + BeforeElse: true + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: true +BreakInheritanceList: BeforeComma +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeComma +BreakStringLiterals: true +ColumnLimit: 90 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: true +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 0 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Preserve +IndentCaseLabels: true +IndentCaseBlocks: false +IndentFunctionDeclarationAfterType: false +IndentGotoLabels: true +IndentPPDirectives: AfterHash +IndentExternBlock: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: Never +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +Standard: Auto +TabWidth: 4 +UseTab: Never +... diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000000..7714903656 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,55 @@ +--- +Checks: "-*,\ +misc-*,\ +-misc-incorrect-roundings,\ +-misc-macro-parentheses,\ +-misc-misplaced-widening-cast,\ +-misc-static-assert,\ +-misc-no-recursion,\ +-misc-non-private-member-variables-in-classes,\ +-misc-include-cleaner,\ +-misc-const-correctness,\ +modernize-*,\ +-modernize-deprecated-headers,\ +-modernize-raw-string-literal,\ +-modernize-return-braced-init-list,\ +-modernize-use-transparent-functors,\ +-modernize-use-trailing-return-type,\ +-modernize-avoid-c-arrays,\ +-modernize-redundant-void-arg,\ +-modernize-use-using,\ +-modernize-use-auto,\ +-modernize-concat-nested-namespaces,\ +-modernize-use-nodiscard,\ +-modernize-macro-to-enum,\ +-modernize-type-traits,\ +performance-*,\ +readability-*,\ +-readability-function-size,\ +-readability-identifier-naming,\ +-readability-implicit-bool-cast,\ +-readability-inconsistent-declaration-parameter-name,\ +-readability-named-parameter,\ +-readability-magic-numbers,\ +-readability-redundant-declaration,\ +-readability-redundant-member-init,\ +-readability-simplify-boolean-expr,\ +-readability-uppercase-literal-suffix,\ +-readability-braces-around-statements,\ +-readability-avoid-const-params-in-decls,\ +-readability-else-after-return,\ +-readability-isolate-declaration,\ +-readability-redundant-string-cstr,\ +-readability-static-accessed-through-instance,\ +-readability-const-return-type,\ +-readability-redundant-access-specifiers,\ +-readability-function-cognitive-complexity,\ +-readability-identifier-length,\ +-readability-use-anyofallof,\ +" +CheckOptions: + - key: readability-braces-around-statements.ShortStatementLines + value: '2' + - key: readability-implicit-bool-conversion.AllowPointerConditions + value: '1' +... diff --git a/.cmake-format.yaml b/.cmake-format.yaml new file mode 100644 index 0000000000..61a2cd0e93 --- /dev/null +++ b/.cmake-format.yaml @@ -0,0 +1,318 @@ +parse: + additional_commands: + rocprofiler_register_checkout_git_submodule: + flags: + - RECURSIVE + kwargs: + RELATIVE_PATH: '*' + WORKING_DIRECTORY: '*' + TEST_FILE: '*' + REPO_URL: '*' + REPO_BRANCH: '*' + ADDITIONAL_COMMANDS: '*' + rocprofiler_register_save_variables: + kwargs: + VARIABLES: '*' + CONDITION: '*' + rocprofiler_register_restore_variables: + kwargs: + VARIABLES: '*' + CONDITION: '*' + rocprofiler_register_target_compile_options: + flags: + - BUILD_INTERFACE + - FORCE + kwargs: + PUBLIC: '*' + PRIVATE: '*' + INTERFACE: '*' + LANGUAGES: '*' + LINK_LANGUAGES: '*' + rocprofiler_register_add_test: + flags: + - SKIP_BASELINE + - SKIP_SAMPLING + - SKIP_REWRITE + - SKIP_RUNTIME + kwargs: + NAME: '*' + TARGET: '*' + MPI: '*' + GPU: '*' + NUM_PROCS: '*' + REWRITE_TIMEOUT: '*' + RUNTIME_TIMEOUT: '*' + SAMPLING_TIMEOUT: '*' + SAMPLING_ARGS: '*' + REWRITE_ARGS: '*' + RUNTIME_ARGS: '*' + RUN_ARGS: '*' + ENVIRONMENT: '*' + LABELS: '*' + PROPERTIES: '*' + SAMPLING_PASS_REGEX: '*' + SAMPLING_FAIL_REGEX: '*' + RUNTIME_PASS_REGEX: '*' + RUNTIME_FAIL_REGEX: '*' + REWRITE_PASS_REGEX: '*' + REWRITE_FAIL_REGEX: '*' + BASELINE_PASS_REGEX: '*' + BASELINE_FAIL_REGEX: '*' + REWRITE_RUN_PASS_REGEX: '*' + REWRITE_RUN_FAIL_REGEX: '*' + rocprofiler_register_add_causal_test: + flags: + - SKIP_BASELINE + kwargs: + NAME: '*' + TARGET: '*' + CAUSAL_TIMEOUT: '*' + CAUSAL_VALIDATE_TIMEOUT: '*' + CAUSAL_MODE: '*' + CAUSAL_ARGS: '*' + CAUSAL_VALIDATE_ARGS: '*' + RUNTIME_ARGS: '*' + RUN_ARGS: '*' + ENVIRONMENT: '*' + LABELS: '*' + PROPERTIES: '*' + CAUSAL_PASS_REGEX: '*' + CAUSAL_FAIL_REGEX: '*' + BASELINE_PASS_REGEX: '*' + BASELINE_FAIL_REGEX: '*' + CAUSAL_VALIDATE_PASS_REGEX: '*' + CAUSAL_VALIDATE_FAIL_REGEX: '*' + rocprofiler_register_target_compile_definitions: + kwargs: + PUBLIC: '*' + PRIVATE: '*' + INTERFACE: '*' + rocprofiler_register_add_bin_test: + flags: + - WILL_FAIL + kwargs: + NAME: '*' + ARGS: '*' + LABELS: '*' + TARGET: '*' + DEPENDS: '*' + COMMAND: '*' + TIMEOUT: '*' + PROPERTIES: '*' + ENVIRONMENT: '*' + WORKING_DIRECTORY: '*' + PASS_REGEX: '*' + FAIL_REGEX: '*' + SKIP_REGEX: '*' + rocprofiler_register_add_python_test: + flags: + - STANDALONE + kwargs: + NAME: '*' + FILE: '*' + TIMEOUT: '*' + PROFILE_ARGS: '*' + RUN_ARGS: '*' + ENVIRONMENT: '*' + LABELS: '*' + DEPENDS: '*' + COMMAND: '*' + PROPERTIES: '*' + PYTHON_EXECUTABLE: '*' + PYTHON_VERSION: '*' + PASS_REGEX: '*' + FAIL_REGEX: '*' + SKIP_REGEX: '*' + rocprofiler_register_add_python_validation_test: + kwargs: + NAME: '*' + ARGS: '*' + PERFETTO_FILE: '*' + PERFETTO_METRIC: '*' + TIMEMORY_FILE: '*' + TIMEMORY_METRIC: '*' + rocm_version_message: + flags: + - STATUS + - WARNING + - SEND_ERROR + - FATAL_ERROR + - AUTHOR_WARNING + rocprofiler_register_find_python: + flags: + - REQUIRED + - QUIET + kwargs: + VERSION: '*' + ROOT_DIR: '*' + COMPONENTS: '*' + rocprofiler_register_python_console_script: + kwargs: + VERSION: '*' + ROOT_DIR: '*' + rocprofiler_register_pybind11_add_module: + flags: + - MODULE + - SHARED + - EXCLUDE_FROM_ALL + - NO_EXTRAS + - SYSTEM + - THIN_LTO + - LTO + kwargs: + PYTHON_VERSION: '*' + CXX_STANDARD: '*' + VISIBILITY: '*' + rocprofiler_register_directory: + flags: + - MKDIR + - FAIL + kwargs: + PREFIX: '*' + OUTPUT_VARIABLE: '*' + WORKING_DIRECTORY: '*' + PATHS: '*' + rocprofiler_register_check_python_dirs_and_versions: + flags: + - UNSET + - FAIL + kwargs: + RESULT_VARIABLE: '*' + OUTPUT_VARIABLE: '*' + rocprofiler_register_find_static_library: + flags: + - NO_CACHE + - REQUIRED + - NO_DEFAULT_PATH + - NO_PACKAGE_ROOT_PATH + - NO_CMAKE_PATH + - NO_CMAKE_ENVIRONMENT_PATH + - NO_SYSTEM_ENVIRONMENT_PATH + - CMAKE_FIND_ROOT_PATH_BOTH + - ONLY_CMAKE_FIND_ROOT_PATH + - NO_CMAKE_FIND_ROOT_PATH + kwargs: + NAMES: '*' + NAMES_PER_DIR: '*' + HINTS: '*' + PATHS: '*' + PATH_SUFFIXES: '*' + DOC: '*' + rocprofiler_register_find_shared_library: + flags: + - NO_CACHE + - REQUIRED + - NO_DEFAULT_PATH + - NO_PACKAGE_ROOT_PATH + - NO_CMAKE_PATH + - NO_CMAKE_ENVIRONMENT_PATH + - NO_SYSTEM_ENVIRONMENT_PATH + - CMAKE_FIND_ROOT_PATH_BOTH + - ONLY_CMAKE_FIND_ROOT_PATH + - NO_CMAKE_FIND_ROOT_PATH + kwargs: + NAMES: '*' + NAMES_PER_DIR: '*' + HINTS: '*' + PATHS: '*' + PATH_SUFFIXES: '*' + DOC: '*' + rocprofiler_register_causal_example_executable: + kwargs: + TAG: '*' + SOURCES: '*' + DEFINITIONS: '*' + LINK_LIBRARIES: '*' + INCLUDE_DIRECTORIES: '*' + rocprofiler_register_add_validation_test: + kwargs: + NAME: '*' + ARGS: '*' + LABELS: '*' + TIMEOUT: '*' + DEPENDS: '*' + PROPERTIES: '*' + PASS_REGEX: '*' + FAIL_REGEX: '*' + SKIP_REGEX: '*' + ENVIRONMENT: '*' + PERFETTO_FILE: '*' + PERFETTO_METRIC: '*' + TIMEMORY_FILE: '*' + TIMEMORY_METRIC: '*' + rocp_register_test_executable: + kwargs: + SECURE: '*' + SOURCES: '*' + LIBRARIES: '*' + CORE_PASS_REGEX: '*' + CORE_FAIL_REGEX: '*' + PRELOAD_PASS_REGEX: '*' + PRELOAD_FAIL_REGEX: '*' + WRAP_PASS_REGEX: '*' + WRAP_FAIL_REGEX: '*' + PRELOAD_WRAP_PASS_REGEX: '*' + PRELOAD_WRAP_FAIL_REGEX: '*' + override_spec: {} + vartags: [] + proptags: [] +format: + disable: false + line_width: 90 + tab_size: 4 + use_tabchars: false + fractional_tab_policy: use-space + max_subgroups_hwrap: 2 + max_pargs_hwrap: 8 + max_rows_cmdline: 2 + separate_ctrl_name_with_space: false + separate_fn_name_with_space: false + dangle_parens: false + dangle_align: child + min_prefix_chars: 4 + max_prefix_chars: 10 + max_lines_hwrap: 2 + line_ending: unix + command_case: lower + keyword_case: upper + always_wrap: [] + enable_sort: true + autosort: false + require_valid_layout: false + layout_passes: {} +markup: + bullet_char: '*' + enum_char: . + first_comment_is_literal: true + literal_comment_pattern: ^# + fence_pattern: ^\s*([`~]{3}[`~]*)(.*)$ + ruler_pattern: ^\s*[^\w\s]{3}.*[^\w\s]{3}$ + explicit_trailing_pattern: '#<' + hashruler_min_length: 10 + canonicalize_hashrulers: true + enable_markup: true +lint: + disabled_codes: [] + function_pattern: '[0-9a-z_]+' + macro_pattern: '[0-9A-Z_]+' + global_var_pattern: '[A-Z][0-9A-Z_]+' + internal_var_pattern: _[A-Z][0-9A-Z_]+ + local_var_pattern: '[a-z][a-z0-9_]+' + private_var_pattern: _[0-9a-z_]+ + public_var_pattern: '[A-Z][0-9A-Z_]+' + argument_var_pattern: '[a-z][a-z0-9_]+' + keyword_pattern: '[A-Z][0-9A-Z_]+' + max_conditionals_custom_parser: 2 + min_statement_spacing: 1 + max_statement_spacing: 2 + max_returns: 6 + max_branches: 12 + max_arguments: 5 + max_localvars: 15 + max_statements: 50 +encode: + emit_byteorder_mark: false + input_encoding: utf-8 + output_encoding: utf-8 +misc: + per_command: {} diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml new file mode 100644 index 0000000000..4959f58ee0 --- /dev/null +++ b/.github/workflows/continuous-integration.yml @@ -0,0 +1,172 @@ +name: Continuous Integration + +on: + push: + branches: [ main, develop ] + paths-ignore: + - '*.md' + pull_request: + branches: [ main, develop ] + paths-ignore: + - '*.md' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + ci: + strategy: + fail-fast: false + matrix: + runner: ['ubuntu-latest'] + compiler: ['clang-13', 'clang-14', 'clang-15', 'gcc-11', 'gcc-12'] + ci-args: [''] + ci-tag: [''] + include: + - runner: 'ubuntu-latest' + compiler: 'gcc-12' + ci-args: '--coverage' + ci-tag: '-codecov' + - runner: 'ubuntu-latest' + compiler: 'clang-15' + ci-args: '--linter clang-tidy' + ci-tag: '-clang-tidy' + # - runner: 'ubuntu-latest' + # compiler: 'gcc-12' + # ci-args: '--memcheck ThreadSanitizer' + # ci-tag: '-thread-sanitizer' + # - runner: 'ubuntu-latest' + # compiler: 'gcc-12' + # ci-args: '--memcheck AddressSanitizer' + # ci-tag: '-address-sanitizer' + # - runner: 'ubuntu-latest' + # compiler: 'gcc-12' + # ci-args: '--memcheck LeakSanitizer' + # ci-tag: '-leak-sanitizer' + # - runner: 'ubuntu-latest' + # compiler: 'gcc-12' + # ci-args: '--memcheck UndefinedBehaviorSanitizer' + # ci-tag: '-undefined-behavior-sanitizer' + + runs-on: ${{ matrix.runner }} + + env: + BUILD_TYPE: RelWithDebInfo + INSTALL_PREFIX: /opt/rocprofiler-register + PACKAGING_INSTALL_PREFIX: /opt/rocm + + steps: + - uses: actions/checkout@v3 + + - name: Install Packages + timeout-minutes: 25 + run: | + CC=${{ matrix.compiler }} && + CXX=$(echo ${{ matrix.compiler }} | sed 's/clang-/clang++-/1' | sed 's/gcc-/g++-/1') && + sudo apt-get update && + sudo apt-get install -y build-essential python3 environment-modules ${{ matrix.compiler }} ${CXX} && + sudo update-alternatives --install /usr/bin/cc cc /usr/bin/${CC} 100 && + sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/${CXX} 100 && + python3 -m pip install --upgrade pip && + python3 -m pip install 'cmake==3.21.4' + + - name: Setup GCov + timeout-minutes: 25 + if: ${{ matrix.compiler == 'gcc-12' }} + run: | + sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-12 100 + + - name: Setup Clang-Tidy + timeout-minutes: 25 + if: ${{ matrix.compiler == 'clang-15' }} + run: | + sudo apt-get install -y clang-tidy-15 + sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-15 100 + + - name: Configure, Build, and Test + timeout-minutes: 115 + shell: bash + run: + cmake --version && + python3 ./scripts/run-ci.py -B build + --name ${{ github.repository_owner }}-${{ github.ref_name }}-${{ matrix.runner }}-${{ matrix.compiler }}${{ matrix.ci-tag }} + --build-jobs 2 + --site GitHub + ${{ matrix.ci-args }} + --disable-cdash + -- + -DCMAKE_C_COMPILER=/usr/bin/cc + -DCMAKE_CXX_COMPILER=/usr/bin/c++ + -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} + -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_PREFIX }} + -DROCPROFILER_REGISTER_BUILD_TESTS=ON + -DROCPROFILER_REGISTER_BUILD_SAMPLES=ON + -- + -VV + + - name: Install + timeout-minutes: 10 + run: + cmake --build build --target install --parallel 2 + + - name: CPack and Install + run: | + cd build + cpack -G STGZ + mkdir -p ${{ env.PACKAGING_INSTALL_PREFIX }} + ./rocprofiler-register-*-Linux.sh --prefix=${{ env.PACKAGING_INSTALL_PREFIX }} --exclude-subdir --skip-license + + - name: Test Install Modulefile + timeout-minutes: 15 + shell: bash + run: | + set -v + source /usr/share/modules/init/$(basename ${SHELL}) + module use ${{ env.INSTALL_PREFIX }}/share/modulefiles + module avail + module load rocprofiler-register + pushd tests + BUILD_DIR=${PWD}/build-rocp-reg-modulefile + cmake -B ${BUILD_DIR} . + cmake --build ${BUILD_DIR} --target all + rm -rf ${BUILD_DIR} + + - name: Test Install Setup Env + timeout-minutes: 15 + shell: bash + run: | + set -v + source ${{ env.INSTALL_PREFIX }}/share/rocprofiler-register/setup-env.sh + pushd samples/library-implementation + BUILD_DIR=${PWD}/build-rocp-reg-setup-env + cmake -B ${BUILD_DIR} . + cmake --build ${BUILD_DIR} --target all + rm -rf ${BUILD_DIR} + + - name: Test Install CPack Modulefile + timeout-minutes: 15 + shell: bash + run: | + set -v + source /usr/share/modules/init/$(basename ${SHELL}) + module use ${{ env.PACKAGING_INSTALL_PREFIX }}/share/modulefiles + module avail + module load rocprofiler-register + pushd tests + BUILD_DIR=${PWD}/build-rocp-reg-modulefile-cpack + cmake -B ${BUILD_DIR} . + cmake --build ${BUILD_DIR} --target all + rm -rf ${BUILD_DIR} + + - name: Test Install CPack Setup Env + timeout-minutes: 15 + shell: bash + run: | + set -v + source ${{ env.PACKAGING_INSTALL_PREFIX }}/share/rocprofiler-register/setup-env.sh + pushd samples/library-implementation + BUILD_DIR=${PWD}/build-rocp-reg-setup-env-cpack + cmake -B ${BUILD_DIR} . + cmake --build ${BUILD_DIR} --target all + rm -rf ${BUILD_DIR} diff --git a/.github/workflows/formatting.yml b/.github/workflows/formatting.yml new file mode 100644 index 0000000000..7cbbb93f75 --- /dev/null +++ b/.github/workflows/formatting.yml @@ -0,0 +1,146 @@ + +name: Formatting + +on: + workflow_dispatch: + pull_request: + branches: [ main ] + paths-ignore: + - '.github/workflows/pull_*.yml' + - '.github/workflows/linting.yml' + - '.github/workflows/markdown_lint.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + cmake: + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v3 + + - name: Extract branch name + shell: bash + run: | + echo "branch=${GITHUB_HEAD_REF:-${GITHUB_HEAD_REF#refs/heads/}}" >> $GITHUB_OUTPUT + id: extract_branch + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y python3-pip + python3 -m pip install -U cmake-format + + - name: Run cmake-format + run: | + set +e + cmake-format -i $(find . -type f | egrep 'CMakeLists.txt|\.cmake$') + if [ $(git diff | wc -l) -ne 0 ]; then + echo -e "\nError! CMake code not formatted. Run cmake-format...\n" + echo -e "\nFiles:\n" + git diff --name-only + echo -e "\nFull diff:\n" + git diff + exit 1 + fi + + - name: Create pull request + if: failure() + uses: peter-evans/create-pull-request@v5 + with: + commit-message: "cmake formatting (cmake-format)" + branch: ${{ steps.extract_branch.outputs.branch }}-cmake-format + delete-branch: true + title: "Format cmake code (via cmake-format) on ${{ steps.extract_branch.outputs.branch }}" + base: ${{ steps.extract_branch.outputs.branch }} + + source: + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v3 + + - name: Install dependencies + run: | + DISTRIB_CODENAME=$(cat /etc/lsb-release | grep DISTRIB_CODENAME | awk -F '=' '{print $NF}') + sudo apt-get update + sudo apt-get install -y software-properties-common wget curl clang-format-11 + + - name: Extract branch name + shell: bash + run: | + echo "branch=${GITHUB_HEAD_REF:-${GITHUB_HEAD_REF#refs/heads/}}" >> $GITHUB_OUTPUT + id: extract_branch + + - name: Run clang-format + run: | + set +e + FILES=$(find samples source tests -type f | egrep '\.(h|hpp|hh|c|cc|cpp)(|\.in)$') + FORMAT_OUT=$(clang-format-11 -i ${FILES}) + if [ $(git diff | wc -l) -ne 0 ]; then + echo -e "\nError! Code not formatted. Run clang-format (version 11)...\n" + echo -e "\nFiles:\n" + git diff --name-only + echo -e "\nFull diff:\n" + git diff + exit 1 + fi + + - name: Create pull request + if: failure() + uses: peter-evans/create-pull-request@v5 + with: + commit-message: "source formatting (clang-format v11)" + branch: ${{ steps.extract_branch.outputs.branch }}-clang-format + delete-branch: true + title: "Format source code (via clang-format v11) on ${{ steps.extract_branch.outputs.branch }}" + base: ${{ steps.extract_branch.outputs.branch }} + + python: + runs-on: ubuntu-22.04 + strategy: + matrix: + python-version: ['3.10'] + + steps: + - uses: actions/checkout@v3 + + - name: Extract branch name + shell: bash + run: | + echo "branch=${GITHUB_HEAD_REF:-${GITHUB_HEAD_REF#refs/heads/}}" >> $GITHUB_OUTPUT + id: extract_branch + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install black + + - name: black format + run: | + black . + if [ $(git diff | wc -l) -ne 0 ]; then + echo -e "\nError! Python code not formatted. Run black...\n" + echo -e "\nFiles:\n" + git diff --name-only + echo -e "\nFull diff:\n" + git diff + exit 1 + fi + + - name: Create pull request + if: failure() + uses: peter-evans/create-pull-request@v5 + with: + commit-message: "python formatting (black)" + branch: ${{ steps.extract_branch.outputs.branch }}-python-format + delete-branch: true + title: "Format python code (via black) on ${{ steps.extract_branch.outputs.branch }}" + base: ${{ steps.extract_branch.outputs.branch }} diff --git a/.gitignore b/.gitignore index 259148fa18..ff0a008fec 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,7 @@ *.exe *.out *.app + +# Build directories +/build* +/.cache diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..ef4e70fe66 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,110 @@ +cmake_minimum_required(VERSION 3.16 FATAL_ERROR) + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR AND CMAKE_CURRENT_SOURCE_DIR STREQUAL + CMAKE_SOURCE_DIR) + set(MSG "") + message(STATUS "Warning! Building from the source directory is not recommended") + message(STATUS "If unintended, please remove 'CMakeCache.txt' and 'CMakeFiles'") + message(STATUS "and build from a separate directory") + message(AUTHOR_WARNING "In-source build") +endif() + +file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" FULL_VERSION_STRING LIMIT_COUNT 1) +string(REGEX REPLACE "(\n|\r)" "" FULL_VERSION_STRING "${FULL_VERSION_STRING}") +string(REGEX REPLACE "([0-9]+)\.([0-9]+)\.([0-9]+)(.*)" "\\1.\\2.\\3" + ROCPROFILER_REGISTER_VERSION "${FULL_VERSION_STRING}") + +foreach(_LANG C CXX) + set(CMAKE_${_LANG}_FLAGS_COVERAGE_INIT + "-Og -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-inline-functions -fprofile-abs-path -fprofile-arcs -ftest-coverage --coverage" + CACHE STRING "${_LANG} flags for code coverage builds") + + set(CMAKE_${_LANG}_FLAGS_COVERAGE + "${CMAKE_${_LANG}_FLAGS_COVERAGE_INIT}" + CACHE STRING "${_LANG} flags for code coverage builds") +endforeach() + +project( + rocprofiler-register + LANGUAGES C CXX + VERSION ${ROCPROFILER_REGISTER_VERSION} + DESCRIPTION "Registration library for rocprofiler" + HOMEPAGE_URL "https://github.com/ROCm-Developer-Tools/rocprofiler-register-internal") + +# needed for modulefile and setup-env.sh +string(REPLACE "-" "_" PROJECT_NAME_UNDERSCORED "${PROJECT_NAME}") + +find_package(Git) + +if(Git_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags + OUTPUT_VARIABLE ROCPROFILER_REGISTER_GIT_DESCRIBE + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE _GIT_DESCRIBE_RESULT + ERROR_QUIET) + + if(NOT _GIT_DESCRIBE_RESULT EQUAL 0) + execute_process( + COMMAND ${GIT_EXECUTABLE} describe + OUTPUT_VARIABLE ROCPROFILER_REGISTER_GIT_DESCRIBE + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE _GIT_DESCRIBE_RESULT + ERROR_QUIET) + endif() + + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse HEAD + OUTPUT_VARIABLE ROCPROFILER_REGISTER_GIT_REVISION + OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) +else() + set(ROCPROFILER_REGISTER_GIT_DESCRIBE "v${ROCPROFILER_REGISTER_VERSION}") + set(ROCPROFILER_REGISTER_GIT_REVISION "") +endif() + +message( + STATUS + "[${PROJECT_NAME}] version ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} (${FULL_VERSION_STRING})" + ) +message(STATUS "[${PROJECT_NAME}] git revision: ${ROCPROFILER_REGISTER_GIT_REVISION}") +message(STATUS "[${PROJECT_NAME}] git describe: ${ROCPROFILER_REGISTER_GIT_DESCRIBE}") +set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ${PROJECT_SOURCE_DIR}/cmake/Modules + ${CMAKE_MODULE_PATH}) + +include(GNUInstallDirs) # install directories + +include(rocprofiler_register_utilities) # various functions/macros +include(rocprofiler_register_interfaces) # interface libraries +include(rocprofiler_register_compilers) # compiler identification +include(rocprofiler_register_options) # project options +include(rocprofiler_register_build_settings) # build flags +include(rocprofiler_register_formatting) # formatting +include(rocprofiler_register_linting) # clang-tidy +include(rocprofiler_register_config_interfaces) # configure interface libraries + +set(CMAKE_C_VISIBILITY_PRESET "hidden") +set(CMAKE_CXX_VISIBILITY_PRESET "hidden") +set(CMAKE_VISIBILITY_INLINES_HIDDEN OFF) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") + +enable_testing() +include(CTest) + +add_subdirectory(source) + +if(ROCPROFILER_REGISTER_BUILD_TESTS) + add_subdirectory(tests) +endif() + +if(ROCPROFILER_REGISTER_BUILD_SAMPLES) + add_subdirectory(samples) +endif() + +# +include(rocprofiler_register_config_install) +include(rocprofiler_register_config_packaging) + +rocprofiler_register_print_features() diff --git a/VERSION b/VERSION new file mode 100644 index 0000000000..6e8bf73aa5 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1.0 diff --git a/cmake/Templates/modulefile.in b/cmake/Templates/modulefile.in new file mode 100644 index 0000000000..4b335a160e --- /dev/null +++ b/cmake/Templates/modulefile.in @@ -0,0 +1,16 @@ +#%Module1.0 + +module-whatis "@PROJECT_NAME_UNDERSCORED@ (version @PROJECT_VERSION@)" + +proc ModulesHelp { } { +puts stderr "Loads @PROJECT_NAME_UNDERSCORED@ v@PROJECT_VERSION@" +} + +set ROOT [file normalize [file dirname [file normalize ${ModulesCurrentModulefile}]]/../../..] + +setenv @PROJECT_NAME_UNDERSCORED@_ROOT "${ROOT}" +prepend-path CMAKE_PREFIX_PATH "${ROOT}" +prepend-path PATH "${ROOT}/bin" +prepend-path LD_LIBRARY_PATH "${ROOT}/@CMAKE_INSTALL_LIBDIR@" +prepend-path PYTHONPATH "${ROOT}/@CMAKE_INSTALL_PYTHONDIR@" +setenv @PROJECT_NAME_UNDERSCORED@_DIR "${ROOT}/@CMAKE_INSTALL_DATAROOTDIR@/cmake/@PROJECT_NAME_UNDERSCORED@" diff --git a/cmake/Templates/rocprofiler-register-config.cmake.in b/cmake/Templates/rocprofiler-register-config.cmake.in new file mode 100644 index 0000000000..db66aafc06 --- /dev/null +++ b/cmake/Templates/rocprofiler-register-config.cmake.in @@ -0,0 +1,32 @@ +# - Config file for @PROJECT_NAME@ and its component libraries +# It defines the following variables: +# +# @PROJECT_NAME@_INCLUDE_DIRS +# @PROJECT_NAME@_LIBRARIES +# @PROJECT_NAME@_INTERNAL_DEFINES - used by the test suite + +# compute paths +get_filename_component(@PROJECT_NAME@_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) + +# version +include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-version.cmake) + +@PACKAGE_INIT@ + +set_and_check(@PROJECT_NAME@_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +set_and_check(@PROJECT_NAME@_LIB_DIR "@PACKAGE_LIB_INSTALL_DIR@") +get_filename_component(@PROJECT_NAME@_ROOT_DIR ${@PROJECT_NAME@_INCLUDE_DIR} PATH) + +include("${@PROJECT_NAME@_CMAKE_DIR}/@PROJECT_NAME@-library-targets.cmake") + +if(TARGET @PROJECT_NAME@::@PROJECT_NAME@) + set(@PROJECT_NAME@_LIBRARIES @PROJECT_NAME@::@PROJECT_NAME@) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + @PROJECT_NAME@ + FOUND_VAR @PROJECT_NAME@_FOUND + REQUIRED_VARS @PROJECT_NAME@_ROOT_DIR @PROJECT_NAME@_INCLUDE_DIR @PROJECT_NAME@_LIBRARIES + VERSION_VAR @PROJECT_NAME@_VERSION + HANDLE_COMPONENTS) diff --git a/cmake/Templates/setup-env.sh.in b/cmake/Templates/setup-env.sh.in new file mode 100644 index 0000000000..b6e449a582 --- /dev/null +++ b/cmake/Templates/setup-env.sh.in @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +BASEDIR=$(dirname ${BASH_SOURCE[0]}) +command -v realpath &> /dev/null && BASEDIR=$(realpath ${BASEDIR}/../..) || BASEDIR=$(cd ${BASEDIR}/../.. && pwd) + +if [ ! -d "${BASEDIR}" ]; then + echo "${BASEDIR} does not exist" + return 1 +fi + +@PROJECT_NAME_UNDERSCORED@_ROOT=${BASEDIR} +PATH=${BASEDIR}/bin:${PATH} +LD_LIBRARY_PATH=${BASEDIR}/@CMAKE_INSTALL_LIBDIR@:${LD_LIBRARY_PATH} +PYTHONPATH=${BASEDIR}/@CMAKE_INSTALL_PYTHONDIR@:${PYTHONPATH} +CMAKE_PREFIX_PATH=${BASEDIR}:${CMAKE_PREFIX_PATH} +@PROJECT_NAME_UNDERSCORED@_DIR=${BASEDIR}/@CMAKE_INSTALL_DATAROOTDIR@/cmake/@PROJECT_NAME_UNDERSCORED@ + +export @PROJECT_NAME_UNDERSCORED@_ROOT +export PATH +export LD_LIBRARY_PATH +export PYTHONPATH +export CMAKE_PREFIX_PATH +export @PROJECT_NAME_UNDERSCORED@_DIR diff --git a/cmake/rocprofiler_register_build_settings.cmake b/cmake/rocprofiler_register_build_settings.cmake new file mode 100644 index 0000000000..1d37776157 --- /dev/null +++ b/cmake/rocprofiler_register_build_settings.cmake @@ -0,0 +1,107 @@ +# ######################################################################################## +# +# Handles the build settings +# +# ######################################################################################## + +include_guard(DIRECTORY) + +include(GNUInstallDirs) +include(FindPackageHandleStandardArgs) +include(rocprofiler_register_compilers) +include(rocprofiler_register_utilities) + +target_compile_definitions(rocprofiler-register-build-flags + INTERFACE $<$:DEBUG>) + +if(ROCPROFILER_REGISTER_BUILD_CI) + rocprofiler_register_target_compile_definitions(rocprofiler-register-build-flags + INTERFACE ROCPROFILER_REGISTER_CI) +endif() + +# ----------------------------------------------------------------------------------------# +# dynamic linking and runtime libraries +# +if(CMAKE_DL_LIBS AND NOT "${CMAKE_DL_LIBS}" STREQUAL "dl") + # if cmake provides dl library, use that + set(dl_LIBRARY + ${CMAKE_DL_LIBS} + CACHE FILEPATH "dynamic linking system library") +endif() + +foreach(_TYPE dl rt) + if(NOT ${_TYPE}_LIBRARY) + find_library(${_TYPE}_LIBRARY NAMES ${_TYPE}) + find_package_handle_standard_args(${_TYPE}-library REQUIRED_VARS ${_TYPE}_LIBRARY) + if(${_TYPE}-library_FOUND) + string(TOUPPER "${_TYPE}" _TYPE_UC) + rocprofiler_register_target_compile_definitions( + rocprofiler-register-${_TYPE} + INTERFACE ROCPROFILER_REGISTER_${_TYPE_UC}=1) + target_link_libraries(rocprofiler-register-${_TYPE} + INTERFACE ${${_TYPE}_LIBRARY}) + if("${_TYPE}" STREQUAL "dl" AND NOT ROCPROFILER_REGISTER_ENABLE_CLANG_TIDY) + # This instructs the linker to add all symbols, not only used ones, to the + # dynamic symbol table. This option is needed for some uses of dlopen or + # to allow obtaining backtraces from within a program. + rocprofiler_register_target_compile_options( + rocprofiler-register-${_TYPE} + LANGUAGES C CXX + LINK_LANGUAGES C CXX + INTERFACE "-rdynamic") + endif() + else() + rocprofiler_register_target_compile_definitions( + rocprofiler-register-${_TYPE} + INTERFACE ROCPROFILER_REGISTER_${_TYPE_UC}=0) + endif() + endif() +endforeach() + +target_link_libraries(rocprofiler-register-build-flags INTERFACE rocprofiler-register::dl) + +# ----------------------------------------------------------------------------------------# +# set the compiler flags +# +rocprofiler_register_target_compile_options( + rocprofiler-register-build-flags + INTERFACE "-W" "-Wall" "-Wno-unknown-pragmas" "-fstack-protector-strong" + "-Wstack-protector") + +# ----------------------------------------------------------------------------------------# +# debug-safe optimizations +# +rocprofiler_register_target_compile_options( + rocprofiler-register-build-flags + LANGUAGES CXX + INTERFACE "-faligned-new") + +# ----------------------------------------------------------------------------------------# +# developer build flags +# +rocprofiler_register_target_compile_options( + rocprofiler-register-developer-flags + LANGUAGES C CXX + INTERFACE "-Werror" "-Wdouble-promotion" "-Wshadow" "-Wextra") + +if(NOT ROCPROFILER_REGISTER_ENABLE_CLANG_TIDY) + rocprofiler_register_target_compile_options( + rocprofiler-register-developer-flags + LANGUAGES C CXX + INTERFACE "-Wstack-usage=524288" # 512 KB + ) +endif() + +if(ROCPROFILER_REGISTER_BUILD_DEVELOPER) + target_link_libraries(rocprofiler-register-build-flags + INTERFACE rocprofiler-register::developer-flags) +endif() + +# ----------------------------------------------------------------------------------------# +# user customization +# +get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) + +if(NOT APPLE OR "$ENV{CONDA_PYTHON_EXE}" STREQUAL "") + rocprofiler_register_target_user_flags(rocprofiler-register-build-flags "CXX") +endif() diff --git a/cmake/rocprofiler_register_compilers.cmake b/cmake/rocprofiler_register_compilers.cmake new file mode 100644 index 0000000000..f3c3fb7414 --- /dev/null +++ b/cmake/rocprofiler_register_compilers.cmake @@ -0,0 +1,352 @@ +# include guard +# ######################################################################################## +# +# Compilers +# +# ######################################################################################## +# +# sets (cached): +# +# CMAKE_C_COMPILER_IS_ CMAKE_CXX_COMPILER_IS_ +# +# where TYPE is: - GNU - CLANG - INTEL - INTEL_ICC - INTEL_ICPC - PGI - XLC - HP_ACC - +# MIPS - MSVC +# + +include(CheckCCompilerFlag) +include(CheckCSourceCompiles) +include(CheckCSourceRuns) + +include(CheckCXXCompilerFlag) +include(CheckCXXSourceCompiles) +include(CheckCXXSourceRuns) + +include(CMakeParseArguments) + +include(rocprofiler_register_utilities) + +# ----------------------------------------------------------------------------------------# +# macro converting string to list +# ----------------------------------------------------------------------------------------# +macro(ROCPROFILER_REGISTER_TO_LIST _VAR _STR) + string(REPLACE " " " " ${_VAR} "${_STR}") + string(REPLACE " " ";" ${_VAR} "${_STR}") +endmacro() + +# ----------------------------------------------------------------------------------------# +# macro converting string to list +# ----------------------------------------------------------------------------------------# +macro(ROCPROFILER_REGISTER_TO_STRING _VAR _STR) + string(REPLACE ";" " " ${_VAR} "${_STR}") +endmacro() + +# ----------------------------------------------------------------------------------------# +# Macro to add to string +# ----------------------------------------------------------------------------------------# +macro(add _VAR _FLAG) + if(NOT "${_FLAG}" STREQUAL "") + if("${${_VAR}}" STREQUAL "") + set(${_VAR} "${_FLAG}") + else() + set(${_VAR} "${${_VAR}} ${_FLAG}") + endif() + endif() +endmacro() + +# ----------------------------------------------------------------------------------------# +# call before running check_{c,cxx}_compiler_flag +# ----------------------------------------------------------------------------------------# +macro(ROCPROFILER_REGISTER_BEGIN_FLAG_CHECK) + if(ROCPROFILER_REGISTER_QUIET_CONFIG) + if(NOT DEFINED CMAKE_REQUIRED_QUIET) + set(CMAKE_REQUIRED_QUIET OFF) + endif() + rocprofiler_register_save_variables(FLAG_CHECK VARIABLES CMAKE_REQUIRED_QUIET) + set(CMAKE_REQUIRED_QUIET ON) + endif() +endmacro() + +# ----------------------------------------------------------------------------------------# +# call after running check_{c,cxx}_compiler_flag +# ----------------------------------------------------------------------------------------# +macro(ROCPROFILER_REGISTER_END_FLAG_CHECK) + if(ROCPROFILER_REGISTER_QUIET_CONFIG) + rocprofiler_register_restore_variables(FLAG_CHECK VARIABLES CMAKE_REQUIRED_QUIET) + endif() +endmacro() + +# ----------------------------------------------------------------------------------------# +# check flag +# ----------------------------------------------------------------------------------------# +function(ROCPROFILER_REGISTER_TARGET_COMPILE_OPTIONS _TARG_TARGET) + cmake_parse_arguments(_TARG "BUILD_INTERFACE;FORCE" "" + "PUBLIC;INTERFACE;PRIVATE;LANGUAGES;LINK_LANGUAGES" ${ARGN}) + + if(NOT _TARG_MODE) + set(_TARG_MODE INTERFACE) + endif() + + get_property(_ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) + set(_SUPPORTED_LANGUAGES "C" "CXX") + + if(NOT _TARG_LANGUAGES) + foreach(_LANG ${_ENABLED_LANGUAGES}) + if(_LANG IN_LIST _SUPPORTED_LANGUAGES) + list(APPEND _TARG_LANGUAGES ${_LANG}) + endif() + endforeach() + endif() + + string(TOLOWER "_${_TARG_TARGET}" _TARG_TARGET_LC) + + function(rocprofiler_register_target_compile_option_impl _TARGET_IMPL + _TARGET_MODE_IMPL _TARGET_LANG_IMPL _TARGET_FLAG_IMPL) + if(_TARG_BUILD_INTERFACE) + target_compile_options( + ${_TARGET_IMPL} + ${_TARGET_MODE_IMPL} + $:${_TARGET_FLAG_IMPL}>> + ) + else() + target_compile_options( + ${_TARGET_IMPL} ${_TARGET_MODE_IMPL} + $<$:${_TARGET_FLAG_IMPL}>) + endif() + + if("${_TARGET_LANG_IMPL}" IN_LIST _TARG_LINK_LANGUAGES) + if(_TARG_BUILD_INTERFACE) + target_link_options( + ${_TARGET_IMPL} + ${_TARGET_MODE_IMPL} + $:${_TARGET_FLAG_IMPL}>> + ) + else() + target_link_options( + ${_TARGET_IMPL} ${_TARGET_MODE_IMPL} + $<$:${_TARGET_FLAG_IMPL}>) + endif() + endif() + endfunction() + + function(rocprofiler_register_target_compile_option_patch_name _P_LANG _P_IN _P_OUT) + string(TOLOWER "${_P_LANG}" _P_LANG) + string(REGEX REPLACE "^(/|-)" "${_P_LANG}${_TARG_TARGET_LC}_" _NAME "${_P_IN}") + string(REPLACE "-" "_" _NAME "${_NAME}") + string(REPLACE " " "_" _NAME "${_NAME}") + string(REPLACE "=" "_" _NAME "${_NAME}") + set(${_P_OUT} + "${_NAME}" + PARENT_SCOPE) + endfunction() + + if(NOT DEFINED rocprofiler_register_c_error AND NOT DEFINED + rocprofiler_register_cxx_error) + rocprofiler_register_begin_flag_check() + check_c_compiler_flag("-Werror" c_rocprofiler_register_werror) + check_cxx_compiler_flag("-Werror" cxx_rocprofiler_register_werror) + rocprofiler_register_end_flag_check() + endif() + + foreach(_TARG_MODE PUBLIC INTERFACE PRIVATE) + foreach(_FLAG ${_TARG_${_TARG_MODE}}) + foreach(_LANG ${_TARG_LANGUAGES}) + unset(FLAG_NAME) + rocprofiler_register_target_compile_option_patch_name(${_LANG} "${_FLAG}" + FLAG_NAME) + + if(_TARG_FORCE) + set(${FLAG_NAME} + 1 + CACHE INTERNAL "${_LANG} flag: ${_FLAG}") + else() + rocprofiler_register_begin_flag_check() + + if("${_LANG}" STREQUAL "C") + if(c_rocprofiler_register_werror) + check_c_compiler_flag("${_FLAG} -Werror" ${FLAG_NAME}) + else() + check_c_compiler_flag("${_FLAG}" ${FLAG_NAME}) + endif() + elseif("${_LANG}" STREQUAL "CXX") + if(cxx_rocprofiler_register_werror) + check_cxx_compiler_flag("${_FLAG} -Werror" ${FLAG_NAME}) + else() + check_cxx_compiler_flag("${_FLAG}" ${FLAG_NAME}) + endif() + else() + message( + FATAL_ERROR + "rocprofiler_register_target_compile_option :: unknown language: ${_LANG}" + ) + endif() + + rocprofiler_register_end_flag_check() + endif() + + if(${FLAG_NAME}) + rocprofiler_register_target_compile_option_impl( + ${_TARG_TARGET} ${_TARG_MODE} ${_LANG} "${_FLAG}") + endif() + endforeach() + endforeach() + endforeach() +endfunction() + +# ----------------------------------------------------------------------------------------# +# add to any language +# ----------------------------------------------------------------------------------------# +function(ROCPROFILER_REGISTER_TARGET_USER_FLAGS _TARGET _LANGUAGE) + + set(_FLAGS ${${_LANGUAGE}FLAGS} $ENV{${_LANGUAGE}FLAGS} ${${_LANGUAGE}_FLAGS} + $ENV{${_LANGUAGE}_FLAGS}) + + string(REPLACE " " ";" _FLAGS "${_FLAGS}") + + set(${PROJECT_NAME}_${_LANGUAGE}_FLAGS + ${${PROJECT_NAME}_${_LANGUAGE}_FLAGS} ${_FLAGS} + PARENT_SCOPE) + + set(${PROJECT_NAME}_${_LANGUAGE}_COMPILE_OPTIONS + ${${PROJECT_NAME}_${_LANGUAGE}_COMPILE_OPTIONS} ${_FLAGS} + PARENT_SCOPE) + + target_compile_options(${_TARGET} + INTERFACE $<$:${_FLAGS}>) +endfunction() + +# ----------------------------------------------------------------------------------------# +# add compiler definition +# ----------------------------------------------------------------------------------------# +function(ROCPROFILER_REGISTER_TARGET_COMPILE_DEFINITIONS _TARG _VIS) + foreach(_DEF ${ARGN}) + if(NOT "${_DEF}" MATCHES "[A-Za-z_]+=.*" AND "${_DEF}" MATCHES + "^ROCPROFILER_REGISTER_") + set(_DEF "${_DEF}=1") + endif() + target_compile_definitions(${_TARG} ${_VIS} $<$:${_DEF}>) + endforeach() +endfunction() + +# ----------------------------------------------------------------------------------------# +# determine compiler types for each language +# ----------------------------------------------------------------------------------------# +get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(LANG C CXX HIP CUDA) + + if(NOT DEFINED CMAKE_${LANG}_COMPILER) + set(CMAKE_${LANG}_COMPILER "") + endif() + + if(NOT DEFINED CMAKE_${LANG}_COMPILER_ID) + set(CMAKE_${LANG}_COMPILER_ID "") + endif() + + function(SET_COMPILER_VAR VAR _BOOL) + set(CMAKE_${LANG}_COMPILER_IS_${VAR} + ${_BOOL} + CACHE INTERNAL "CMake ${LANG} compiler identification (${VAR})" FORCE) + mark_as_advanced(CMAKE_${LANG}_COMPILER_IS_${VAR}) + endfunction() + + if(("${LANG}" STREQUAL "C" AND CMAKE_COMPILER_IS_GNUCC) + OR ("${LANG}" STREQUAL "CXX" AND CMAKE_COMPILER_IS_GNUCXX)) + + # GNU compiler + set_compiler_var(GNU 1) + + elseif(CMAKE_${LANG}_COMPILER MATCHES "icc.*") + + # Intel icc compiler + set_compiler_var(INTEL 1) + set_compiler_var(INTEL_ICC 1) + + elseif(CMAKE_${LANG}_COMPILER MATCHES "icpc.*") + + # Intel icpc compiler + set_compiler_var(INTEL 1) + set_compiler_var(INTEL_ICPC 1) + + elseif(CMAKE_${LANG}_COMPILER_ID MATCHES "AppleClang") + + # Clang/LLVM compiler + set_compiler_var(CLANG 1) + set_compiler_var(APPLE_CLANG 1) + + elseif(CMAKE_${LANG}_COMPILER_ID MATCHES "Clang") + + # Clang/LLVM compiler + set_compiler_var(CLANG 1) + + # HIP Clang compiler + if(CMAKE_${LANG}_COMPILER MATCHES "hipcc") + set_compiler_var(HIPCC 1) + endif() + + elseif(CMAKE_${LANG}_COMPILER_ID MATCHES "PGI") + + # PGI compiler + set_compiler_var(PGI 1) + + elseif(CMAKE_${LANG}_COMPILER MATCHES "xlC" AND UNIX) + + # IBM xlC compiler + set_compiler_var(XLC 1) + + elseif(CMAKE_${LANG}_COMPILER MATCHES "aCC" AND UNIX) + + # HP aC++ compiler + set_compiler_var(HP_ACC 1) + + elseif( + CMAKE_${LANG}_COMPILER MATCHES "CC" + AND CMAKE_SYSTEM_NAME MATCHES "IRIX" + AND UNIX) + + # IRIX MIPSpro CC Compiler + set_compiler_var(MIPS 1) + + elseif(CMAKE_${LANG}_COMPILER_ID MATCHES "Intel") + + set_compiler_var(INTEL 1) + + set(CTYPE ICC) + if("${LANG}" STREQUAL "CXX") + set(CTYPE ICPC) + endif() + + set_compiler_var(INTEL_${CTYPE} 1) + + elseif(CMAKE_${LANG}_COMPILER MATCHES "MSVC") + + # Windows Visual Studio compiler + set_compiler_var(MSVC 1) + + elseif(CMAKE_${LANG}_COMPILER_ID MATCHES "NVIDIA") + + # NVCC + set_compiler_var(NVIDIA 1) + + endif() + + # set other to no + foreach( + TYPE + GNU + INTEL + INTEL_ICC + INTEL_ICPC + APPLE_CLANG + CLANG + PGI + XLC + HP_ACC + MIPS + MSVC + NVIDIA + HIPCC) + if(NOT DEFINED CMAKE_${LANG}_COMPILER_IS_${TYPE}) + set_compiler_var(${TYPE} 0) + endif() + endforeach() + +endforeach() diff --git a/cmake/rocprofiler_register_config_install.cmake b/cmake/rocprofiler_register_config_install.cmake new file mode 100644 index 0000000000..afa4e64c9a --- /dev/null +++ b/cmake/rocprofiler_register_config_install.cmake @@ -0,0 +1,87 @@ +# include guard +include_guard(GLOBAL) + +include(CMakePackageConfigHelpers) + +set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME config) + +install( + EXPORT rocprofiler-register-library-targets + FILE rocprofiler-register-library-targets.cmake + NAMESPACE rocprofiler-register:: + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/rocprofiler-register) + +configure_file( + ${PROJECT_SOURCE_DIR}/cmake/Templates/setup-env.sh.in + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/setup-env.sh @ONLY) + +configure_file( + ${PROJECT_SOURCE_DIR}/cmake/Templates/modulefile.in + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/modulefiles/${PROJECT_NAME}/${PROJECT_VERSION} + @ONLY) + +install( + FILES ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/setup-env.sh + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME} + COMPONENT setup) + +install( + FILES + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/modulefiles/${PROJECT_NAME}/${PROJECT_VERSION} + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/modulefiles/${PROJECT_NAME} + COMPONENT setup) + +# ------------------------------------------------------------------------------# +# install tree +# +set(PROJECT_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}) +set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}) +set(LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}) + +configure_package_config_file( + ${PROJECT_SOURCE_DIR}/cmake/Templates/${PROJECT_NAME}-config.cmake.in + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/rocprofiler-register + INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} + PATH_VARS PROJECT_INSTALL_DIR INCLUDE_INSTALL_DIR LIB_INSTALL_DIR) + +write_basic_package_version_file( + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-version.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMinorVersion) + +install( + FILES + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-config.cmake + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-version.cmake + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME} + OPTIONAL) + +export(PACKAGE ${PROJECT_NAME}) + +# ------------------------------------------------------------------------------# +# build tree +# +set(_BUILDTREE_EXPORT_DIR + "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/cmake/rocprofiler-register") + +if(NOT EXISTS "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +endif() + +if(NOT EXISTS "${_BUILDTREE_EXPORT_DIR}") + file(MAKE_DIRECTORY "${_BUILDTREE_EXPORT_DIR}") +endif() + +if(NOT EXISTS "${_BUILDTREE_EXPORT_DIR}/rocprofiler-register-library-targets.cmake") + file(TOUCH "${_BUILDTREE_EXPORT_DIR}/rocprofiler-register-library-targets.cmake") +endif() + +export( + EXPORT rocprofiler-register-library-targets + NAMESPACE rocprofiler-register:: + FILE "${_BUILDTREE_EXPORT_DIR}/rocprofiler-register-library-targets.cmake") + +set(rocprofiler_register_DIR + "${_BUILDTREE_EXPORT_DIR}" + CACHE PATH "rocprofiler-register" FORCE) diff --git a/cmake/rocprofiler_register_config_interfaces.cmake b/cmake/rocprofiler_register_config_interfaces.cmake new file mode 100644 index 0000000000..5f7a2e1e72 --- /dev/null +++ b/cmake/rocprofiler_register_config_interfaces.cmake @@ -0,0 +1,67 @@ +# include guard +include_guard(DIRECTORY) + +# ######################################################################################## +# +# External Packages are found here +# +# ######################################################################################## + +target_include_directories( + rocprofiler-register-headers + INTERFACE $ + $ + $ + $) + +# ensure the env overrides the appending /opt/rocm later +string(REPLACE ":" ";" CMAKE_PREFIX_PATH "$ENV{CMAKE_PREFIX_PATH};${CMAKE_PREFIX_PATH}") + +# ----------------------------------------------------------------------------------------# +# +# Threading +# +# ----------------------------------------------------------------------------------------# + +set(CMAKE_THREAD_PREFER_PTHREAD ON) +set(THREADS_PREFER_PTHREAD_FLAG OFF) + +find_package(Threads ${rocprofiler_register_FIND_QUIETLY} + ${rocprofiler_register_FIND_REQUIREMENT}) +if(Threads_FOUND) + target_link_libraries(rocprofiler-register-threading + INTERFACE $) +endif() + +# ----------------------------------------------------------------------------------------# +# +# dynamic linking (dl) and runtime (rt) libraries +# +# ----------------------------------------------------------------------------------------# + +foreach(_LIB dl rt) + find_library(${_LIB}_LIBRARY NAMES ${_LIB}) + find_package_handle_standard_args(${_LIB}-library REQUIRED_VARS ${_LIB}_LIBRARY) + if(${_LIB}_LIBRARY) + target_link_libraries( + rocprofiler-register-${_LIB} INTERFACE $ + $) + endif() +endforeach() + +# ----------------------------------------------------------------------------------------# +# +# stdc++fs (filesystem) library +# +# ----------------------------------------------------------------------------------------# + +find_library(stdcxxfs_LIBRARY NAMES stdc++fs) +find_package_handle_standard_args(stdcxxfs-library REQUIRED_VARS stdcxxfs_LIBRARY) + +if(stdcxxfs_LIBRARY) + target_link_libraries(rocprofiler-register-stdcxxfs + INTERFACE $) +else() + target_link_libraries(rocprofiler-register-stdcxxfs + INTERFACE $) +endif() diff --git a/cmake/rocprofiler_register_config_packaging.cmake b/cmake/rocprofiler_register_config_packaging.cmake new file mode 100644 index 0000000000..4e13119443 --- /dev/null +++ b/cmake/rocprofiler_register_config_packaging.cmake @@ -0,0 +1,100 @@ +# configure packaging + +# Add packaging directives +set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) +set(CPACK_PACKAGE_VENDOR "Advanced Micro Devices, Inc.") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_DESCRIPTION}") +set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") +set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") +set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") +set(CPACK_PACKAGE_CONTACT "jonathan.madsen@amd.com") +set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") +set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF) +set(ROCPROFILER_REGISTER_CPACK_SYSTEM_NAME + "${CMAKE_SYSTEM_NAME}" + CACHE STRING "System name, e.g. Linux or -") +set(ROCPROFILER_REGISTER_CPACK_PACKAGE_SUFFIX + "" + CACHE STRING "Package suffix") + +set(CPACK_PACKAGE_FILE_NAME + "${CPACK_PACKAGE_NAME}-${ROCPROFILER_REGISTER_VERSION}-${ROCPROFILER_REGISTER_CPACK_SYSTEM_NAME}${ROCPROFILER_REGISTER_CPACK_PACKAGE_SUFFIX}" + ) +if(DEFINED ENV{CPACK_PACKAGE_FILE_NAME}) + set(CPACK_PACKAGE_FILE_NAME $ENV{CPACK_PACKAGE_FILE_NAME}) +endif() + +set(ROCPROFILER_REGISTER_PACKAGE_FILE_NAME + ${CPACK_PACKAGE_NAME}-${ROCPROFILER_REGISTER_VERSION}-${ROCPROFILER_REGISTER_CPACK_SYSTEM_NAME}${ROCPROFILER_REGISTER_CPACK_PACKAGE_SUFFIX} + ) +rocprofiler_register_add_feature(ROCPROFILER_REGISTER_PACKAGE_FILE_NAME "CPack filename") + +# -------------------------------------------------------------------------------------- # +# +# Debian package specific variables +# +# -------------------------------------------------------------------------------------- # + +set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "${PROJECT_HOMEPAGE_URL}") +set(CPACK_DEBIAN_PACKAGE_RELEASE + "${ROCPROFILER_REGISTER_CPACK_SYSTEM_NAME}${ROCPROFILER_REGISTER_CPACK_PACKAGE_SUFFIX}" + ) +string(REGEX REPLACE "([a-zA-Z])-([0-9])" "\\1\\2" CPACK_DEBIAN_PACKAGE_RELEASE + "${CPACK_DEBIAN_PACKAGE_RELEASE}") +string(REPLACE "-" "~" CPACK_DEBIAN_PACKAGE_RELEASE "${CPACK_DEBIAN_PACKAGE_RELEASE}") +if(DEFINED ENV{CPACK_DEBIAN_PACKAGE_RELEASE}) + set(CPACK_DEBIAN_PACKAGE_RELEASE $ENV{CPACK_DEBIAN_PACKAGE_RELEASE}) +endif() + +set(_DEBIAN_PACKAGE_DEPENDS "") +if(rocm_version_FOUND) + set(_ROCPROFILER_REGISTER_SUFFIX " (>= 1.0.0.${rocm_version_NUMERIC_VERSION})") + set(_ROCTRACER_SUFFIX " (>= 1.0.0.${rocm_version_NUMERIC_VERSION})") + set(_ROCM_SMI_SUFFIX + " (>= ${rocm_version_MAJOR_VERSION}.0.0.${rocm_version_NUMERIC_VERSION})") +endif() +string(REPLACE ";" ", " _DEBIAN_PACKAGE_DEPENDS "${_DEBIAN_PACKAGE_DEPENDS}") +set(CPACK_DEBIAN_PACKAGE_DEPENDS + "${_DEBIAN_PACKAGE_DEPENDS}" + CACHE STRING "Debian package dependencies" FORCE) +rocprofiler_register_add_feature(CPACK_DEBIAN_PACKAGE_DEPENDS + "Debian package dependencies") +set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT") + +# -------------------------------------------------------------------------------------- # +# +# RPM package specific variables +# +# -------------------------------------------------------------------------------------- # + +if(DEFINED CPACK_PACKAGING_INSTALL_PREFIX) + set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${CPACK_PACKAGING_INSTALL_PREFIX}") +endif() + +set(CPACK_RPM_PACKAGE_RELEASE + "${ROCPROFILER_REGISTER_CPACK_SYSTEM_NAME}${ROCPROFILER_REGISTER_CPACK_PACKAGE_SUFFIX}" + ) +string(REGEX REPLACE "([a-zA-Z])-([0-9])" "\\1\\2" CPACK_RPM_PACKAGE_RELEASE + "${CPACK_RPM_PACKAGE_RELEASE}") +string(REPLACE "-" "~" CPACK_RPM_PACKAGE_RELEASE "${CPACK_RPM_PACKAGE_RELEASE}") +if(DEFINED ENV{CPACK_RPM_PACKAGE_RELEASE}) + set(CPACK_RPM_PACKAGE_RELEASE $ENV{CPACK_RPM_PACKAGE_RELEASE}) +endif() + +# Get rpm distro +if(CPACK_RPM_PACKAGE_RELEASE) + set(CPACK_RPM_PACKAGE_RELEASE_DIST ON) +endif() +set(CPACK_RPM_FILE_NAME "RPM-DEFAULT") + +# -------------------------------------------------------------------------------------- # +# +# Prepare final version for the CPACK use +# +# -------------------------------------------------------------------------------------- # + +set(CPACK_PACKAGE_VERSION + "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}" + ) + +include(CPack) diff --git a/cmake/rocprofiler_register_formatting.cmake b/cmake/rocprofiler_register_formatting.cmake new file mode 100644 index 0000000000..ffc23f0243 --- /dev/null +++ b/cmake/rocprofiler_register_formatting.cmake @@ -0,0 +1,104 @@ +# ------------------------------------------------------------------------------# +# +# creates following targets to format code: +# - format +# - format-source +# - format-cmake +# - format-python +# - format-rocprofiler-register-source +# - format-rocprofiler-register-cmake +# - format-rocprofiler-register-python +# +# ------------------------------------------------------------------------------# + +include_guard(DIRECTORY) + +find_program(ROCPROFILER_REGISTER_CLANG_FORMAT_EXE NAMES clang-format-11 + clang-format-mp-11) +find_program(ROCPROFILER_REGISTER_CMAKE_FORMAT_EXE NAMES cmake-format) +find_program(ROCPROFILER_REGISTER_BLACK_FORMAT_EXE NAMES black) + +add_custom_target(format-rocprofiler-register) +if(NOT TARGET format) + add_custom_target(format) +endif() +foreach(_TYPE source python cmake) + if(NOT TARGET format-${_TYPE}) + add_custom_target(format-${_TYPE}) + endif() +endforeach() + +if(ROCPROFILER_REGISTER_CLANG_FORMAT_EXE + OR ROCPROFILER_REGISTER_BLACK_FORMAT_EXE + OR ROCPROFILER_REGISTER_CMAKE_FORMAT_EXE) + + set(rocp_source_files) + set(rocp_header_files) + set(rocp_python_files) + set(rocp_cmake_files ${PROJECT_SOURCE_DIR}/CMakeLists.txt) + + foreach(_DIR cmake samples source tests) + foreach(_TYPE header_files source_files cmake_files python_files) + set(${_TYPE}) + endforeach() + file(GLOB_RECURSE header_files ${PROJECT_SOURCE_DIR}/${_DIR}/*.h + ${PROJECT_SOURCE_DIR}/${_DIR}/*.hpp) + file(GLOB_RECURSE source_files ${PROJECT_SOURCE_DIR}/${_DIR}/*.c + ${PROJECT_SOURCE_DIR}/${_DIR}/*.cpp) + file(GLOB_RECURSE cmake_files ${PROJECT_SOURCE_DIR}/${_DIR}/*CMakeLists.txt + ${PROJECT_SOURCE_DIR}/${_DIR}/*.cmake) + file(GLOB_RECURSE python_files ${PROJECT_SOURCE_DIR}/${_DIR}/*.py) + foreach(_TYPE header_files source_files cmake_files python_files) + list(APPEND rocp_${_TYPE} ${${_TYPE}}) + endforeach() + endforeach() + + foreach(_TYPE header_files source_files cmake_files python_files) + if(rocp_${_TYPE}) + list(REMOVE_DUPLICATES rocp_${_TYPE}) + list(SORT rocp_${_TYPE}) + endif() + endforeach() + + if(ROCPROFILER_REGISTER_CLANG_FORMAT_EXE AND (rocp_source_files OR rocp_header_files)) + add_custom_target( + format-rocprofiler-register-source + ${ROCPROFILER_REGISTER_CLANG_FORMAT_EXE} -i ${rocp_header_files} + ${rocp_source_files} + COMMENT + "[rocprofiler-register] Running source formatter ${ROCPROFILER_REGISTER_CLANG_FORMAT_EXE}..." + ) + endif() + + if(ROCPROFILER_REGISTER_BLACK_FORMAT_EXE AND rocp_python_files) + add_custom_target( + format-rocprofiler-register-python + ${ROCPROFILER_REGISTER_BLACK_FORMAT_EXE} -q ${rocp_python_files} + COMMENT + "[rocprofiler-register] Running Python formatter ${ROCPROFILER_REGISTER_BLACK_FORMAT_EXE}..." + ) + endif() + + if(ROCPROFILER_REGISTER_CMAKE_FORMAT_EXE AND rocp_cmake_files) + add_custom_target( + format-rocprofiler-register-cmake + ${ROCPROFILER_REGISTER_CMAKE_FORMAT_EXE} -i ${rocp_cmake_files} + COMMENT + "[rocprofiler-register] Running CMake formatter ${ROCPROFILER_REGISTER_CMAKE_FORMAT_EXE}..." + ) + endif() + + foreach(_TYPE source python cmake) + if(TARGET format-rocprofiler-register-${_TYPE}) + add_dependencies(format-rocprofiler-register + format-rocprofiler-register-${_TYPE}) + add_dependencies(format-${_TYPE} format-rocprofiler-register-${_TYPE}) + endif() + endforeach() + + foreach(_TYPE source python) + if(TARGET format-rocprofiler-register-${_TYPE}) + add_dependencies(format format-rocprofiler-register-${_TYPE}) + endif() + endforeach() +endif() diff --git a/cmake/rocprofiler_register_interfaces.cmake b/cmake/rocprofiler_register_interfaces.cmake new file mode 100644 index 0000000000..9bac2556dd --- /dev/null +++ b/cmake/rocprofiler_register_interfaces.cmake @@ -0,0 +1,34 @@ +# +# +# Forward declaration of all INTERFACE targets +# +# + +include(rocprofiler_register_utilities) + +# +# interfaces for build flags +# +rocprofiler_register_add_interface_library( + rocprofiler-register-headers + "Provides minimal set of include flags to compile with rocprofiler-register") +rocprofiler_register_add_interface_library( + rocprofiler-register-build-flags + "Provides generalized build flags for rocprofiler-register" INTERNAL) +rocprofiler_register_add_interface_library(rocprofiler-register-threading + "Enables multithreading support" INTERNAL) +rocprofiler_register_add_interface_library( + rocprofiler-register-developer-flags + "Compiler flags for developers (more warnings, etc.)" INTERNAL) +rocprofiler_register_add_interface_library(rocprofiler-register-memcheck "Sanitizer" + INTERNAL) + +# +# interfaces for libraries +# +rocprofiler_register_add_interface_library( + rocprofiler-register-dl "Build flags for dynamic linking library" INTERNAL) +rocprofiler_register_add_interface_library(rocprofiler-register-rt + "Build flags for runtime library" INTERNAL) +rocprofiler_register_add_interface_library(rocprofiler-register-stdcxxfs + "C++ filesystem library" INTERNAL) diff --git a/cmake/rocprofiler_register_linting.cmake b/cmake/rocprofiler_register_linting.cmake new file mode 100644 index 0000000000..1a34218e6f --- /dev/null +++ b/cmake/rocprofiler_register_linting.cmake @@ -0,0 +1,47 @@ +include_guard(GLOBAL) + +# ----------------------------------------------------------------------------------------# +# +# Clang Tidy +# +# ----------------------------------------------------------------------------------------# + +find_program( + ROCPROFILER_REGISTER_CLANG_TIDY_COMMAND + NAMES clang-tidy-18 + clang-tidy-17 + clang-tidy-16 + clang-tidy-15 + clang-tidy-14 + clang-tidy-13 + clang-tidy-12 + clang-tidy-11 + clang-tidy) + +macro(ROCPROFILER_REGISTER_ACTIVATE_CLANG_TIDY) + if(ROCPROFILER_REGISTER_ENABLE_CLANG_TIDY) + if(NOT ROCPROFILER_REGISTER_CLANG_TIDY_COMMAND) + message( + FATAL_ERROR + "ROCPROFILER_REGISTER_ENABLE_CLANG_TIDY is ON but clang-tidy is not found!" + ) + endif() + + set(CMAKE_CXX_CLANG_TIDY ${ROCPROFILER_REGISTER_CLANG_TIDY_COMMAND} + -header-filter=${PROJECT_SOURCE_DIR}/.*) + + # Create a preprocessor definition that depends on .clang-tidy content so the + # compile command will change when .clang-tidy changes. This ensures that a + # subsequent build re-runs clang-tidy on all sources even if they do not otherwise + # need to be recompiled. Nothing actually uses this definition. We add it to + # targets on which we run clang-tidy just to get the build dependency on the + # .clang-tidy file. + file(SHA1 ${PROJECT_SOURCE_DIR}/.clang-tidy clang_tidy_sha1) + set(CLANG_TIDY_DEFINITIONS "CLANG_TIDY_SHA1=${clang_tidy_sha1}") + unset(clang_tidy_sha1) + endif() +endmacro() + +macro(ROCPROFILER_REGISTER_DEACTIVATE_CLANG_TIDY) + set(CMAKE_CXX_CLANG_TIDY) +endmacro() diff --git a/cmake/rocprofiler_register_memcheck.cmake b/cmake/rocprofiler_register_memcheck.cmake new file mode 100644 index 0000000000..de096c6389 --- /dev/null +++ b/cmake/rocprofiler_register_memcheck.cmake @@ -0,0 +1,40 @@ +# +# +# +set(ROCPROFILER_REGISTER_MEMCHECK_TYPES "ThreadSanitizer" "AddressSanitizer" + "LeakSanitizer" "UndefinedBehaviorSanitizer") + +if(ROCPROFILER_REGISTER_MEMCHECK AND NOT ROCPROFILER_REGISTER_MEMCHECK IN_LIST + ROCPROFILER_REGISTER_MEMCHECK_TYPES) + message( + FATAL_ERROR + "Unsupported memcheck type '${ROCPROFILER_REGISTER_MEMCHECK}'. Options: ${ROCPROFILER_REGISTER_MEMCHECK_TYPES}" + ) +endif() + +set_property(CACHE ROCPROFILER_REGISTER_MEMCHECK + PROPERTY STRINGS "${ROCPROFILER_REGISTER_MEMCHECK_TYPES}") + +function(rocprofiler_register_add_memcheck_flags _TYPE _LIB) + target_compile_options( + rocprofiler-register-memcheck + INTERFACE $ + -static-lib${_LIB}) + target_link_options( + rocprofiler-register-memcheck INTERFACE $) +endfunction() + +# always unset so that it doesn't preload if memcheck disabled +unset(ROCPROFILER_REGISTER_MEMCHECK_PRELOAD_ENV CACHE) + +if(ROCPROFILER_REGISTER_MEMCHECK STREQUAL "AddressSanitizer") + rocprofiler_register_add_memcheck_flags("address" "asan") +elseif(ROCPROFILER_REGISTER_MEMCHECK STREQUAL "LeakSanitizer") + rocprofiler_register_add_memcheck_flags("leak" "lsan") +elseif(ROCPROFILER_REGISTER_MEMCHECK STREQUAL "ThreadSanitizer") + rocprofiler_register_add_memcheck_flags("thread" "tsan") +elseif(ROCPROFILER_REGISTER_MEMCHECK STREQUAL "UndefinedBehaviorSanitizer") + rocprofiler_register_add_memcheck_flags("undefined" "ubsan") +endif() diff --git a/cmake/rocprofiler_register_options.cmake b/cmake/rocprofiler_register_options.cmake new file mode 100644 index 0000000000..e25debc4ae --- /dev/null +++ b/cmake/rocprofiler_register_options.cmake @@ -0,0 +1,90 @@ +# +# rocprofiler_register_options.cmake +# +# Configure miscellaneous settings +# +# standard cmake options +rocprofiler_register_add_option(BUILD_SHARED_LIBS "Build shared libraries" ON) +rocprofiler_register_add_option(BUILD_STATIC_LIBS "Build static libraries" OFF) +rocprofiler_register_add_option(CMAKE_POSITION_INDEPENDENT_CODE + "Build position independent code" ON) + +# export compile commands in the project +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_EXTENSIONS OFF) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +rocprofiler_register_add_option(ROCPROFILER_REGISTER_BUILD_TESTS + "Enable building the tests" OFF) +rocprofiler_register_add_option(ROCPROFILER_REGISTER_BUILD_SAMPLES "Enable building the + code samples" OFF) +rocprofiler_register_add_option(ROCPROFILER_REGISTER_BUILD_CI + "Enable continuous integration additions" OFF ADVANCED) +rocprofiler_register_add_option(ROCPROFILER_REGISTER_ENABLE_CLANG_TIDY + "Enable clang-tidy checks" OFF ADVANCED) +rocprofiler_register_add_option( + ROCPROFILER_REGISTER_BUILD_DEVELOPER "Extra build flags for development like -Werror" + ${ROCPROFILER_REGISTER_BUILD_CI} ADVANCED) + +# In the future, we will do this even with clang-tidy enabled +if(ROCPROFILER_REGISTER_BUILD_CI AND NOT ROCPROFILER_REGISTER_ENABLE_CLANG_TIDY) + message( + STATUS + "Forcing ROCPROFILER_REGISTER_BUILD_DEVELOPER=ON because ROCPROFILER_REGISTER_BUILD_CI=ON" + ) + set(ROCPROFILER_REGISTER_BUILD_DEVELOPER + ON + CACHE + BOOL + "Any compiler warnings are errors (forced due ROCPROFILER_REGISTER_BUILD_CI=ON)" + FORCE) +endif() + +set(ROCPROFILER_REGISTER_BUILD_TYPES "Release" "RelWithDebInfo" "Debug" "MinSizeRel" + "Coverage") + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE + "Release" + CACHE STRING "Build type" FORCE) +endif() + +if(NOT CMAKE_BUILD_TYPE IN_LIST ROCPROFILER_REGISTER_BUILD_TYPES) + message( + FATAL_ERROR + "Unsupported build type '${CMAKE_BUILD_TYPE}'. Options: ${ROCPROFILER_REGISTER_BUILD_TYPES}" + ) +endif() + +if(ROCPROFILER_REGISTER_BUILD_CI) + foreach(_BUILD_TYPE ${ROCPROFILER_REGISTER_BUILD_TYPES}) + string(TOUPPER "${_BUILD_TYPE}" _BUILD_TYPE) + + # remove NDEBUG preprocessor def so that asserts are triggered + string(REGEX REPLACE ".DNDEBUG" "" CMAKE_C_FLAGS_${_BUILD_TYPE} + "${CMAKE_C_FLAGS_${_BUILD_TYPE}}") + string(REGEX REPLACE ".DNDEBUG" "" CMAKE_CXX_FLAGS_${_BUILD_TYPE} + "${CMAKE_CXX_FLAGS_${_BUILD_TYPE}}") + endforeach() +endif() + +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "${ROCPROFILER_REGISTER_BUILD_TYPES}") +endif() + +rocprofiler_register_add_cache_option(ROCPROFILER_REGISTER_MEMCHECK "" STRING + "Memory checker type" ADVANCED) + +# ASAN is defined by testing team on Jenkins +if(ASAN) + set(ROCPROFILER_REGISTER_MEMCHECK + "AddressSanitizer" + CACHE STRING "Memory checker type (forced by ASAN defined)" FORCE) +endif() + +include(rocprofiler_register_memcheck) diff --git a/cmake/rocprofiler_register_utilities.cmake b/cmake/rocprofiler_register_utilities.cmake new file mode 100644 index 0000000000..3ba52d49fc --- /dev/null +++ b/cmake/rocprofiler_register_utilities.cmake @@ -0,0 +1,941 @@ +# 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_REGISTER_QUIET_CONFIG settings +# ----------------------------------------------------------------------- +# +function(ROCPROFILER_REGISTER_MESSAGE TYPE) + if(NOT ROCPROFILER_REGISTER_QUIET_CONFIG) + message(${TYPE} "[rocprofiler-register] ${ARGN}") + endif() +endfunction() + +# ----------------------------------------------------------------------- +# Save a set of variables with the given prefix +# ----------------------------------------------------------------------- +macro(ROCPROFILER_REGISTER_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_REGISTER_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_register_capitalize - make a string capitalized (first letter is +# capital) usage: capitalize("SHARED" CShared) message(STATUS "-- CShared is +# \"${CShared}\"") $ -- CShared is "Shared" +function(ROCPROFILER_REGISTER_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_register_strip_target( [FORCE] [EXPLICIT]) +# +# Creates a post-build command which strips a binary. FORCE flag will override +# +function(ROCPROFILER_REGISTER_STRIP_TARGET) + cmake_parse_arguments(STRIP "FORCE;EXPLICIT" "" "ARGS" ${ARGN}) + + list(LENGTH STRIP_UNPARSED_ARGUMENTS NUM_UNPARSED) + + if(NUM_UNPARSED EQUAL 1) + set(_TARGET "${STRIP_UNPARSED_ARGUMENTS}") + else() + rocprofiler_register_message( + FATAL_ERROR + "rocprofiler_register_strip_target cannot deduce target from \"${ARGN}\"") + endif() + + if(NOT TARGET "${_TARGET}") + rocprofiler_register_message( + FATAL_ERROR + "rocprofiler_register_strip_target not provided valid target: \"${_TARGET}\"") + endif() + + if(CMAKE_STRIP AND (STRIP_FORCE OR ROCPROFILER_REGISTER_STRIP_LIBRARIES)) + if(STRIP_EXPLICIT) + add_custom_command( + TARGET ${_TARGET} + POST_BUILD + COMMAND ${CMAKE_STRIP} ${STRIP_ARGS} $ + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Stripping ${_TARGET}...") + else() + add_custom_command( + TARGET ${_TARGET} + POST_BUILD + COMMAND + ${CMAKE_STRIP} -w --keep-symbol="rocprofiler_register_init" + --keep-symbol="rocprofiler_register_finalize" + --keep-symbol="rocprofiler_register_push_trace" + --keep-symbol="rocprofiler_register_pop_trace" + --keep-symbol="rocprofiler_register_push_region" + --keep-symbol="rocprofiler_register_pop_region" + --keep-symbol="rocprofiler_register_set_env" + --keep-symbol="rocprofiler_register_set_mpi" + --keep-symbol="rocprofiler_register_reset_preload" + --keep-symbol="rocprofiler_register_set_instrumented" + --keep-symbol="rocprofiler_register_user_*" + --keep-symbol="ompt_start_tool" --keep-symbol="kokkosp_*" + --keep-symbol="OnLoad" --keep-symbol="OnUnload" + --keep-symbol="OnLoadToolProp" --keep-symbol="OnUnloadTool" + --keep-symbol="__libc_start_main" ${STRIP_ARGS} + $ + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Stripping ${_TARGET}...") + endif() + endif() +endfunction() + +# ------------------------------------------------------------------------------# +# function add_rocprofiler_register_test_target() +# +# Creates a target which runs ctest but depends on all the tests being built. +# +function(ADD_ROCPROFILER_REGISTER_TEST_TARGET) + if(NOT TARGET rocprofiler-register-test) + add_custom_target( + rocprofiler-register-test + COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR} --target test + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Running tests...") + endif() +endfunction() + +# ----------------------------------------------------------------------------------------# +# macro rocprofiler_register_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_REGISTER_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() + + # default assumption + if(NOT CHECKOUT_REPO_BRANCH) + set(CHECKOUT_REPO_BRANCH "master") + 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_register_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 "Checking out '${CHECKOUT_REPO_URL}' @ '${CHECKOUT_REPO_BRANCH}'...") + + # 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 -b ${CHECKOUT_REPO_BRANCH} + ${CHECKOUT_ADDITIONAL_CMDS} ${CHECKOUT_REPO_URL} ${CHECKOUT_RELATIVE_PATH} + WORKING_DIRECTORY ${CHECKOUT_WORKING_DIRECTORY} + RESULT_VARIABLE RET) + + # 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) + endif() + + # check the return code + if(RET GREATER 0) + set(_CMD + "${GIT_EXECUTABLE} clone -b ${CHECKOUT_REPO_BRANCH} + ${CHECKOUT_ADDITIONAL_CMDS} ${CHECKOUT_REPO_URL} ${CHECKOUT_RELATIVE_PATH}" + ) + message( + STATUS "function(rocprofiler_register_checkout_git_submodule) failed.") + message(FATAL_ERROR "Command: \"${_CMD}\"") + else() + set(_TEST_FILE_EXISTS ON) + endif() + 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_REGISTER_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_REGISTER_ADD_INTERFACE_LIBRARY _TARGET _DESCRIPT) + add_library(${_TARGET} INTERFACE) + string(REPLACE "${PROJECT_NAME}-" "" _ALIAS_TARGET "${_TARGET}") + add_library(${PROJECT_NAME}::${_ALIAS_TARGET} ALIAS ${_TARGET}) + add_library(${PROJECT_NAME}::${_TARGET} ALIAS ${_TARGET}) + set(_ARGS "${ARGN}") + if(NOT "INTERNAL" IN_LIST _ARGS) + install( + TARGETS ${_TARGET} + DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT core + EXPORT ${PROJECT_NAME}-library-targets + OPTIONAL) + endif() +endfunction() + +# ----------------------------------------------------------------------- +# function add_feature( ) Add a project feature, whose activation is +# specified by the existence of the variable , to the list of enabled/disabled +# features, plus a docstring describing the feature +# +function(ROCPROFILER_REGISTER_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_REGISTER_BUILD_DOCS) + set_property( + GLOBAL APPEND PROPERTY ${PROJECT_NAME}_CMAKE_OPTIONS_DOC + "${_var}` | ${_description}${EXTRA_DESC} |") + endif() + elseif("DOC" IN_LIST ARGN AND ROCPROFILER_REGISTER_BUILD_DOCS) + set_property(GLOBAL APPEND PROPERTY ${PROJECT_NAME}_CMAKE_OPTIONS_DOC + "${_var}` | ${_description}${EXTRA_DESC} |") + endif() +endfunction() + +# ----------------------------------------------------------------------------------------# +# function add_option( [NO_FEATURE]) Add an +# option and add as a feature if NO_FEATURE is not provided +# +function(ROCPROFILER_REGISTER_ADD_OPTION _NAME _MESSAGE _DEFAULT) + option(${_NAME} "${_MESSAGE}" ${_DEFAULT}) + if("NO_FEATURE" IN_LIST ARGN) + mark_as_advanced(${_NAME}) + else() + rocprofiler_register_add_feature(${_NAME} "${_MESSAGE}") + if(ROCPROFILER_REGISTER_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_register_add_cache_option( +# [NO_FEATURE] [ADVANCED] [CMAKE_DEFINE]) +# +function(ROCPROFILER_REGISTER_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_register_add_feature(${_NAME} "${_MESSAGE}") + + if(ROCPROFILER_REGISTER_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_register_report_feature_changes() :: print changes in features +# +function(ROCPROFILER_REGISTER_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_register_watch_for_change(${_feature}) + elseif("${_feature}" IN_LIST ARGN) + rocprofiler_register_watch_for_change(${_feature}) + endif() + endforeach() +endfunction() + +# ----------------------------------------------------------------------------------------# +# function print_enabled_features() Print enabled features plus their docstrings. +# +function(ROCPROFILER_REGISTER_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_register_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_REGISTER_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_REGISTER_PRINT_FEATURES) + rocprofiler_register_report_feature_changes() + rocprofiler_register_print_enabled_features() + rocprofiler_register_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_register_custom_compilation) + cmake_parse_arguments(COMP "GLOBAL;PROJECT" "COMPILER" "DIRECTORY;TARGET;SOURCE" + ${ARGN}) + + # find rocprofiler-register-launch-compiler + find_program( + ROCPROFILER_REGISTER_COMPILE_LAUNCHER + NAMES rocprofiler-register-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_register_custom_compilation not provided COMPILER argument") + endif() + + if(NOT ROCPROFILER_REGISTER_COMPILE_LAUNCHER) + message( + FATAL_ERROR + "rocprofiler-register could not find 'rocprofiler-register-launch-compiler'. Please set '-DROCPROFILER_REGISTER_COMPILE_LAUNCHER=/path/to/launcher'" + ) + endif() + + if(COMP_GLOBAL) + # if global, don't bother setting others + set_property( + GLOBAL + PROPERTY + RULE_LAUNCH_COMPILE + "${ROCPROFILER_REGISTER_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}" + ) + set_property( + GLOBAL + PROPERTY + RULE_LAUNCH_LINK + "${ROCPROFILER_REGISTER_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}" + ) + else() + foreach(_TYPE PROJECT DIRECTORY TARGET SOURCE) + # make project/subproject scoping easy, e.g. + # rocprofiler_register_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_REGISTER_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}" + ) + set_property( + ${_TYPE} ${_VAL} + PROPERTY + RULE_LAUNCH_LINK + "${ROCPROFILER_REGISTER_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}" + ) + endforeach() + endif() + endforeach() + endif() +endfunction() + +function(ROCPROFILER_REGISTER_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_register_watch_var_name ROCPROFILER_REGISTER_WATCH_VALUE_${_var}) + if(DEFINED ${_rocprofiler_register_watch_var_name}) + if("${${_var}}" STREQUAL "${${_rocprofiler_register_watch_var_name}}") + return() + else() + rocprofiler_register_message( + STATUS + "${_var} changed :: ${${_rocprofiler_register_watch_var_name}} --> ${${_var}}" + ) + update_var(ON) + endif() + else() + if(NOT "${${_var}}" STREQUAL "") + rocprofiler_register_message(STATUS "${_var} :: ${${_var}}") + update_var(ON) + endif() + endif() + + # store the value for the next run + set(${_rocprofiler_register_watch_var_name} + "${${_var}}" + CACHE INTERNAL "Last value of ${_var}" FORCE) +endfunction() + +function(ROCPROFILER_REGISTER_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_register_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_register_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_register_message(FATAL_ERROR + "Directory '${_PATH}' does not exist") + elseif(NOT IS_DIRECTORY "${_PATH}" AND F_FAIL) + rocprofiler_register_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_REGISTER_CHECK_PYTHON_DIRS_AND_VERSIONS) + cmake_parse_arguments(F "FAIL;UNSET" "RESULT_VARIABLE;OUTPUT_VARIABLE" "" ${ARGN}) + + list(LENGTH ROCPROFILER_REGISTER_PYTHON_VERSIONS _NUM_PYTHON_VERSIONS) + list(LENGTH ROCPROFILER_REGISTER_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_register_message( + WARNING + "Error! Number of python versions : ${_NUM_PYTHON_VERSIONS}. VERSIONS :: ${ROCPROFILER_REGISTER_PYTHON_VERSIONS}" + ) + rocprofiler_register_message( + WARNING + "Error! Number of python root directories : ${_NUM_PYTHON_ROOT_DIRS}. ROOT DIRS :: ${ROCPROFILER_REGISTER_PYTHON_ROOT_DIRS}" + ) + rocprofiler_register_message( + FATAL_ERROR + "Error! Number of python versions != number of python root directories") + elseif(F_UNSET) + unset(ROCPROFILER_REGISTER_PYTHON_VERSIONS CACHE) + unset(ROCPROFILER_REGISTER_PYTHON_ROOT_DIRS CACHE) + if(F_OUTPUT_VARIABLE) + set(${F_OUTPUT_VARIABLE} 0) + endif() + endif() + endif() +endfunction() + +# ---------------------------------------------------------------------------- +# Console scripts +# +function(ROCPROFILER_REGISTER_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}") + 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_REGISTER_BUILD_TESTING OR ROCPROFILER_REGISTER_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_REGISTER_FIND_STATIC_LIBRARY) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) + find_library(${ARGN}) +endfunction() + +function(ROCPROFILER_REGISTER_FIND_SHARED_LIBRARY) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX}) + find_library(${ARGN}) +endfunction() + +function(ROCPROFILER_REGISTER_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 $ + ${_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_REGISTER_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_register_buildtree_tpl("${_TPL_TARGET}" "${_NEW_NAME}" + "${_BUILD_TREE_DIR}" ${ARGN}) + + install( + FILES $ + 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() + +cmake_policy(POP) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..585d9d4c24 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,25 @@ + +[tool.black] +line-length = 90 +target-version = ['py36', 'py37', 'py38', 'py39', 'py310'] +include = '\.py$' +exclude = ''' +( + /( + \.eggs + | \.git + | \.github + | \.tox + | \.venv + | \.misc + | \.vscode + | \.cache + | \.pytest_cache + | dist + | external + | build + | build-release + | build-rocprofiler + )/ +) +''' diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt new file mode 100644 index 0000000000..925feac8b6 --- /dev/null +++ b/samples/CMakeLists.txt @@ -0,0 +1,6 @@ +# +# Samples +# +project(rocprofiler-register-samples LANGUAGES C CXX) + +add_subdirectory(library-implementation) diff --git a/samples/library-implementation/CMakeLists.txt b/samples/library-implementation/CMakeLists.txt new file mode 100644 index 0000000000..bff53798e3 --- /dev/null +++ b/samples/library-implementation/CMakeLists.txt @@ -0,0 +1,18 @@ +# +# +# +cmake_minimum_required(VERSION 3.16 FATAL_ERROR) + +project(rocprofiler-register-library-implementation LANGUAGES C CXX) + +if("${CMAKE_PROJECT_NAME}" STREQUAL "${PROJECT_NAME}") + find_package(rocprofiler-register REQUIRED) + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_EXTENSIONS OFF) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() + +add_library(rocp-reg-hip-demo SHARED) +target_sources(rocp-reg-hip-demo PRIVATE demo.cpp demo.hpp) +target_link_libraries(rocp-reg-hip-demo + PRIVATE rocprofiler-register::rocprofiler-register) diff --git a/samples/library-implementation/demo.cpp b/samples/library-implementation/demo.cpp new file mode 100644 index 0000000000..5a5243ac15 --- /dev/null +++ b/samples/library-implementation/demo.cpp @@ -0,0 +1,120 @@ +#include "demo.hpp" + +#include + +#include +#include +#include + +#define ROCP_REG_VERSION \ + ROCPROFILER_REGISTER_COMPUTE_VERSION_3( \ + HIP_VERSION_MAJOR, HIP_VERSION_MINOR, HIP_VERSION_PATCH) + +ROCPROFILER_REGISTER_DEFINE_IMPORT(hip, ROCP_REG_VERSION) + +namespace hip +{ +namespace +{ +auto& +get_hip_api_table_impl() +{ + static auto _table = std::atomic{ nullptr }; + return _table; +} + +void +register_profiler_impl() +{ + static auto _const_api_table = HipApiTable{}; + initialize_hip_api_table(&_const_api_table); + + // set this before any recursive opportunity arises + get_hip_api_table_impl().exchange(&_const_api_table); + + // create a copy of the api table for modification by registration + static auto _profiler_api_table = HipApiTable{}; + copy_hip_api_table(&_profiler_api_table, &_const_api_table); + + void* _profiler_api_table_v = static_cast(&_profiler_api_table); + + auto lib_id = rocprofiler_register_library_indentifier_t{}; + auto success = + rocprofiler_register_library_api_table("hip", + &ROCPROFILER_REGISTER_IMPORT_FUNC(hip), + ROCP_REG_VERSION, + &_profiler_api_table_v, + 1, + &lib_id); + + if(success == 0) + { + auto* _api_table = &_const_api_table; + if(!get_hip_api_table_impl().compare_exchange_strong(_api_table, + &_profiler_api_table)) + { + // with the current impl, if we ever get here, someone is calling one the + // functions in this anonymous namespace that shouldn't + std::cerr + << "register_profiler_impl expected the API table to be the internal " + "implementation and yet it is not. something went wrong.\n"; + abort(); + } + } +} + +void +register_profiler() +{ + // this registration scheme is designed to minimize overhead once + // registered (only pay cost of checking atomic boolean) + // once the profiler is registered. If the library has not + // been registered and two or more threads try to register concurrently + // the first thread to acquire the lock below, will block the + // threads until registration is complete. However, + // if the same thread performing the registration re-enters this function + // i.e. this library's API is called during registration, this function + // will prevent a deadlock by not attempting to re-enter the + // the call-once and not releasing any waiting threads by flipping + // the _is_registered field to true. + static auto _is_registered = std::atomic{ false }; + + if(!_is_registered.load(std::memory_order_acquire)) + { + using mutex_t = std::recursive_mutex; + using auto_lock_t = std::unique_lock; + static auto _once = std::once_flag{}; + static auto _mutex = mutex_t{}; + + // defer the lock so we can check for recursion + auto _lk = auto_lock_t{ _mutex, std::defer_lock }; + + // this will be true if the same thread currently executing the call_once invokes + // the library's API while registering the profiler (e.g. tool which wants to + // instrument HIP API invokes a HIP function while registering with the profiler) + // we allow this thread to proceed and access the "const" API table but + // return so it does not flip _is_registered to true, which would result + // in any subsequent threads not waiting until the library is fully registered, + // resulting in missed callbacks for the tools + if(_lk.owns_lock()) return; + + // ensures any subsequent threads wait until the first thread + // finishes registration + _lk.lock(); + // call_once to ensure that we only register once + std::call_once(_once, register_profiler_impl); + // the first thread has completed registration and all + // threads waiting on lock will be released and this + // block will not be entered again + _is_registered.exchange(true, std::memory_order_release); + } +} +} // namespace + +HipApiTable* +get_hip_api_table() +{ + register_profiler(); + return get_hip_api_table_impl().load(std::memory_order_relaxed); +} +} // namespace hip diff --git a/samples/library-implementation/demo.hpp b/samples/library-implementation/demo.hpp new file mode 100644 index 0000000000..301068a408 --- /dev/null +++ b/samples/library-implementation/demo.hpp @@ -0,0 +1,37 @@ +#pragma once + +#define HIP_VERSION_MAJOR 1 +#define HIP_VERSION_MINOR 0 +#define HIP_VERSION_PATCH 0 + +#include + +extern "C" { +// fake hip function +void +hip_init(void); +} + +namespace hip +{ +struct HipApiTable +{ + uint64_t size = 0; + void (*functor)() = nullptr; +}; + +// populates hip api table with function pointers +inline void +initialize_hip_api_table(HipApiTable* dst) +{ + dst->size = sizeof(HipApiTable); + dst->functor = &hip_init; +} + +// copies the api table from src to dst +inline void +copy_hip_api_table(HipApiTable* dst, const HipApiTable* src) +{ + *dst = *src; +} +} // namespace hip diff --git a/scripts/address-sanitizer-suppr.txt b/scripts/address-sanitizer-suppr.txt new file mode 100644 index 0000000000..c094802b42 --- /dev/null +++ b/scripts/address-sanitizer-suppr.txt @@ -0,0 +1,3 @@ +# +# AddressSanitizer suppressions file for rocprofiler-register project. +# diff --git a/scripts/leak-sanitizer-suppr.txt b/scripts/leak-sanitizer-suppr.txt new file mode 100644 index 0000000000..e466c76ba2 --- /dev/null +++ b/scripts/leak-sanitizer-suppr.txt @@ -0,0 +1,3 @@ +# +# LeakSanitizer suppressions file for rocprofiler-register project. +# diff --git a/scripts/run-ci.py b/scripts/run-ci.py new file mode 100755 index 0000000000..f531a6c4c7 --- /dev/null +++ b/scripts/run-ci.py @@ -0,0 +1,463 @@ +#!/usr/bin/env python3 + + +import os +import re +import sys +import glob +import socket +import shutil +import argparse +import multiprocessing + +# this constant is used to define CTEST_PROJECT_NAME +# and default value for CTEST_SUBMIT_URL +_PROJECT_NAME = "rocprofiler-register" +_BASE_URL = "10.194.116.31/cdash" + + +def which(cmd, require): + v = shutil.which(cmd) + if require and v is None: + raise RuntimeError(f"{cmd} not found") + return v if v is not None else "" + + +def generate_custom(args, cmake_args, ctest_args): + if not os.path.exists(args.binary_dir): + os.makedirs(args.binary_dir) + + if args.memcheck is not None: + if args.coverage: + raise ValueError( + f"Enabling --memcheck={args.memcheck} and --coverage not supported" + ) + cmake_args += [f"-DROCPROFILER_REGISTER_MEMCHECK={args.memcheck}"] + + NAME = args.name + SITE = args.site + BUILD_JOBS = args.build_jobs + SUBMIT_URL = args.submit_url + SOURCE_DIR = os.path.realpath(args.source_dir) + BINARY_DIR = os.path.realpath(args.binary_dir) + CMAKE_ARGS = " ".join(cmake_args) + CTEST_ARGS = " ".join(ctest_args) + + GIT_CMD = which("git", require=True) + GCOV_CMD = which("gcov", require=False) + CMAKE_CMD = which("cmake", require=True) + # CTEST_CMD = which("ctest", require=True) + + NAME = re.sub(r"(.*)-([0-9]+)/merge", "PR_\\2_\\1", NAME) + + DEFAULT_CMAKE_ARGS = " ".join( + [f"-DROCPROFILER_REGISTER_BUILD_{x}=ON" for x in ["CI", "TESTS", "SAMPLES"]] + ) + + MEMCHECK_TYPE = "" if args.memcheck is None else args.memcheck + + MEMCHECK_SANITIZER_OPTIONS = "" + MEMCHECK_SUPPRESSION_FILE = "" + + if MEMCHECK_TYPE == "AddressSanitizer": + MEMCHECK_SANITIZER_OPTIONS = "detect_leaks=0 use_sigaltstack=0" + MEMCHECK_SUPPRESSION_FILE = f"{SOURCE_DIR}/scripts/address-sanitizer-suppr.txt" + elif MEMCHECK_TYPE == "LeakSanitizer": + MEMCHECK_SUPPRESSION_FILE = f"{SOURCE_DIR}/scripts/leak-sanitizer-suppr.txt" + elif MEMCHECK_TYPE == "ThreadSanitizer": + external_symbolizer_path = "" + for version in range(8, 20): + _symbolizer = shutil.which(f"llvm-symbolizer-{version}") + if _symbolizer: + external_symbolizer_path = f"external_symbolizer_path={_symbolizer}" + os.environ["TSAN_OPTIONS"] = " ".join( + [ + "history_size=5", + "second_deadlock_stack=1", + f"suppressions={SOURCE_DIR}/scripts/thread-sanitizer-suppr.txt", + external_symbolizer_path, + os.environ.get("TSAN_OPTIONS", ""), + ] + ) + + return f""" + set(CTEST_PROJECT_NAME "{_PROJECT_NAME}") + set(CTEST_NIGHTLY_START_TIME "05:00:00 UTC") + + set(CTEST_DROP_METHOD "http") + set(CTEST_DROP_SITE_CDASH TRUE) + set(CTEST_SUBMIT_URL "http://{SUBMIT_URL}") + + set(CTEST_UPDATE_TYPE git) + set(CTEST_UPDATE_VERSION_ONLY TRUE) + set(CTEST_GIT_COMMAND {GIT_CMD}) + set(CTEST_GIT_INIT_SUBMODULES FALSE) + + set(CTEST_OUTPUT_ON_FAILURE TRUE) + set(CTEST_USE_LAUNCHERS TRUE) + set(CMAKE_CTEST_ARGUMENTS --output-on-failure {CTEST_ARGS}) + + set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS "100") + set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS "100") + set(CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE "51200") + set(CTEST_CUSTOM_COVERAGE_EXCLUDE "/usr/.*;/opt/.*;.*external/.*;.*samples/.*;.*tests/.*") + + set(CTEST_MEMORYCHECK_TYPE "{MEMCHECK_TYPE}") + set(CTEST_MEMORYCHECK_SUPPRESSIONS_FILE "{MEMCHECK_SUPPRESSION_FILE}") + set(CTEST_MEMORYCHECK_SANITIZER_OPTIONS "{MEMCHECK_SANITIZER_OPTIONS}") + + set(CTEST_SITE "{SITE}") + set(CTEST_BUILD_NAME "{NAME}") + + set(CTEST_SOURCE_DIRECTORY {SOURCE_DIR}) + set(CTEST_BINARY_DIRECTORY {BINARY_DIR}) + + set(CTEST_CONFIGURE_COMMAND "{CMAKE_CMD} -B {BINARY_DIR} {SOURCE_DIR} {DEFAULT_CMAKE_ARGS} {CMAKE_ARGS}") + set(CTEST_BUILD_COMMAND "{CMAKE_CMD} --build {BINARY_DIR} --target all --parallel {BUILD_JOBS}") + set(CTEST_COVERAGE_COMMAND {GCOV_CMD}) + """ + + +def generate_dashboard_script(args): + CODECOV = 1 if args.coverage else 0 + DASHBOARD_MODE = args.mode + SOURCE_DIR = os.path.realpath(args.source_dir) + BINARY_DIR = os.path.realpath(args.binary_dir) + MEMCHECK = 1 if args.memcheck is not None else 0 + SUBMIT = 0 if args.disable_cdash else 1 + ARGN = "${ARGN}" + + if args.memcheck == "ThreadSanitizer": + MEMCHECK = 0 + + _script = f""" + macro(dashboard_submit) + if("{SUBMIT}" GREATER 0) + ctest_submit({ARGN}) + endif() + endmacro() + """ + + _script += """ + + include("${CMAKE_CURRENT_LIST_DIR}/CTestCustom.cmake") + + macro(handle_error _message _ret) + if(NOT ${${_ret}} EQUAL 0) + dashboard_submit(PARTS Done RETURN_VALUE _submit_ret) + message(FATAL_ERROR "${_message} failed: ${${_ret}}") + endif() + endmacro() + """ + + _script += f""" + ctest_start({DASHBOARD_MODE}) + ctest_update(SOURCE "{SOURCE_DIR}" RETURN_VALUE _update_ret + CAPTURE_CMAKE_ERROR _update_err) + ctest_configure(BUILD "{BINARY_DIR}" RETURN_VALUE _configure_ret) + dashboard_submit(PARTS Start Update Configure RETURN_VALUE _submit_ret) + + if(NOT _update_err EQUAL 0) + message(WARNING "ctest_update failed") + endif() + + handle_error("Configure" _configure_ret) + + ctest_build(BUILD "{BINARY_DIR}" RETURN_VALUE _build_ret) + dashboard_submit(PARTS Build RETURN_VALUE _submit_ret) + + handle_error("Build" _build_ret) + + if("{MEMCHECK}" GREATER 0) + ctest_memcheck(BUILD "{BINARY_DIR}" RETURN_VALUE _test_ret) + dashboard_submit(PARTS Test RETURN_VALUE _submit_ret) + else() + ctest_test(BUILD "{BINARY_DIR}" RETURN_VALUE _test_ret) + dashboard_submit(PARTS Test RETURN_VALUE _submit_ret) + endif() + + if("{CODECOV}" GREATER 0) + ctest_coverage( + BUILD "{BINARY_DIR}" + RETURN_VALUE _coverage_ret + CAPTURE_CMAKE_ERROR _coverage_err) + dashboard_submit(PARTS Coverage RETURN_VALUE _submit_ret) + endif() + + handle_error("Testing" _test_ret) + + dashboard_submit(PARTS Done RETURN_VALUE _submit_ret) + """ + return _script + + +def parse_cdash_args(args): + BUILD_JOBS = multiprocessing.cpu_count() + DASHBOARD_MODE = "Continuous" + DASHBOARD_STAGES = [ + "Start", + "Update", + "Configure", + "Build", + "Test", + "MemCheck", + "Coverage", + "Submit", + ] + SOURCE_DIR = os.getcwd() + BINARY_DIR = os.path.join(SOURCE_DIR, "build") + SITE = socket.gethostname() + SUBMIT_URL = f"{_BASE_URL}/submit.php?project={_PROJECT_NAME}" + + parser = argparse.ArgumentParser() + + parser.add_argument( + "-n", "--name", help="Job name", default=None, type=str, required=True + ) + parser.add_argument("-s", "--site", help="Site name", default=SITE, type=str) + parser.add_argument( + "-q", "--quiet", help="Disable printing logs", action="store_true" + ) + parser.add_argument( + "-c", "--coverage", help="Enable code coverage", action="store_true" + ) + parser.add_argument( + "-j", + "--build-jobs", + help="Number of build tasks", + default=BUILD_JOBS, + type=int, + ) + parser.add_argument( + "-B", + "--binary-dir", + help="Build directory", + default=BINARY_DIR, + type=str, + ) + parser.add_argument( + "-S", + "--source-dir", + help="Source directory", + default=SOURCE_DIR, + type=str, + ) + parser.add_argument( + "-F", + "--clean", + help="Remove existing build directory", + action="store_true", + ) + parser.add_argument( + "-M", + "--mode", + help="Dashboard mode", + default=DASHBOARD_MODE, + choices=("Continuous", "Nightly", "Experimental"), + type=str, + ) + parser.add_argument( + "-T", + "--stages", + help="Dashboard stages", + nargs="+", + default=DASHBOARD_STAGES, + choices=DASHBOARD_STAGES, + type=str, + ) + parser.add_argument( + "--submit-url", + help="CDash submission site", + default=SUBMIT_URL, + type=str, + ) + parser.add_argument( + "--repeat-until-pass", + help=" for --repeat until-pass:", + default=None, + type=int, + ) + parser.add_argument( + "--repeat-until-fail", + help=" for --repeat until-fail:", + default=None, + type=int, + ) + parser.add_argument( + "--repeat-after-timeout", + help=" for --repeat after-timeout:", + default=None, + type=int, + ) + parser.add_argument( + "--disable-cdash", + help="Disable submitting results to CDash dashboard", + action="store_true", + ) + parser.add_argument( + "--memcheck", + help="Run dynamic analysis tool", + default=None, + type=str, + choices=( + "ThreadSanitizer", + "AddressSanitizer", + "LeakSanitizer", + "UndefinedBehaviorSanitizer", + ), + ) + parser.add_argument( + "--linter", + help="Enable linting tool", + default=None, + type=str, + choices=("clang-tidy",), + ) + + return parser.parse_args(args) + + +def parse_args(args=None): + if args is None: + args = sys.argv[1:] + + index = 0 + input_args = [] + ctest_args = [] + cmake_args = [] + data = [input_args, cmake_args, ctest_args] + cmd = os.path.basename(sys.argv[0]) + + for itr in args: + if itr == "--": + index += 1 + if index > 2: + raise RuntimeError( + f"Usage: {cmd} -- -- " + ) + else: + data[index].append(itr) + + cdash_args = parse_cdash_args(input_args) + + if cdash_args.coverage: + cmake_args += ["-DROCPROFILER_REGISTER_BUILD_CODECOV=ON"] + + if cdash_args.linter == "clang-tidy": + cmake_args += ["-DROCPROFILER_REGISTER_ENABLE_CLANG_TIDY=ON"] + + def get_repeat_val(_param): + _value = getattr(cdash_args, f"repeat_{_param}".replace("-", "_")) + return [f"{_param}:{_value}"] if _value is not None and _value > 1 else [] + + repeat_args = ( + get_repeat_val("until-pass") + + get_repeat_val("until-fail") + + get_repeat_val("after-timeout") + ) + ctest_args += ["--repeat"] + repeat_args if len(repeat_args) > 0 else [] + + return [cdash_args, cmake_args, ctest_args] + + +def run(*args, **kwargs): + import subprocess + + return subprocess.run(*args, **kwargs) + + +if __name__ == "__main__": + args, cmake_args, ctest_args = parse_args() + + if args.clean and os.path.exists(args.binary_dir): + if args.source_dir == args.binary_dir: + raise RuntimeError( + f"cannot clean binary directory == source directory ({args.source_dir})" + ) + + shutil.rmtree(args.binary_dir) + + if not os.path.exists(args.binary_dir): + os.makedirs(args.binary_dir) + + from textwrap import dedent + + _config = dedent(generate_custom(args, cmake_args, ctest_args)) + _script = dedent(generate_dashboard_script(args)) + + if not args.quiet: + sys.stderr.write(f"##### CTestCustom.cmake #####\n\n{_config}\n\n") + sys.stderr.write(f"##### dashboard.cmake #####\n\n{_script}\n\n") + + with open(os.path.join(args.binary_dir, "CTestCustom.cmake"), "w") as f: + f.write(f"{_config}\n") + + with open(os.path.join(args.binary_dir, "dashboard.cmake"), "w") as f: + f.write(f"{_script}\n") + + CTEST_CMD = which("ctest", require=True) + + dashboard_args = ["-D"] + for itr in args.stages: + dashboard_args.append(f"{args.mode}{itr}") + + try: + if not args.quiet and len(ctest_args) == 0: + ctest_args = ["--output-on-failure", "-V"] + + run( + [CTEST_CMD] + + dashboard_args + + [ + "-S", + os.path.join(args.binary_dir, "dashboard.cmake"), + ] + + ctest_args, + check=True, + ) + finally: + echo_files = [] + if "-VV" not in ctest_args and not args.quiet: + for file in glob.glob( + os.path.join(args.binary_dir, "Testing/Temporary/**"), + recursive=True, + ): + if not os.path.isfile(file): + continue + if re.match( + r"Last(Start|Update|Configure|Build|Test).*\.log$", + os.path.basename(file), + ) is None and "MemoryChecker" not in os.path.basename(file): + continue + + echo_files.append(file) + + if echo_files: + # sort alphabetically + echo_files = sorted(echo_files) + echo_files_sorted = [] + # loop over order we want + for key in [ + "LastStart", + "LastUpdate", + "LastConfigure", + "LastBuild", + "LastTest", + ]: + for file in echo_files: + # if key in file, append + if key in file: + echo_files_sorted.append(file) + echo_files_sorted += [x for x in echo_files if x not in echo_files_sorted] + for file in echo_files_sorted: + print(f"\n\n\n###### Reading {file}... ######\n\n\n") + with open(file, "r") as inpf: + fdata = inpf.read() + oname = os.path.basename(file) + if "LastTest" not in oname and "Coverage" not in oname: + print(fdata) + if oname.endswith(".log"): + oname += ".log" + with open(os.path.join(args.binary_dir, oname), "w") as outf: + print(f"\n\n###### Writing {oname}... ######\n\n") + outf.write(fdata) diff --git a/scripts/thread-sanitizer-suppr.txt b/scripts/thread-sanitizer-suppr.txt new file mode 100644 index 0000000000..e1d7b14d74 --- /dev/null +++ b/scripts/thread-sanitizer-suppr.txt @@ -0,0 +1,3 @@ +# +# ThreadSanitizer suppressions file for rocprofiler-register project. +# diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt new file mode 100644 index 0000000000..e8fa6d76bb --- /dev/null +++ b/source/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# +# +rocprofiler_register_activate_clang_tidy() + +if(ROCPROFILER_REGISTER_BUILD_CODECOV) + set(CMAKE_BUILD_TYPE "Coverage") +endif() + +add_subdirectory(include) +add_subdirectory(lib) diff --git a/source/include/CMakeLists.txt b/source/include/CMakeLists.txt new file mode 100644 index 0000000000..fd82437f6e --- /dev/null +++ b/source/include/CMakeLists.txt @@ -0,0 +1,4 @@ +# +# +# +add_subdirectory(rocprofiler-register) diff --git a/source/include/rocprofiler-register/CMakeLists.txt b/source/include/rocprofiler-register/CMakeLists.txt new file mode 100644 index 0000000000..fbdbae1cae --- /dev/null +++ b/source/include/rocprofiler-register/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# +# Installation of public headers +# +# +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in + ${CMAKE_CURRENT_BINARY_DIR}/version.h @ONLY) + +set(ROCPROFILER_REGISTER_INCLUDE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rocprofiler-register.h + ${CMAKE_CURRENT_BINARY_DIR}/version.h) + +install(FILES ${ROCPROFILER_REGISTER_INCLUDE_FILES} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/rocprofiler-register) diff --git a/source/include/rocprofiler-register/rocprofiler-register.h b/source/include/rocprofiler-register/rocprofiler-register.h new file mode 100644 index 0000000000..b49c1c8cdb --- /dev/null +++ b/source/include/rocprofiler-register/rocprofiler-register.h @@ -0,0 +1,188 @@ +// 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 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*rocprofiler_configure_callback_t)(void*); + +typedef struct +{ + rocprofiler_configure_callback_t initialize; + rocprofiler_configure_callback_t finalize; + void* user_data; +} rocprofiler_configure_result_t; + +typedef uint32_t (*rocprofiler_register_import_func_t)(void); + +typedef struct +{ + uint64_t handle; +} rocprofiler_register_library_indentifier_t; + +/// @enum rocprofiler_register_error_code_t +/// @brief enumeration of error codes +/// +/// @var ROCP_REG_SUCCESS +/// @brief Successful call to rocprofiler-register +/// +/// @var ROCP_REG_NO_TOOLS +/// @brief API table was not passed to rocprofiler because no rocprofiler tool +/// configuration symbols were requested +/// +/// @var ROCP_REG_DEADLOCK +/// @brief The thread that is currently communicating the API tables to rocprofiler +/// re-entered \ref rocprofiler_register_library_api_table +/// +/// @var ROCP_REG_BAD_API_TABLE_LENGTH +/// @brief Library provided an invalid API table length (likely zero) +/// +/// @var ROCP_REG_UNSUPPORTED_API +/// @brief Library is providing an API table name that is not supported +/// +/// @var ROCP_REG_ROCPROFILER_ERROR +/// @brief Rocprofiler returned an error when passing the API tables +/// +/// @var ROCP_REG_EXCESS_API_INSTANCES +/// @brief The same API has been registered too many times +/// +typedef enum rocprofiler_register_error_code_t // NOLINT(performance-enum-size) +{ + ROCP_REG_SUCCESS = 0, + ROCP_REG_NO_TOOLS, + ROCP_REG_DEADLOCK, + ROCP_REG_BAD_API_TABLE_LENGTH, + ROCP_REG_UNSUPPORTED_API, + ROCP_REG_INVALID_API_ADDRESS, + ROCP_REG_ROCPROFILER_ERROR, + ROCP_REG_EXCESS_API_INSTANCES, + ROCP_REG_ERROR_CODE_END, +} rocprofiler_register_error_code_t; + +/// @fn rocprofiler_register_error_code_t rocprofiler_register_library_api_table( +/// const char* lib_name, +/// rocprofiler_register_import_func_t import_func, +/// uint32_t lib_version, +/// void* api_tables, +/// uint64_t api_table_length, +/// rocprofiler_register_library_indentifier_t* register_id) +/// @param[in] lib_name string identifier for the library registering the API table +/// @param[in] import_func function pointer to rocprofiler_register_import_ +/// symbol +/// @param[in] lib_version lib version in form of (10000 * major ) + (100 * minor) + patch +/// @param[in] api_tables pointer to one or more API table pointers +/// @param[in] api_table_length number of API tables that are being passed in. Must be > 0 +/// @param[out] register_id a unique identifier for this library encoding the API category +/// and the priority in the event that multiple libraries register with the same name +/// @returns value of type @ref rocprofiler_register_error_code_t +/// +/// @brief primary function call that needs to be performed when the API table of the +/// library is initialized. +/// +rocprofiler_register_error_code_t +rocprofiler_register_library_api_table( + const char* lib_name, + rocprofiler_register_import_func_t import_func, + uint32_t lib_version, + void** api_tables, + uint64_t api_table_length, + rocprofiler_register_library_indentifier_t* register_id) + ROCPROFILER_REGISTER_ATTRIBUTE(nonnull(4, 6)) ROCPROFILER_REGISTER_PUBLIC_API; + +const char* rocprofiler_register_error_string(rocprofiler_register_error_code_t) + ROCPROFILER_REGISTER_PUBLIC_API; + +#ifdef __cplusplus +} +#endif + +/// @def ROCPROFILER_REGISTER_COMPUTE_VERSION_1 +/// @param[in] MAJOR_VERSION major version of library (integral) +/// @brief Helper macro for users to generate versioning int expected by +/// rocprofiler-register when the library only maintains a major version number +#define ROCPROFILER_REGISTER_COMPUTE_VERSION_1(MAJOR_VERSION) (10000 * MAJOR_VERSION) + +/// @def ROCPROFILER_REGISTER_COMPUTE_VERSION_ +/// @param[in] MAJOR_VERSION major version of library (integral) +/// @param[in] MINOR_VERSION minor version of library (integral) +/// @brief Helper macro for users to generate versioning int expected by +/// rocprofiler-register when the library only maintains a major and minor version number +#define ROCPROFILER_REGISTER_COMPUTE_VERSION_2(MAJOR_VERSION, MINOR_VERSION) \ + (ROCPROFILER_REGISTER_COMPUTE_VERSION_1(MAJOR_VERSION) + (100 * MINOR_VERSION)) + +/// @def ROCPROFILER_REGISTER_COMPUTE_VERSION_3 +/// @param[in] MAJOR_VERSION major version of library (integral) +/// @param[in] MINOR_VERSION minor version of library (integral) +/// @param[in] PATCH_VERSION patch version of library (integral) +/// @brief Helper macro for users to generate versioning int expected by +/// rocprofiler-register when the library maintains a major, minor, and patch version +/// numbers +#define ROCPROFILER_REGISTER_COMPUTE_VERSION_3( \ + MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION) \ + (ROCPROFILER_REGISTER_COMPUTE_VERSION_2(MAJOR_VERSION, MINOR_VERSION) + \ + (PATCH_VERSION)) + +/// @def ROCPROFILER_REGISTER_COMPUTE_VERSION_4 +/// @param[in] MAJOR_VERSION major version of library (integral) +/// @param[in] MINOR_VERSION minor version of library (integral) +/// @param[in] PATCH_VERSION patch version of library (integral) +/// @param[in] TWEAK_VERSION tweak version of library which will be ignored +/// @brief Helper macro for users to generate versioning int expected by +/// rocprofiler-register when the library maintains a major, minor, patch, and tweak +/// version numbers +#define ROCPROFILER_REGISTER_COMPUTE_VERSION_3( \ + MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION) \ + (ROCPROFILER_REGISTER_COMPUTE_VERSION_2(MAJOR_VERSION, MINOR_VERSION) + \ + (PATCH_VERSION)) + +/// @def ROCPROFILER_REGISTER_IMPORT_FUNC(NAME) +/// @param[in] NAME the string identifier for the library +/// @brief Helper macro for retrieving the name of the import function which is used by +/// rocprofiler-register to identify the location and priority of the registering library +#define ROCPROFILER_REGISTER_IMPORT_FUNC(NAME) \ + ROCPROFILER_REGISTER_PP_COMBINE(rocprofiler_register_import_, NAME) + +/// @def ROCPROFILER_REGISTER_DEFINE_IMPORT(NAME, VERSION) +/// @param[in] NAME the unquoted string identifier for the library, e.g. hip +/// @brief Helper macro for declaring a visible import symbol for rocprofiler-register +/// which returns the version. +/// +#ifdef __cplusplus +# define ROCPROFILER_REGISTER_DEFINE_IMPORT(NAME, VERSION) \ + extern "C" { \ + uint32_t ROCPROFILER_REGISTER_IMPORT_FUNC(NAME)() \ + ROCPROFILER_REGISTER_ATTRIBUTE(visibility("default")); \ + \ + uint32_t ROCPROFILER_REGISTER_IMPORT_FUNC(NAME)() { return VERSION; } \ + } +#else +# define ROCPROFILER_REGISTER_DEFINE_IMPORT(NAME, VERSION) \ + uint32_t ROCPROFILER_REGISTER_IMPORT_FUNC(NAME)(void) \ + ROCPROFILER_REGISTER_ATTRIBUTE(visibility("default")); \ + \ + uint32_t ROCPROFILER_REGISTER_IMPORT_FUNC(NAME)(void) { return VERSION; } +#endif diff --git a/source/include/rocprofiler-register/version.h.in b/source/include/rocprofiler-register/version.h.in new file mode 100644 index 0000000000..76239994fd --- /dev/null +++ b/source/include/rocprofiler-register/version.h.in @@ -0,0 +1,103 @@ +// 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 + +// clang-format off +#define ROCPROFILER_REGISTER_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ +#define ROCPROFILER_REGISTER_VERSION_MINOR @PROJECT_VERSION_MINOR@ +#define ROCPROFILER_REGISTER_VERSION_PATCH @PROJECT_VERSION_PATCH@ +#define ROCPROFILER_REGISTER_VERSION_STRING "@FULL_VERSION_STRING@" +#define ROCPROFILER_REGISTER_SOVERSION "@PROJECT_VERSION_MAJOR@" +#define ROCPROFILER_REGISTER_GIT_DESCRIBE "@ROCPROFILER_REGISTER_GIT_DESCRIBE@" +#define ROCPROFILER_REGISTER_GIT_REVISION "@ROCPROFILER_REGISTER_GIT_REVISION@" + +// system info during compilation +#define ROCPROFILER_REGISTER_LIBRARY_ARCH "@CMAKE_LIBRARY_ARCHITECTURE@" +#define ROCPROFILER_REGISTER_SYSTEM_NAME "@CMAKE_SYSTEM_NAME@" +#define ROCPROFILER_REGISTER_SYSTEM_PROCESSOR "@CMAKE_SYSTEM_PROCESSOR@" +#define ROCPROFILER_REGISTER_SYSTEM_VERSION "@CMAKE_SYSTEM_VERSION@" + +// compiler information +#define ROCPROFILER_REGISTER_COMPILER_ID "@CMAKE_CXX_COMPILER_ID@" +#define ROCPROFILER_REGISTER_COMPILER_VERSION "@CMAKE_CXX_COMPILER_VERSION@" +#define ROCPROFILER_REGISTER_COMPILER_STRING ROCPROFILER_REGISTER_COMPILER_ID " v" ROCPROFILER_REGISTER_COMPILER_VERSION +// clang-format on + +#define ROCPROFILER_REGISTER_VERSION \ + ((10000 * ROCPROFILER_REGISTER_VERSION_MAJOR) + \ + (100 * ROCPROFILER_REGISTER_VERSION_MINOR) + ROCPROFILER_REGISTER_VERSION_PATCH) + +#define ROCPROFILER_REGISTER_ATTRIBUTE(...) __attribute__((__VA_ARGS__)) +#define ROCPROFILER_REGISTER_PP_COMBINE(X, Y) X##Y + +#if defined(rocprofiler_register_EXPORTS) +// only defined in build tree +# define ROCPROFILER_REGISTER_VISIBILITY(MODE) \ + ROCPROFILER_REGISTER_ATTRIBUTE(visibility(MODE)) +# define ROCPROFILER_REGISTER_PUBLIC_API ROCPROFILER_REGISTER_VISIBILITY("default") +# define ROCPROFILER_REGISTER_HIDDEN_API ROCPROFILER_REGISTER_VISIBILITY("hidden") +# define ROCPROFILER_REGISTER_INTERNAL_API ROCPROFILER_REGISTER_VISIBILITY("internal") +# define ROCPROFILER_REGISTER_INLINE \ + ROCPROFILER_REGISTER_ATTRIBUTE(always_inline) inline +# define ROCPROFILER_REGISTER_NOINLINE ROCPROFILER_REGISTER_ATTRIBUTE(noinline) +# define ROCPROFILER_REGISTER_HOT ROCPROFILER_REGISTER_ATTRIBUTE(hot) +# define ROCPROFILER_REGISTER_COLD ROCPROFILER_REGISTER_ATTRIBUTE(cold) +# define ROCPROFILER_REGISTER_CONST ROCPROFILER_REGISTER_ATTRIBUTE(const) +# define ROCPROFILER_REGISTER_PURE ROCPROFILER_REGISTER_ATTRIBUTE(pure) +# define ROCPROFILER_REGISTER_WEAK ROCPROFILER_REGISTER_ATTRIBUTE(weak) +# define ROCPROFILER_REGISTER_PACKED ROCPROFILER_REGISTER_ATTRIBUTE(__packed__) +# define ROCPROFILER_REGISTER_PACKED_ALIGN(VAL) \ + ROCPROFILER_REGISTER_PACKED ROCPROFILER_REGISTER_ATTRIBUTE(__aligned__(VAL)) +# define ROCPROFILER_REGISTER_LIKELY(...) __builtin_expect((__VA_ARGS__), 1) +# define ROCPROFILER_REGISTER_UNLIKELY(...) __builtin_expect((__VA_ARGS__), 0) + +# if defined(ROCPROFILER_REGISTER_CI) && ROCPROFILER_REGISTER_CI > 0 +# if defined(NDEBUG) +# undef NDEBUG +# endif +# if !defined(DEBUG) +# define DEBUG 1 +# endif +# if defined(__cplusplus) +# include // NOLINT +# else +# include +# endif +# endif + +# define ROCPROFILER_REGISTER_STRINGIZE(X) ROCPROFILER_REGISTER_STRINGIZE2(X) +# define ROCPROFILER_REGISTER_STRINGIZE2(X) # X +# define ROCPROFILER_REGISTER_LINESTR ROCPROFILER_REGISTER_STRINGIZE(__LINE__) +# define ROCPROFILER_REGISTER_ESC(...) __VA_ARGS__ + +# if defined(__cplusplus) +# if !defined(ROCPROFILER_REGISTER_FOLD_EXPRESSION) +# define ROCPROFILER_REGISTER_FOLD_EXPRESSION(...) ((__VA_ARGS__), ...) +# endif +# endif +#else +# define ROCPROFILER_REGISTER_VISIBILITY(MODE) +# define ROCPROFILER_REGISTER_PUBLIC_API +# define ROCPROFILER_REGISTER_HIDDEN_API +# define ROCPROFILER_REGISTER_INTERNAL_API +#endif diff --git a/source/lib/CMakeLists.txt b/source/lib/CMakeLists.txt new file mode 100644 index 0000000000..fd82437f6e --- /dev/null +++ b/source/lib/CMakeLists.txt @@ -0,0 +1,4 @@ +# +# +# +add_subdirectory(rocprofiler-register) diff --git a/source/lib/rocprofiler-register/CMakeLists.txt b/source/lib/rocprofiler-register/CMakeLists.txt new file mode 100644 index 0000000000..f1464bad77 --- /dev/null +++ b/source/lib/rocprofiler-register/CMakeLists.txt @@ -0,0 +1,36 @@ +# +# builds the rocprofiler-register library +# +add_library(rocprofiler-register SHARED) +add_library(rocprofiler-register::rocprofiler-register ALIAS rocprofiler-register) + +add_subdirectory(details) + +target_sources(rocprofiler-register PRIVATE rocprofiler_register.cpp) + +if(ROCPROFILER_REGISTER_BUILD_TESTS) + # make sure header is C-compatible + target_sources(rocprofiler-register PRIVATE rocprofiler_register.c) +endif() + +target_include_directories( + rocprofiler-register PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/source + ${PROJECT_BINARY_DIR}/source) + +target_link_libraries( + rocprofiler-register + PUBLIC rocprofiler-register::headers + PRIVATE rocprofiler-register::build-flags rocprofiler-register::memcheck + rocprofiler-register::stdcxxfs rocprofiler-register::dl) + +set_target_properties( + rocprofiler-register + PROPERTIES OUTPUT_NAME rocprofiler-register + SOVERSION ${PROJECT_VERSION_MAJOR} + VERSION ${PROJECT_VERSION}) + +install( + TARGETS rocprofiler-register + DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT core + EXPORT ${PROJECT_NAME}-library-targets) diff --git a/source/lib/rocprofiler-register/details/CMakeLists.txt b/source/lib/rocprofiler-register/details/CMakeLists.txt new file mode 100644 index 0000000000..19f7c15568 --- /dev/null +++ b/source/lib/rocprofiler-register/details/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# builds the rocprofiler-register library +# +set(rocprofiler_register_details_sources dl.cpp utility.cpp) + +set(rocprofiler_register_details_headers environment.hpp join.hpp dl.hpp log.hpp + utility.hpp) + +target_sources(rocprofiler-register PRIVATE ${rocprofiler_register_details_sources} + ${rocprofiler_register_details_headers}) diff --git a/source/lib/rocprofiler-register/details/dl.cpp b/source/lib/rocprofiler-register/details/dl.cpp new file mode 100644 index 0000000000..3ae00a688e --- /dev/null +++ b/source/lib/rocprofiler-register/details/dl.cpp @@ -0,0 +1,125 @@ +// 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. + +#define GNU_SOURCE 1 + +#include "dl.hpp" +#include "join.hpp" +#include "utility.hpp" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace fs = ::std::filesystem; + +namespace rocprofiler_register +{ +namespace binary +{ +namespace +{ +const open_modes_vec_t default_link_open_modes = { (RTLD_LAZY | RTLD_NOLOAD), + (RTLD_LAZY | RTLD_LOCAL) }; +} // namespace + +std::vector +get_segment_addresses(pid_t _pid) +{ + auto _data = std::vector{}; + auto _fname = common::join('/', "/proc", _pid, "maps"); + auto ifs = std::ifstream{ _fname }; + if(!ifs) + { + fprintf(stderr, "Failure opening %s\n", _fname.c_str()); + } + else + { + auto _get_entry = [&_data](std::string_view _name) -> segment_address_ranges& { + for(auto& itr : _data) + { + if(itr.filepath == _name) return itr; + } + return _data.emplace_back( + segment_address_ranges{ .filepath = std::string{ _name } }); + }; + + while(ifs) + { + std::string _line = {}; + if(std::getline(ifs, _line) && !_line.empty()) + { + auto _delim = utility::delimit(_line, " \t\n\r"); + if(_delim.size() > 5 && fs::exists(fs::path{ _delim.back() })) + { + auto& _entry = _get_entry(_delim.back()); + auto _addr = utility::delimit(_delim.front(), "-"); + auto load_address = std::stoull(_addr.front(), nullptr, 16); + auto last_address = std::stoull(_addr.back(), nullptr, 16); + _entry.ranges.emplace_back( + address_range{ load_address, last_address }); + } + } + } + } + return _data; +} + +std::optional +get_linked_path(std::string_view _name, open_modes_vec_t&& _open_modes) +{ + if(_name.empty()) return fs::current_path().string(); + + if(_open_modes.empty()) _open_modes = default_link_open_modes; + + void* _handle = nullptr; + bool _noload = false; + for(auto _mode : _open_modes) + { + _handle = dlopen(_name.data(), _mode); + _noload = (_mode & RTLD_NOLOAD) == RTLD_NOLOAD; + if(_handle) break; + } + + if(_handle) + { + struct link_map* _link_map = nullptr; + dlinfo(_handle, RTLD_DI_LINKMAP, &_link_map); + if(_link_map != nullptr && !std::string_view{ _link_map->l_name }.empty()) + { + return fs::absolute(fs::path{ _link_map->l_name }).string(); + } + if(_noload == false) dlclose(_handle); + } + + return std::nullopt; +} +} // namespace binary +} // namespace rocprofiler_register diff --git a/source/lib/rocprofiler-register/details/dl.hpp b/source/lib/rocprofiler-register/details/dl.hpp new file mode 100644 index 0000000000..bfded01a8d --- /dev/null +++ b/source/lib/rocprofiler-register/details/dl.hpp @@ -0,0 +1,60 @@ +// 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 +#include +#include +#include +#include + +#include +#include +#include + +namespace rocprofiler_register +{ +namespace binary +{ +using open_modes_vec_t = std::vector; + +struct address_range +{ + uintptr_t start = 0; + uintptr_t last = 0; +}; + +struct segment_address_ranges +{ + std::string filepath = {}; + std::vector ranges = {}; +}; + +std::vector +get_segment_addresses(pid_t _pid = getpid()); + +// helper function for translating generic lib name to resolved path +std::optional +get_linked_path(std::string_view, open_modes_vec_t&& = {}); +} // namespace binary +} // namespace rocprofiler_register diff --git a/source/lib/rocprofiler-register/details/environment.hpp b/source/lib/rocprofiler-register/details/environment.hpp new file mode 100644 index 0000000000..03bcf47089 --- /dev/null +++ b/source/lib/rocprofiler-register/details/environment.hpp @@ -0,0 +1,191 @@ +// 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 "log.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(ROCPROFILER_REGISTER_ENVIRON_LOG_NAME) +# if defined(ROCPROFILER_REGISTER_COMMON_LIBRARY_NAME) +# define ROCPROFILER_REGISTER_ENVIRON_LOG_NAME \ + "[" ROCPROFILER_REGISTER_COMMON_LIBRARY_NAME "]" +# else +# define ROCPROFILER_REGISTER_ENVIRON_LOG_NAME "[environ]" +# endif +#endif + +#if !defined(ROCPROFILER_REGISTER_ENVIRON_LOG_START) +# if defined(ROCPROFILER_REGISTER_COMMON_LIBRARY_LOG_START) +# define ROCPROFILER_REGISTER_ENVIRON_LOG_START \ + ROCPROFILER_REGISTER_COMMON_LIBRARY_LOG_START +# elif defined(ROCPROFILER_REGISTER_LOG_COLORS_AVAILABLE) +# define ROCPROFILER_REGISTER_ENVIRON_LOG_START \ + fprintf(stderr, "%s", ::rocprofiler_register::log::color::dmesg()); +# else +# define ROCPROFILER_REGISTER_ENVIRON_LOG_START +# endif +#endif + +#if !defined(ROCPROFILER_REGISTER_ENVIRON_LOG_END) +# if defined(ROCPROFILER_REGISTER_COMMON_LIBRARY_LOG_END) +# define ROCPROFILER_REGISTER_ENVIRON_LOG_END \ + ROCPROFILER_REGISTER_COMMON_LIBRARY_LOG_END +# elif defined(ROCPROFILER_REGISTER_LOG_COLORS_AVAILABLE) +# define ROCPROFILER_REGISTER_ENVIRON_LOG_END \ + fprintf(stderr, "%s", ::rocprofiler_register::log::color::end()); +# else +# define ROCPROFILER_REGISTER_ENVIRON_LOG_END +# endif +#endif + +#define ROCPROFILER_REGISTER_ENVIRON_LOG(CONDITION, ...) \ + if(CONDITION) \ + { \ + fflush(stderr); \ + ROCPROFILER_REGISTER_ENVIRON_LOG_START \ + fprintf(stderr, \ + "[rocprofiler-register]" ROCPROFILER_REGISTER_ENVIRON_LOG_NAME "[%i] ", \ + getpid()); \ + fprintf(stderr, __VA_ARGS__); \ + ROCPROFILER_REGISTER_ENVIRON_LOG_END \ + fflush(stderr); \ + } + +namespace rocprofiler_register +{ +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_register][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(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 +inline auto +get_env(std::string_view env_id, Tp&& _default) +{ + if constexpr(std::is_enum::value) + { + using Up = std::underlying_type_t; + // cast to underlying type -> get_env -> cast to enum type + return static_cast(get_env_impl(env_id, static_cast(_default))); + } + else + { + return get_env_impl(env_id, std::forward(_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_REGISTER_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_register diff --git a/source/lib/rocprofiler-register/details/join.hpp b/source/lib/rocprofiler-register/details/join.hpp new file mode 100644 index 0000000000..0086560dcf --- /dev/null +++ b/source/lib/rocprofiler-register/details/join.hpp @@ -0,0 +1,184 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#if !defined(ROCPROFILER_REGISTER_FOLD_EXPRESSION) +# define ROCPROFILER_REGISTER_FOLD_EXPRESSION(...) ((__VA_ARGS__), ...) +#endif + +namespace rocprofiler_register +{ +namespace common +{ +namespace +{ +template +struct is_string_impl : std::false_type +{ }; + +template <> +struct is_string_impl : std::true_type +{ }; + +template <> +struct is_string_impl : std::true_type +{ }; + +template <> +struct is_string_impl : std::true_type +{ }; + +template <> +struct is_string_impl : std::true_type +{ }; + +template +struct is_string : is_string_impl>> +{ }; + +template +auto +as_string(ArgT&& _v, std::enable_if_t::value, int> = 0) +{ + if constexpr(std::is_pointer>::value) + { + return (_v == nullptr) ? std::string{ "\"\"" } + : (std::string{ "\"" } + _v + std::string{ "\"" }); + } + else + { + return std::string{ "\"" } + _v + std::string{ "\"" }; + } +} + +template +auto +as_string(ArgT&& _v, std::enable_if_t::value, long> = 0) +{ + return _v; +} + +template +auto +join(DelimT&& _delim, Args&&... _args) +{ + using delim_type = std::remove_cv_t>; + + std::stringstream _ss{}; + _ss << std::boolalpha; + + if constexpr(std::is_same::value) + { + const char _delim_c[2] = { _delim, '\0' }; + ROCPROFILER_REGISTER_FOLD_EXPRESSION(_ss << _delim_c << _args); + auto _ret = _ss.str(); + return (_ret.length() > 1) ? _ret.substr(1) : std::string{}; + } + else + { + ROCPROFILER_REGISTER_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 +auto +join(QuoteStrings&&, DelimT&& _delim, Args&&... _args) +{ + using delim_type = std::remove_cv_t>; + + std::stringstream _ss{}; + _ss << std::boolalpha; + + if constexpr(std::is_same::value) + { + const char _delim_c[2] = { _delim, '\0' }; + ROCPROFILER_REGISTER_FOLD_EXPRESSION(_ss << _delim_c << as_string(_args)); + auto _ret = _ss.str(); + return (_ret.length() > 1) ? _ret.substr(1) : std::string{}; + } + else + { + ROCPROFILER_REGISTER_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 +auto +join(std::array&& _delim, Args&&... _args) +{ + return join("", + std::get<0>(_delim), + join(std::get<1>(_delim), std::forward(_args)...), + std::get<2>(_delim)); +} + +template +auto +join(QuoteStrings&&, std::array&& _delim, Args&&... _args) +{ + return join(QuoteStrings{}, + "", + std::get<0>(_delim), + join(std::get<1>(_delim), std::forward(_args)...), + std::get<2>(_delim)); +} + +template +auto +join(std::tuple&& _delim, Args&&... _args) +{ + return join("", + std::get<0>(_delim), + join(std::get<1>(_delim), std::forward(_args)...), + std::get<2>(_delim)); +} + +template +auto +join(QuoteStrings&&, std::tuple&& _delim, Args&&... _args) +{ + return join(QuoteStrings{}, + "", + std::get<0>(_delim), + join(std::get<1>(_delim), std::forward(_args)...), + std::get<2>(_delim)); +} +} // namespace +} // namespace common +} // namespace rocprofiler_register diff --git a/source/lib/rocprofiler-register/details/log.hpp b/source/lib/rocprofiler-register/details/log.hpp new file mode 100644 index 0000000000..bc9ecf7c75 --- /dev/null +++ b/source/lib/rocprofiler-register/details/log.hpp @@ -0,0 +1,518 @@ +// 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 + +#include + +#ifndef ROCPROFILER_REGISTER_LOG_COLORS_AVAILABLE +# define ROCPROFILER_REGISTER_LOG_COLORS_AVAILABLE 1 +#endif + +#ifndef ROCPROFILER_REGISTER_PROJECT_NAME +# define ROCPROFILER_REGISTER_PROJECT_NAME "rocprofiler-register" +#endif + +#ifndef ROCP_REG_FILE_NAME +# define ROCP_REG_FILE_NAME \ + ::std::string{ __FILE__ } \ + .substr(::std::string_view{ __FILE__ }.find_last_of('/') + 1) \ + .c_str() +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rocprofiler_register +{ +namespace log +{ +bool& +monochrome(); + +inline bool& +monochrome() +{ + static bool _v = []() { + auto _val = false; + const char* _env_cstr = nullptr; + _env_cstr = std::getenv("ROCPROFILER_REGISTER_MONOCHROME"); + + 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 rocprofiler_register + +namespace rocprofiler_register +{ +namespace log +{ +struct base +{ +public: + static base indent(size_t, size_t = 2) { return base{}; } + + template + auto operator<<(Tp&&) + { + return base{}; + } +}; + +struct logger : public base +{ + logger() = default; + + explicit logger(bool _exit) + : m_exit{ _exit } + { } + + ~logger() + { + if(m_done) + { + std::cerr << color::end() << "\n"; + if(m_exit) abort(); + } + } + + logger(logger&& rhs) noexcept + { + m_exit = rhs.m_exit; + m_done = rhs.m_done; + rhs.m_done = false; + } + + logger& operator=(logger&& rhs) noexcept + { + m_exit = rhs.m_exit; + m_done = rhs.m_done; + rhs.m_done = false; + return *this; + } + + logger&& indent(size_t _n, size_t _tab_size = 4) + { + for(size_t i = 0; i < _n; i++) + for(size_t j = 0; j < _tab_size; j++) + std::cerr << " "; + return std::move(*this); + } + + template + logger&& operator<<(Tp&& _v) + { + std::cerr << std::forward(_v); + return std::move(*this); + } + +private: + bool m_exit = false; + bool m_done = true; +}; + +template +inline auto& +get_color_hist() +{ + static thread_local std::vector> _v{}; + return _v; +} + +template +inline auto +push_color_hist(Tp* _v, const char* _c) +{ + if(!monochrome()) get_color_hist().emplace_back(_v, _c); + return _c; +} + +template +inline std::string +pop_color_hist(Tp* _v) +{ + if(monochrome()) return std::string{}; + + auto& _hist = get_color_hist(); + for(auto itr = _hist.rbegin(); itr != _hist.rend(); ++itr) + { + Tp* _addr = itr->first; + if(_addr == _v) + { + auto fitr = _hist.begin(); + std::advance(fitr, std::distance(_hist.rbegin(), itr)); + _hist.erase(fitr); + } + } + for(auto itr = _hist.rbegin(); itr != _hist.rend(); ++itr) + { + if(itr->first == _v) return itr->second; + } + return color::end(); +} + +template +std::basic_ostream& +info(std::basic_ostream& os) +{ + return (os << push_color_hist(&os, color::info())); +} + +template +std::basic_ostream& +warning(std::basic_ostream& os) +{ + return (os << push_color_hist(&os, color::warning())); +} + +template +std::basic_ostream& +fatal(std::basic_ostream& os) +{ + return (os << push_color_hist(&os, color::fatal())); +} + +template +std::basic_ostream& +source(std::basic_ostream& os) +{ + return (os << push_color_hist(&os, color::source())); +} + +template +std::basic_ostream& +end(std::basic_ostream& os) +{ + return (os << push_color_hist(&os, color::end())); +} + +template +std::basic_ostream& +pop(std::basic_ostream& os) +{ + return (os << pop_color_hist(&os)); +} + +template +std::basic_ostream& +reset(std::basic_ostream& os) +{ + pop_color_hist(&os); + return (os << color::end()); +} + +template +std::basic_ostream& +flush(std::basic_ostream& os) +{ + return (os << pop << std::flush); +} + +template +std::basic_ostream& +endl(std::basic_ostream& os) +{ + return (os << pop << "\n" << std::flush); +} + +template +struct stream_base +{ + stream_base(StreamT& _os, const char* _color) + : m_os{ _os } + { + m_os << push_color_hist(&_os, _color); + } + + ~stream_base() { m_os << pop_color_hist(&m_os); } + + stream_base(const stream_base&) = delete; + stream_base& operator=(const stream_base&) = delete; + + stream_base(stream_base&& rhs) noexcept = default; + stream_base& operator=(stream_base&& rhs) noexcept = default; + + template + stream_base& operator<<(Tp&& _v) + { + m_os << std::forward(_v); + return *this; + } + + template + stream_base& operator<<(Tp& _v) + { + m_os << _v; + return *this; + } + + stream_base& put(char _c) + { + m_os.put(_c); + return *this; + } + + stream_base& endl() + { + m_os << std::endl; + return *this; + } + + template + stream_base& write(Args&&... _args) + { + m_os.write(std::forward(_args)...); + return *this; + } + + stream_base& flush() + { + m_os << std::flush; + return *this; + } + + auto tellp() { return m_os.tellp(); } + + template + stream_base& seekp(Args&&... _args) + { + m_os.seekp(std::forward(_args)...); + return *this; + } + +private: + StreamT& m_os; +}; + +template +stream_base +stream(StreamT& _os, const char* _color) +{ + return stream_base{ _os, _color }; +} + +template +stream_base +info_stream(StreamT& _os) +{ + return stream_base{ _os, color::info() }; +} + +template +stream_base +source_stream(StreamT& _os) +{ + return stream_base{ _os, color::source() }; +} + +template +stream_base +warning_stream(StreamT& _os) +{ + return stream_base{ _os, color::warning() }; +} + +template +stream_base +fatal_stream(StreamT& _os) +{ + return stream_base{ _os, color::fatal() }; +} + +inline std::string +string(const char* _color, std::string_view _v) +{ + return std::string{ _color } + std::string{ _v } + std::string{ color::end() }; +} + +inline std::string +string(const char* _color, std::stringstream& _v) +{ + return std::string{ _color } + _v.str() + std::string{ color::end() }; +} + +inline std::string +string(const char* _color, std::stringstream&& _v) +{ + return std::string{ _color } + _v.str() + std::string{ color::end() }; +} + +template +inline auto +info_string(Tp&& _v) +{ + return string(color::info(), std::forward(_v)); +} + +template +inline auto +source_string(Tp&& _v) +{ + return string(color::source(), std::forward(_v)); +} + +template +inline auto +warning_string(Tp&& _v) +{ + return string(color::warning(), std::forward(_v)); +} + +template +inline auto +fatal_string(Tp&& _v) +{ + return string(color::fatal(), std::forward(_v)); +} +} // namespace log +} // namespace rocprofiler_register + +#if !defined(ROCPROFILER_REGISTER_LOG) +# define ROCPROFILER_REGISTER_LOG(COLOR, EXIT_CODE) \ + (::rocprofiler_register::log::logger(EXIT_CODE) \ + << ::rocprofiler_register::log::color::end() \ + << ::rocprofiler_register::log::color::source() << "[" \ + << ROCPROFILER_REGISTER_PROJECT_NAME << "][" << ROCP_REG_FILE_NAME << ":" \ + << __LINE__ << "][" << getpid() << "] " \ + << ::rocprofiler_register::log::color::end() << COLOR) +#endif + +#if defined(NDEBUG) +# if !defined(ROCPROFILER_REGISTER_INFO) +# define ROCPROFILER_REGISTER_INFO (::rocprofiler_register::log::base()) +# endif +# if !defined(ROCPROFILER_REGISTER_ASSERT) +# define ROCPROFILER_REGISTER_ASSERT(COND) (::rocprofiler_register::log::base()) +# endif +#else +# if !defined(ROCPROFILER_REGISTER_INFO) +# define ROCPROFILER_REGISTER_INFO \ + ROCPROFILER_REGISTER_LOG(::rocprofiler_register::log::color::info(), false) +# endif +# if !defined(ROCPROFILER_REGISTER_ASSERT) +# define ROCPROFILER_REGISTER_ASSERT(COND) \ + (COND) ? ::rocprofiler_register::log::base() : ROCPROFILER_REGISTER_FATAL +# endif +#endif + +#if !defined(ROCPROFILER_REGISTER_WARNING) +# define ROCPROFILER_REGISTER_WARNING \ + ROCPROFILER_REGISTER_LOG(::rocprofiler_register::log::color::warning(), false) +#endif + +#if !defined(ROCPROFILER_REGISTER_FATAL) +# define ROCPROFILER_REGISTER_FATAL \ + ROCPROFILER_REGISTER_LOG(::rocprofiler_register::log::color::fatal(), true) +#endif + +#if !defined(ROCPROFILER_REGISTER_PREFER) +# define ROCPROFILER_REGISTER_PREFER(COND) \ + (COND) ? ::rocprofiler_register::log::base() : ROCPROFILER_REGISTER_WARNING +#endif + +#if !defined(ROCPROFILER_REGISTER_REQUIRE) +# define ROCPROFILER_REGISTER_REQUIRE(COND) \ + (COND) ? ::rocprofiler_register::log::base() : ROCPROFILER_REGISTER_FATAL +#endif diff --git a/source/lib/rocprofiler-register/details/utility.cpp b/source/lib/rocprofiler-register/details/utility.cpp new file mode 100644 index 0000000000..7a72ba729d --- /dev/null +++ b/source/lib/rocprofiler-register/details/utility.cpp @@ -0,0 +1,127 @@ +// 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. + +#include "utility.hpp" + +#include +#include + +#include +#include + +namespace rocprofiler_register +{ +namespace utility +{ +namespace +{ +template +inline auto +emplace_impl(ContainerT& _c, int, Args&&... _args) + -> decltype(_c.emplace_back(std::forward(_args)...)) +{ + return _c.emplace_back(std::forward(_args)...); +} + +template +inline auto +emplace_impl(ContainerT& _c, long, Args&&... _args) + -> decltype(_c.emplace(std::forward(_args)...)) +{ + return _c.emplace(std::forward(_args)...); +} + +template +inline auto +emplace(ContainerT& _c, Args&&... _args) +{ + return emplace_impl(_c, 0, std::forward(_args)...); +} + +template +inline auto +reserve_impl(ContainerT& _c, int, ArgT _arg) -> decltype(_c.reserve(_arg), bool()) +{ + _c.reserve(_arg); + return true; +} + +template +inline auto +reserve_impl(ContainerT&, long, ArgT) +{ + return false; +} + +template +inline auto +reserve(ContainerT& _c, ArgT _arg) +{ + return reserve_impl(_c, 0, _arg); +} +} // namespace + +template +ContainerT +delimit(const std::string& line, std::string_view delimiters) +{ + ContainerT _result{}; + size_t _beginp = 0; // position that is the beginning of the new string + size_t _delimp = 0; // position of the delimiter in the string + if(reserve(_result, 0)) + { + size_t _nmax = 0; + for(char itr : line) + { + for(size_t j = 0; j < delimiters.length(); ++j) + { + if(itr == delimiters.at(j)) ++_nmax; + } + } + reserve(_result, _nmax); + } + while(_beginp < line.length() && _delimp < line.length()) + { + // find the first character (starting at _delimp) that is not a delimiter + _beginp = line.find_first_not_of(delimiters, _delimp); + // if no a character after or at _end that is not a delimiter is not found + // then we are done + if(_beginp == std::string::npos) break; + // starting at the position of the new string, find the next delimiter + _delimp = line.find_first_of(delimiters, _beginp); + std::string _tmp{}; + // starting at the position of the new string, get the characters + // between this position and the next delimiter + _tmp = line.substr(_beginp, _delimp - _beginp); + // don't add empty strings + if(!_tmp.empty()) emplace(_result, _tmp); + } + return _result; +} + +template std::vector +delimit(const std::string&, std::string_view); + +template std::set +delimit(const std::string&, std::string_view); +} // namespace utility +} // namespace rocprofiler_register diff --git a/source/lib/rocprofiler-register/details/utility.hpp b/source/lib/rocprofiler-register/details/utility.hpp new file mode 100644 index 0000000000..7600af8b4c --- /dev/null +++ b/source/lib/rocprofiler-register/details/utility.hpp @@ -0,0 +1,44 @@ +// 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 +#include +#include +#include + +namespace rocprofiler_register +{ +namespace utility +{ +template > +ContainerT +delimit(const std::string& line, std::string_view delimiters = "\"',;: "); + +extern template std::vector +delimit(const std::string&, std::string_view); + +extern template std::set +delimit(const std::string&, std::string_view); +} // namespace utility +} // namespace rocprofiler_register diff --git a/source/lib/rocprofiler-register/rocprofiler_register.c b/source/lib/rocprofiler-register/rocprofiler_register.c new file mode 100644 index 0000000000..0b3dd6d140 --- /dev/null +++ b/source/lib/rocprofiler-register/rocprofiler_register.c @@ -0,0 +1,24 @@ +// 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 +#include + +int ROCPROFILER_REGISTER_INTERNAL_API rocp_register_sym = 0; diff --git a/source/lib/rocprofiler-register/rocprofiler_register.cpp b/source/lib/rocprofiler-register/rocprofiler_register.cpp new file mode 100644 index 0000000000..55cd1ab4c7 --- /dev/null +++ b/source/lib/rocprofiler-register/rocprofiler_register.cpp @@ -0,0 +1,374 @@ +// 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. + +#define GNU_SOURCE 1 + +#include + +#include "details/dl.hpp" +#include "details/environment.hpp" +#include "details/log.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern "C" { +#pragma weak rocprofiler_configure +#pragma weak rocprofiler_set_api_table +#pragma weak rocprofiler_register_import_hip +#pragma weak rocprofiler_register_import_hip_static +#pragma weak rocprofiler_register_import_hsa +#pragma weak rocprofiler_register_import_hsa_static +#pragma weak rocprofiler_register_import_roctx +#pragma weak rocprofiler_register_import_roctx_static + +extern rocprofiler_configure_result_t* +rocprofiler_configure(uint32_t, const char*, uint32_t, uint32_t); + +extern int +rocprofiler_set_api_table(const char*, uint64_t, uint64_t, void**, uint64_t); + +extern uint32_t +rocprofiler_register_import_hip(void); + +extern uint32_t +rocprofiler_register_import_hsa(void); + +extern uint32_t +rocprofiler_register_import_roctx(void); + +extern uint32_t +rocprofiler_register_import_hip_static(void); + +extern uint32_t +rocprofiler_register_import_hsa_static(void); + +extern uint32_t +rocprofiler_register_import_roctx_static(void); +} + +namespace +{ +namespace fs = ::std::filesystem; +using namespace rocprofiler_register; +using rocprofiler_set_api_table_t = decltype(::rocprofiler_set_api_table)*; +using bitset_t = std::bitset; + +static_assert(sizeof(bitset_t) == + sizeof(rocprofiler_register_library_indentifier_t::handle), + "bitset should be same at uint64_t"); + +int rocprofiler_register_verbose = common::get_env("ROCPROFILER_REGISTER_VERBOSE", 0); +constexpr int rocprofiler_register_info_level = 2; +constexpr auto rocprofiler_lib_name = "librocprofiler64.so"; +constexpr auto rocprofiler_lib_register_entrypoint = "rocprofiler_set_api_table"; +constexpr auto rocprofiler_register_lib_name = + "librocprofiler-register.so." ROCPROFILER_REGISTER_SOVERSION; + +enum rocp_reg_supported_library // NOLINT(performance-enum-size) +{ + ROCP_REG_HSA = 0, + ROCP_REG_HIP, + ROCP_REG_ROCTX, + ROCP_REG_LAST, +}; + +template +struct supported_library_trait +{ + static constexpr bool specialized = false; + static constexpr auto value = ROCP_REG_LAST; + static constexpr const char* const common_name = nullptr; + static constexpr const char* const symbol_name = nullptr; + static constexpr const char* const library_name = nullptr; +}; + +#define ROCP_REG_DEFINE_LIBRARY_TRAITS(ENUM, NAME, SYM_NAME, LIB_NAME) \ + template <> \ + struct supported_library_trait \ + { \ + static constexpr bool specialized = true; \ + static constexpr auto value = ENUM; \ + static constexpr auto common_name = NAME; \ + static constexpr auto symbol_name = SYM_NAME; \ + static constexpr auto library_name = LIB_NAME; \ + }; + +ROCP_REG_DEFINE_LIBRARY_TRAITS(ROCP_REG_HSA, + "hsa", + "rocprofiler_register_import_hsa", + "libhsa-runtime64.so.[2-9]($|\\.[0-9\\.]+)") + +ROCP_REG_DEFINE_LIBRARY_TRAITS(ROCP_REG_HIP, + "hip", + "rocprofiler_register_import_hip", + "libamdhip64.so.[6-9]($|\\.[0-9\\.]+)") + +ROCP_REG_DEFINE_LIBRARY_TRAITS(ROCP_REG_ROCTX, + "roctx", + "rocprofiler_register_import_roctx", + "libroctx64.so.[4-9]($|\\.[0-9\\.]+)") + +auto +get_this_library_path() +{ + auto _this_lib_path = binary::get_linked_path(rocprofiler_register_lib_name, + { RTLD_NOLOAD | RTLD_LAZY }); + ROCPROFILER_REGISTER_REQUIRE(_this_lib_path) + << rocprofiler_register_lib_name + << " could not locate itself in the list of loaded libraries"; + return fs::path{ *_this_lib_path }.parent_path().string(); +} + +struct rocp_import +{ + rocp_reg_supported_library library_idx = ROCP_REG_LAST; + std::string_view common_name = {}; + std::string_view symbol_name = {}; + std::string_view library_name = {}; +}; + +template +auto rocp_reg_get_imports(std::index_sequence) +{ + auto _data = std::vector{}; + auto _import_scan = [&_data](auto _info) { + if(_info.specialized) + { + _data.emplace_back(rocp_import{ + _info.value, _info.common_name, _info.symbol_name, _info.library_name }); + } + }; + + (_import_scan(supported_library_trait{}), ...); + return _data; +} + +auto +rocp_reg_scan_for_tools() +{ + auto _rocp_reg_lib = common::get_env("ROCPROFILER_REGISTER_LIBRARY", std::string{}); + bool _force_tool = + common::get_env("ROCPROFILER_REGISTER_FORCE_LOAD", !_rocp_reg_lib.empty()); + bool _found_tool = (rocprofiler_configure != nullptr || _force_tool); + + static void* rocprofiler_lib_handle = nullptr; + static rocprofiler_set_api_table_t rocprofiler_lib_config_fn = nullptr; + + if(_force_tool) + { + if(rocprofiler_lib_handle && rocprofiler_lib_config_fn) + return std::make_pair(rocprofiler_lib_handle, rocprofiler_lib_config_fn); + + if(_rocp_reg_lib.empty()) _rocp_reg_lib = rocprofiler_lib_name; + + auto _rocp_reg_lib_path = fs::path{ _rocp_reg_lib }; + auto _rocp_reg_lib_path_fname = _rocp_reg_lib_path.filename(); + auto _rocp_reg_lib_path_abs = + (_rocp_reg_lib_path.is_absolute()) + ? _rocp_reg_lib_path + : (fs::path{ get_this_library_path() } / _rocp_reg_lib_path_fname); + + // check to see if the rocprofiler library is already loaded + rocprofiler_lib_handle = + dlopen(_rocp_reg_lib_path.c_str(), RTLD_NOLOAD | RTLD_LAZY); + + // try to load with the given path + if(!rocprofiler_lib_handle) + { + rocprofiler_lib_handle = + dlopen(_rocp_reg_lib_path.c_str(), RTLD_GLOBAL | RTLD_LAZY); + } + + // try to load with the absoulte path + if(!rocprofiler_lib_handle) + { + _rocp_reg_lib_path = _rocp_reg_lib_path_abs; + rocprofiler_lib_handle = + dlopen(_rocp_reg_lib_path.c_str(), RTLD_GLOBAL | RTLD_LAZY); + } + + // try to load with the basename path + if(!rocprofiler_lib_handle) + { + _rocp_reg_lib_path = _rocp_reg_lib_path_fname; + rocprofiler_lib_handle = + dlopen(_rocp_reg_lib_path.c_str(), RTLD_GLOBAL | RTLD_LAZY); + } + + if(rocprofiler_register_verbose >= rocprofiler_register_info_level) + ROCPROFILER_REGISTER_INFO << "loaded " << _rocp_reg_lib_path_fname.string() + << " library at " << _rocp_reg_lib_path.string(); + + ROCPROFILER_REGISTER_REQUIRE(rocprofiler_lib_handle) + << _rocp_reg_lib << " failed to load\n"; + + *(void**) (&rocprofiler_lib_config_fn) = + dlsym(rocprofiler_lib_handle, rocprofiler_lib_register_entrypoint); + + ROCPROFILER_REGISTER_REQUIRE(rocprofiler_lib_config_fn) + << _rocp_reg_lib << " did not contain '" + << rocprofiler_lib_register_entrypoint << "' symbol\n"; + } + else if(_found_tool && rocprofiler_set_api_table) + { + rocprofiler_lib_config_fn = &rocprofiler_set_api_table; + } + + return std::make_pair(rocprofiler_lib_handle, rocprofiler_lib_config_fn); +} + +constexpr auto library_seq = std::make_index_sequence{}; +auto global_mutex = std::recursive_mutex{}; +auto import_info = rocp_reg_get_imports(library_seq); +auto instance_counters = std::array{}; +} // namespace + +extern "C" { +rocprofiler_register_error_code_t +rocprofiler_register_library_api_table( + const char* common_name, + rocprofiler_register_import_func_t import_func, + uint32_t lib_version, + void** api_tables, + uint64_t api_table_length, + rocprofiler_register_library_indentifier_t* register_id) +{ + if(api_table_length < 1) return ROCP_REG_BAD_API_TABLE_LENGTH; + + (void) lib_version; + (void) api_tables; + + auto _lk = std::unique_lock{ global_mutex, std::defer_lock }; + if(_lk.owns_lock()) return ROCP_REG_DEADLOCK; + + auto _scan_result = rocp_reg_scan_for_tools(); + + rocp_import* _import_match = nullptr; + for(auto& itr : import_info) + { + if(itr.common_name == common_name) + { + _import_match = &itr; + break; + } + } + + // not a supported library name + if(!_import_match || _import_match->library_idx == ROCP_REG_LAST) + return ROCP_REG_UNSUPPORTED_API; + + if(import_func != nullptr && + common::get_env("ROCPROFILER_REGISTER_SECURE", false)) + { + auto _import_func_addr = reinterpret_cast(import_func); + auto _segment_addresses = binary::get_segment_addresses(); + auto _in_address_range = [](uintptr_t _addr, + const std::vector& _range) { + for(auto ritr : _range) + { + if(_addr >= ritr.start && _addr < ritr.last) return true; + } + return false; + }; + + // check that the address of the import function is within the expected library + // name + bool _valid_addr = false; + for(const auto& itr : _segment_addresses) + { + if(_in_address_range(_import_func_addr, itr.ranges)) + { + if(std::regex_search(fs::path{ itr.filepath }.filename().string(), + std::regex{ _import_match->library_name.data() })) + { + _valid_addr = true; + } + } + } + + // the library provided + if(!_valid_addr) return ROCP_REG_INVALID_API_ADDRESS; + } + + constexpr auto offset_factor = 64 / std::max(ROCP_REG_LAST, 8); + // if ROCP_REG_LAST > 8, then we can no longer encode 8 instances per lib + // because we ran out of bits (i.e. max of 8 * 8 = 64) + static_assert((offset_factor * ROCP_REG_LAST) <= sizeof(uint64_t) * 8, + "ROCP_REG_LAST has exceeded the max allowable size"); + + // too many instances of the same library + if(instance_counters.at(_import_match->library_idx) >= offset_factor) + return ROCP_REG_EXCESS_API_INSTANCES; + + auto _instance_val = instance_counters.at(_import_match->library_idx)++; + auto& _bits = *reinterpret_cast(®ister_id->handle); + _bits = bitset_t{ (offset_factor * _import_match->library_idx) + _instance_val }; + + if(_bits.to_ulong() != register_id->handle) + throw std::runtime_error("error encoding register_id"); + + // rocprofiler library is dlopened and we have the functor to pass the API data + auto _activate_rocprofiler = (_scan_result.second != nullptr); + + if(_activate_rocprofiler) + { + auto _ret = _scan_result.second( + common_name, lib_version, _instance_val, api_tables, api_table_length); + if(_ret != 0) return ROCP_REG_ROCPROFILER_ERROR; + } + else + { + return ROCP_REG_NO_TOOLS; + } + + return ROCP_REG_SUCCESS; +} + +const char* +rocprofiler_register_error_string(rocprofiler_register_error_code_t _ec) +{ + switch(_ec) + { + case ROCP_REG_SUCCESS: return "rocprofiler_register_success"; + case ROCP_REG_NO_TOOLS: return "rocprofiler_register_no_tools"; + case ROCP_REG_DEADLOCK: return "rocprofiler_register_deadlock"; + case ROCP_REG_BAD_API_TABLE_LENGTH: + return "rocprofiler_register_bad_api_table_length"; + case ROCP_REG_UNSUPPORTED_API: return "rocprofiler_register_unsupported_api"; + case ROCP_REG_INVALID_API_ADDRESS: + return "rocprofiler_register_invalid_api_address"; + case ROCP_REG_ROCPROFILER_ERROR: return "rocprofiler_register_rocprofiler_error"; + case ROCP_REG_EXCESS_API_INSTANCES: + return "rocprofiler_register_excess_api_instances"; + case ROCP_REG_ERROR_CODE_END: return "rocprofiler_register_unknown_error"; + } + return "rocprofiler_register_unknown_error"; +} +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000000..fc1c741ab6 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,465 @@ +cmake_minimum_required(VERSION 3.16 FATAL_ERROR) + +project(rocprofiler-register-tests LANGUAGES C CXX) + +include(CMakeParseArguments) +include(GNUInstallDirs) + +if("${CMAKE_PROJECT_NAME}" STREQUAL "${PROJECT_NAME}") + find_package(rocprofiler-register REQUIRED) + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_EXTENSIONS OFF) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_C_VISIBILITY_PRESET "hidden") + set(CMAKE_CXX_VISIBILITY_PRESET "hidden") + set(CMAKE_VISIBILITY_INLINES_HIDDEN OFF) + set(CMAKE_POSITION_INDEPENDENT_CODE ON) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") + enable_testing() + include(CTest) +endif() + +function(rocp_register_strip_target) + if(CMAKE_BUILD_TYPE MATCHES "(DEBUG|Debug)") + return() + endif() + + cmake_parse_arguments(STRIP "" "" "ARGS" ${ARGN}) + + list(LENGTH STRIP_UNPARSED_ARGUMENTS NUM_UNPARSED) + + if(NUM_UNPARSED EQUAL 1) + set(_TARGET "${STRIP_UNPARSED_ARGUMENTS}") + else() + message( + FATAL_ERROR "rocp_register_strip_target cannot deduce target from \"${ARGN}\"" + ) + endif() + + if(NOT TARGET "${_TARGET}") + message( + FATAL_ERROR + "rocp_register_strip_target not provided valid target: \"${_TARGET}\"") + endif() + + if(CMAKE_STRIP) + add_custom_command( + TARGET ${_TARGET} + POST_BUILD + COMMAND ${CMAKE_STRIP} ${STRIP_ARGS} $ + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Stripping ${_TARGET}...") + else() + message(WARNING "CMAKE_STRIP not set... Not stripping ${_TARGET}") + endif() +endfunction() + +# +# mock libraries +# +add_subdirectory(hsa-runtime) +add_subdirectory(amdhip) +add_subdirectory(roctx) +add_subdirectory(rocprofiler) + +# +# common to multiple tests +# +find_package(Threads REQUIRED) + +add_library(rocprofiler-register-tests-common INTERFACE) +target_include_directories(rocprofiler-register-tests-common + INTERFACE $) +target_link_libraries(rocprofiler-register-tests-common INTERFACE Threads::Threads stdc++) + +add_library(rocprofiler-register-tests-strong INTERFACE) +target_compile_definitions(rocprofiler-register-tests-strong + INTERFACE ROCP_REG_TEST_WEAK=0) + +add_library(rocprofiler-register-tests-weak INTERFACE) +target_compile_definitions(rocprofiler-register-tests-weak INTERFACE ROCP_REG_TEST_WEAK=1) + +add_library(rocprofiler-register-tests-rocp INTERFACE) +target_link_options(rocprofiler-register-tests-rocp INTERFACE -Wl,--no-as-needed) +target_link_libraries(rocprofiler-register-tests-rocp INTERFACE rocprofiler::rocprofiler) + +add_library(rocprofiler-register::tests-common ALIAS rocprofiler-register-tests-common) +add_library(rocprofiler-register::tests-strong ALIAS rocprofiler-register-tests-strong) +add_library(rocprofiler-register::tests-weak ALIAS rocprofiler-register-tests-weak) +add_library(rocprofiler-register::tests-rocp ALIAS rocprofiler-register-tests-rocp) + +# +# test scenarios +# +function(rocp_register_test_executable _NAME) + set(_SV_ARGS) + foreach(_TYPE "CORE" "PRELOAD" "WRAP" "PRELOAD_WRAP") + list(APPEND _SV_ARGS "${_TYPE}_PASS_REGEX" "${_TYPE}_FAIL_REGEX") + endforeach() + cmake_parse_arguments( + RRTE + "" # options + "SECURE;${_SV_ARGS}" # single value args + "SOURCES;LIBRARIES" # multiple value args + ${ARGN}) + + add_executable(${_NAME}) + target_sources(${_NAME} PRIVATE ${RRTE_SOURCES}) + target_link_libraries(${_NAME} PRIVATE rocprofiler-register::tests-common + ${RRTE_LIBRARIES}) + + function(rocp_register_add_test _TEST_NAME _TARGET _ENV _PASS _FAIL) + if(RRTE_SECURE) + list(APPEND _ENV "ROCPROFILER_REGISTER_SECURE=true") + set(_LABELS "secure") + else() + set(_LABELS "insecure") + endif() + add_test( + NAME ${_TEST_NAME} + COMMAND $ + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) + set_tests_properties( + ${_TEST_NAME} + PROPERTIES ENVIRONMENT + "LD_LIBRARY_PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY};${_ENV}" + PASS_REGULAR_EXPRESSION + "${_PASS}" + FAIL_REGULAR_EXPRESSION + "${_FAIL}" + LABELS + "${_LABELS}" + ${ARGN}) + endfunction() + + rocp_register_add_test(${_NAME} ${_NAME} "" "${RRTE_CORE_PASS_REGEX}" + "${RRTE_CORE_FAIL_REGEX}") + + rocp_register_add_test(${_NAME}-preload ${_NAME} "LD_PRELOAD=librocprofiler64.so" + "${RRTE_PRELOAD_PASS_REGEX}" "${RRTE_PRELOAD_FAIL_REGEX}") + + rocp_register_add_test(${_NAME}-wrap ${_NAME} "ROCP_REG_TEST_WRAP=1" + "${RRTE_WRAP_PASS_REGEX}" "${RRTE_WRAP_FAIL_REGEX}") + + rocp_register_add_test( + ${_NAME}-preload-wrap ${_NAME} + "LD_PRELOAD=librocprofiler64.so;ROCP_REG_TEST_WRAP=1" + "${RRTE_PRELOAD_WRAP_PASS_REGEX}" "${RRTE_PRELOAD_WRAP_FAIL_REGEX}") + +endfunction() + +# serial +rocp_register_test_executable( + test-amdhip-roctx + SECURE ON + SOURCES test-amdhip-roctx.cpp + LIBRARIES rocprofiler-register::tests-strong amdhip::amdhip roctx::roctx + CORE_PASS_REGEX + ".hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n.roctx.cpp..push. thread-main\n.roctx.cpp..pop. thread-main\n" + PRELOAD_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.roctx.cpp..push. thread-main\n.roctx.cpp..pop. thread-main\n" + WRAP_PASS_REGEX + ".hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n.roctx.cpp..push. thread-main\n.roctx.cpp..pop. thread-main\n" + PRELOAD_WRAP_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.rocprofiler.cpp..push. thread-main\n.rocprofiler.cpp..pop. thread-main\n" + ) + +rocp_register_test_executable( + test-amdhip-roctx-weak + SOURCES test-amdhip-roctx.cpp + LIBRARIES rocprofiler-register::tests-weak + CORE_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n.roctx.cpp..push. thread-main\n.roctx.cpp..pop. thread-main\n" + PRELOAD_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.roctx.cpp..push. thread-main\n.roctx.cpp..pop. thread-main\n" + WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n.roctx.cpp..push. thread-main\n.roctx.cpp..pop. thread-main\n" + PRELOAD_WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.rocprofiler.cpp..push. thread-main\n.rocprofiler.cpp..pop. thread-main\n" + ) + +rocp_register_test_executable( + test-amdhip-roctx-rocp + SOURCES test-amdhip-roctx.cpp + LIBRARIES rocprofiler-register::tests-strong amdhip::amdhip roctx::roctx + rocprofiler-register::tests-rocp + CORE_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.roctx.cpp..push. thread-main\n.roctx.cpp..pop. thread-main\n" + PRELOAD_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.roctx.cpp..push. thread-main\n.roctx.cpp..pop. thread-main\n" + WRAP_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.rocprofiler.cpp..push. thread-main\n.rocprofiler.cpp..pop. thread-main\n" + PRELOAD_WRAP_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.rocprofiler.cpp..push. thread-main\n.rocprofiler.cpp..pop. thread-main\n" + ) + +rocp_register_test_executable( + test-amdhip-roctx-weak-rocp + SOURCES test-amdhip-roctx.cpp + LIBRARIES rocprofiler-register::tests-weak rocprofiler-register::tests-rocp + CORE_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.roctx.cpp..push. thread-main\n.roctx.cpp..pop. thread-main\n" + PRELOAD_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.roctx.cpp..push. thread-main\n.roctx.cpp..pop. thread-main\n" + WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.rocprofiler.cpp..push. thread-main\n.rocprofiler.cpp..pop. thread-main\n" + PRELOAD_WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.rocprofiler.cpp..push. thread-main\n.rocprofiler.cpp..pop. thread-main\n" + ) + +# multithreaded +rocp_register_test_executable( + test-amdhip-roctx-mt + SOURCES test-amdhip-roctx-mt.cpp + LIBRARIES rocprofiler-register::tests-strong amdhip::amdhip roctx::roctx + CORE_PASS_REGEX + ".hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n" + PRELOAD_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n" + WRAP_PASS_REGEX + ".hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n" + PRELOAD_WRAP_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n" + ) + +rocp_register_test_executable( + test-amdhip-roctx-mt-weak + SOURCES test-amdhip-roctx-mt.cpp + LIBRARIES rocprofiler-register::tests-weak + CORE_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n" + PRELOAD_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n" + WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n" + PRELOAD_WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n" + ) + +rocp_register_test_executable( + test-amdhip-roctx-mt-rocp + SOURCES test-amdhip-roctx-mt.cpp + LIBRARIES rocprofiler-register::tests-strong amdhip::amdhip roctx::roctx + rocprofiler-register::tests-rocp + CORE_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n" + PRELOAD_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n" + WRAP_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n" + PRELOAD_WRAP_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n" + ) + +# 29 +rocp_register_test_executable( + test-amdhip-roctx-mt-weak-rocp + SOURCES test-amdhip-roctx-mt.cpp + LIBRARIES rocprofiler-register::tests-weak rocprofiler-register::tests-rocp + CORE_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n" + PRELOAD_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..push. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n.roctx.cpp..pop. thread-[0-3]\n" + WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n" + PRELOAD_WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libroctx64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. roctx :: 40601 :: 0 :: 1\n.roctx.cpp. roctx identifier 16\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..push. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n.rocprofiler.cpp..pop. thread-[0-3]\n" + ) + +# constructor +rocp_register_test_executable( + test-amdhip-ctor + SOURCES test-amdhip-ctor.cpp + LIBRARIES rocprofiler-register::tests-strong amdhip::amdhip + CORE_PASS_REGEX + ".hsa-runtime.cpp. hsa_init\n.hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n" + PRELOAD_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n" + WRAP_PASS_REGEX + ".hsa-runtime.cpp. hsa_init\n.hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n" + PRELOAD_WRAP_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n" + ) + +rocp_register_test_executable( + test-amdhip-ctor-weak + SOURCES test-amdhip-ctor.cpp + LIBRARIES rocprofiler-register::tests-weak + CORE_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libhsa-runtime64.so, 1\n.hsa-runtime.cpp. hsa_init\n.hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n" + PRELOAD_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libhsa-runtime64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n" + WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libhsa-runtime64.so, 1\n.hsa-runtime.cpp. hsa_init\n.hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n" + PRELOAD_WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libhsa-runtime64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n" + ) + +# 41 +rocp_register_test_executable( + test-amdhip-ctor-rocp + SOURCES test-amdhip-ctor.cpp + LIBRARIES rocprofiler-register::tests-strong amdhip::amdhip + rocprofiler-register::tests-rocp + CORE_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n" + PRELOAD_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n" + WRAP_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n" + PRELOAD_WRAP_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n" + ) + +rocp_register_test_executable( + test-amdhip-ctor-weak-rocp + SOURCES test-amdhip-ctor.cpp + LIBRARIES rocprofiler-register::tests-weak rocprofiler-register::tests-rocp + CORE_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libhsa-runtime64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n" + PRELOAD_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libhsa-runtime64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n" + WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libhsa-runtime64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n" + PRELOAD_WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.fwd.hpp. dlopen libhsa-runtime64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n" + ) + +# constructor + mt +rocp_register_test_executable( + test-amdhip-ctor-mt + SOURCES test-amdhip-ctor-mt.cpp + LIBRARIES rocprofiler-register::tests-strong amdhip::amdhip + CORE_PASS_REGEX + ".hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n" + PRELOAD_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n" + WRAP_PASS_REGEX + ".hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n" + PRELOAD_WRAP_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n" + ) + +rocp_register_test_executable( + test-amdhip-ctor-mt-weak + SOURCES test-amdhip-ctor-mt.cpp + LIBRARIES rocprofiler-register::tests-weak + CORE_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n" + PRELOAD_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n" + WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.hsa-runtime.cpp. hsa_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n" + PRELOAD_WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n" + ) + +rocp_register_test_executable( + test-amdhip-ctor-mt-rocp + SOURCES test-amdhip-ctor-mt.cpp + LIBRARIES rocprofiler-register::tests-strong amdhip::amdhip + rocprofiler-register::tests-rocp + CORE_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n" + PRELOAD_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n" + WRAP_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n" + PRELOAD_WRAP_PASS_REGEX + ".rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n" + ) + +rocp_register_test_executable( + test-amdhip-ctor-mt-weak-rocp + SOURCES test-amdhip-ctor-mt.cpp + LIBRARIES rocprofiler-register::tests-weak rocprofiler-register::tests-rocp + CORE_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n" + PRELOAD_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.hsa-runtime.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n.amdhip.cpp. hip_init\n" + WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n" + PRELOAD_WRAP_PASS_REGEX + ".fwd.hpp. dlopen libamdhip64.so, 1\n.rocprofiler.cpp. rocp_ctor\n.rocprofiler.cpp. hsa :: 20100 :: 0 :: 1\n.hsa-runtime.cpp. hsa identifier 0\n.rocprofiler.cpp. hsa_init\n.rocprofiler.cpp. hip :: 60001 :: 0 :: 1\n.amdhip.cpp. hip identifier 8\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n.rocprofiler.cpp. hip_init\n" + ) + +add_executable(test-invalid-hsa-runtime) +target_sources(test-invalid-hsa-runtime PRIVATE test-amdhip-roctx.cpp) +target_link_libraries( + test-invalid-hsa-runtime PRIVATE rocprofiler-register::tests-common roctx::roctx + amdhip::amdhip-invalid) + +add_test( + NAME test-secure-invalid-hsa-runtime + COMMAND $ + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) + +set_tests_properties( + test-secure-invalid-hsa-runtime + PROPERTIES + ENVIRONMENT + "LD_LIBRARY_PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/invalid:${CMAKE_LIBRARY_OUTPUT_DIRECTORY};ROCPROFILER_REGISTER_SECURE=1" + LABELS + "secure" + WILL_FAIL + ON) + +add_test( + NAME test-insecure-invalid-hsa-runtime + COMMAND $ + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) + +set_tests_properties( + test-insecure-invalid-hsa-runtime + PROPERTIES + ENVIRONMENT + "LD_LIBRARY_PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/invalid:${CMAKE_LIBRARY_OUTPUT_DIRECTORY};ROCPROFILER_REGISTER_SECURE=0" + LABELS + "insecure") + +add_executable(test-amdhip-hsart-roctx) +target_sources(test-amdhip-hsart-roctx PRIVATE test-amdhip-hsart-roctx.cpp) +target_link_libraries( + test-amdhip-hsart-roctx PRIVATE rocprofiler-register::tests-common + hsa-runtime::hsa-runtime amdhip::amdhip roctx::roctx) + +add_test( + NAME test-force-rocprofiler-dlopen + COMMAND $ + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) + +set_tests_properties( + test-force-rocprofiler-dlopen + PROPERTIES + ENVIRONMENT + "LD_LIBRARY_PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY};ROCPROFILER_REGISTER_FORCE_LOAD=1;ROCPROFILER_REGISTER_SECURE=yes;ROCPROFILER_REGISTER_VERBOSE=3" + LABELS + "dlopen;secure") + +add_test( + NAME test-rocprofiler-register-library-base-path + COMMAND $ + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) + +set_tests_properties( + test-rocprofiler-register-library-base-path + PROPERTIES + ENVIRONMENT + "LD_LIBRARY_PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY};ROCPROFILER_REGISTER_LIBRARY=librocprofiler64.so;ROCPROFILER_REGISTER_SECURE=yes;ROCPROFILER_REGISTER_VERBOSE=3;ROCPROFILER_REGISTER_MONOCHROME=true" + LABELS + "dlopen;secure") + +add_test( + NAME test-rocprofiler-register-library-absolute-path + COMMAND $ + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) + +set_tests_properties( + test-rocprofiler-register-library-absolute-path + PROPERTIES + ENVIRONMENT + "LD_LIBRARY_PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY};ROCPROFILER_REGISTER_LIBRARY=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/librocprofiler64.so;ROCPROFILER_REGISTER_SECURE=yes;ROCPROFILER_REGISTER_VERBOSE=3;ROCPROFILER_REGISTER_MONOCHROME=true" + LABELS + "dlopen;secure") diff --git a/tests/amdhip/CMakeLists.txt b/tests/amdhip/CMakeLists.txt new file mode 100644 index 0000000000..0e667af2fe --- /dev/null +++ b/tests/amdhip/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# +# + +if(NOT TARGET rocprofiler-register::rocprofiler-register) + find_package(rocprofiler-register REQUIRED) +endif() + +add_library(amdhip SHARED) +add_library(amdhip::amdhip ALIAS amdhip) +target_sources(amdhip PRIVATE amdhip.cpp amdhip.hpp) +target_include_directories(amdhip PUBLIC $) +target_link_libraries( + amdhip + PRIVATE rocprofiler-register::rocprofiler-register + PUBLIC hsa-runtime::hsa-runtime) +set_target_properties( + amdhip + PROPERTIES OUTPUT_NAME amdhip64 + SOVERSION 6 + VERSION 6.0.1) +rocp_register_strip_target(amdhip) + +add_library(amdhip-invalid SHARED) +add_library(amdhip::amdhip-invalid ALIAS amdhip-invalid) +target_sources(amdhip-invalid PRIVATE amdhip.cpp amdhip.hpp) +target_include_directories(amdhip-invalid + PUBLIC $) +target_link_libraries( + amdhip-invalid + PRIVATE rocprofiler-register::rocprofiler-register + PUBLIC hsa-runtime::hsa-runtime-invalid) +set_target_properties( + amdhip-invalid + PROPERTIES OUTPUT_NAME amdhip64 + SOVERSION 6 + VERSION 6.0.1 + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/invalid") +rocp_register_strip_target(amdhip-invalid) diff --git a/tests/amdhip/amdhip.cpp b/tests/amdhip/amdhip.cpp new file mode 100644 index 0000000000..02208d4d17 --- /dev/null +++ b/tests/amdhip/amdhip.cpp @@ -0,0 +1,154 @@ +#include "amdhip.hpp" +#include "hsa-runtime.hpp" + +#include + +#include +#include +#include +#include + +#define ROCP_REG_VERSION \ + ROCPROFILER_REGISTER_COMPUTE_VERSION_3( \ + HIP_VERSION_MAJOR, HIP_VERSION_MINOR, HIP_VERSION_PATCH) + +ROCPROFILER_REGISTER_DEFINE_IMPORT(hip, ROCP_REG_VERSION) + +#ifndef ROCP_REG_FILE_NAME +# define ROCP_REG_FILE_NAME \ + ::std::string{ __FILE__ } \ + .substr(::std::string_view{ __FILE__ }.find_last_of('/') + 1) \ + .c_str() +#endif + +namespace hip +{ +namespace +{ +auto& +get_hip_api_table_impl() +{ + static auto _table = std::atomic{ nullptr }; + return _table; +} + +void +register_profiler_impl() +{ + static auto _const_api_table = HipApiTable{}; + initialize_hip_api_table(&_const_api_table); + + // set this before any recursive opportunity arises + get_hip_api_table_impl().exchange(&_const_api_table); + + // create a copy of the api table for modification by registration + static auto _profiler_api_table = HipApiTable{}; + copy_hip_api_table(&_profiler_api_table, &_const_api_table); + + void* _profiler_api_table_v = static_cast(&_profiler_api_table); + + auto lib_id = rocprofiler_register_library_indentifier_t{}; + auto success = + rocprofiler_register_library_api_table("hip", + &ROCPROFILER_REGISTER_IMPORT_FUNC(hip), + ROCP_REG_VERSION, + &_profiler_api_table_v, + 1, + &lib_id); + + if(success == ROCP_REG_SUCCESS) + { + printf("[%s] hip identifier %lu\n", ROCP_REG_FILE_NAME, lib_id.handle); + auto* _api_table = &_const_api_table; + if(!get_hip_api_table_impl().compare_exchange_strong(_api_table, + &_profiler_api_table)) + { + // with the current impl, if we ever get here, someone is calling one the + // functions in this anonymous namespace that shouldn't + std::cerr + << "register_profiler_impl expected the API table to be the internal " + "implementation and yet it is not. something went wrong.\n"; + abort(); + } + } + else if(success != ROCP_REG_NO_TOOLS) + { + std::cerr << "HIP library failed to register with rocprofiler-register: " + << rocprofiler_register_error_string(success) << "\n"; + exit(EXIT_FAILURE); + } +} + +void +register_profiler() +{ + // this registration scheme is designed to minimize overhead once + // registered (only pay cost of checking atomic boolean) + // once the profiler is registered. If the library has not + // been registered and two or more threads try to register concurrently + // the first thread to acquire the lock below, will block the + // threads until registration is complete. However, + // if the same thread performing the registration re-enters this function + // i.e. this library's API is called during registration, this function + // will prevent a deadlock by not attempting to re-enter the + // the call-once and not releasing any waiting threads by flipping + // the _is_registered field to true. + static auto _is_registered = std::atomic{ false }; + + if(!_is_registered.load(std::memory_order_acquire)) + { + using mutex_t = std::recursive_mutex; + using auto_lock_t = std::unique_lock; + static auto _once = std::once_flag{}; + static auto _mutex = mutex_t{}; + + // defer the lock so we can check for recursion + auto _lk = auto_lock_t{ _mutex, std::defer_lock }; + + // this will be true if the same thread currently executing the call_once invokes + // the library's API while registering the profiler (e.g. tool which wants to + // instrument HIP API invokes a HIP function while registering with the profiler) + // we allow this thread to proceed and access the "const" API table but + // return so it does not flip _is_registered to true, which would result + // in any subsequent threads not waiting until the library is fully registered, + // resulting in missed callbacks for the tools + if(_lk.owns_lock()) return; + + // ensures any subsequent threads wait until the first thread + // finishes registration + _lk.lock(); + // call_once to ensure that we only register once + std::call_once(_once, register_profiler_impl); + // the first thread has completed registration and all + // threads waiting on lock will be released and this + // block will not be entered again + _is_registered.exchange(true, std::memory_order_release); + } +} +} // namespace + +HipApiTable* +get_hip_api_table() +{ + static auto _once = std::once_flag{}; + std::call_once(_once, hsa_init); + register_profiler(); + return get_hip_api_table_impl().load(std::memory_order_relaxed); +} + +void +hip_init() +{ + printf("[%s] %s\n", ROCP_REG_FILE_NAME, __FUNCTION__); +} + +bool _constructed = true; +} // namespace hip + +extern "C" { +void +hip_init(void) +{ + if(hip::_constructed) hip::get_hip_api_table()->hip_init_fn(); +} +} diff --git a/tests/amdhip/amdhip.hpp b/tests/amdhip/amdhip.hpp new file mode 100644 index 0000000000..bdfebdf857 --- /dev/null +++ b/tests/amdhip/amdhip.hpp @@ -0,0 +1,40 @@ +#pragma once + +#define HIP_VERSION_MAJOR 6 +#define HIP_VERSION_MINOR 0 +#define HIP_VERSION_PATCH 1 + +#include + +extern "C" { +// fake hip function +void +hip_init(void) __attribute__((visibility("default"))); +} + +namespace hip +{ +struct HipApiTable +{ + uint64_t size = 0; + decltype(::hip_init)* hip_init_fn = nullptr; +}; + +void +hip_init(); + +// populates hip api table with function pointers +inline void +initialize_hip_api_table(HipApiTable* dst) +{ + dst->size = sizeof(HipApiTable); + dst->hip_init_fn = &::hip::hip_init; +} + +// copies the api table from src to dst +inline void +copy_hip_api_table(HipApiTable* dst, const HipApiTable* src) +{ + *dst = *src; +} +} // namespace hip diff --git a/tests/common/fwd.h b/tests/common/fwd.h new file mode 100644 index 0000000000..571c66c0d4 --- /dev/null +++ b/tests/common/fwd.h @@ -0,0 +1,31 @@ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(ROCP_REG_TEST_WEAK) && ROCP_REG_TEST_WEAK > 0 +# pragma weak hip_init +# pragma weak hsa_init +# pragma weak roctxRangePush +# pragma weak roctxRangePop +#endif + +extern void +hip_init(void); + +extern void +hsa_init(void); + +extern void +roctxRangePush(const char*); + +extern void +roctxRangePop(const char*); + +#ifdef __cplusplus +} +#endif diff --git a/tests/common/fwd.hpp b/tests/common/fwd.hpp new file mode 100644 index 0000000000..6438a2a77b --- /dev/null +++ b/tests/common/fwd.hpp @@ -0,0 +1,101 @@ +#pragma once + +#include "fwd.h" + +#include +#include +#include +#include + +#ifndef ROCP_REG_FILE_NAME +# define ROCP_REG_FILE_NAME \ + ::std::string{ __FILE__ } \ + .substr(::std::string_view{ __FILE__ }.find_last_of('/') + 1) \ + .c_str() +#endif + +namespace +{ +decltype(hip_init)* hip_init_fn = nullptr; +decltype(hsa_init)* hsa_init_fn = nullptr; +decltype(roctxRangePush)* roctxRangePush_fn = nullptr; +decltype(roctxRangePush)* roctxRangePop_fn = nullptr; + +enum rocp_reg_test_modes : uint8_t +{ + ROCP_REG_TEST_NONE = 0x0, + ROCP_REG_TEST_HIP = (1 << 0), + ROCP_REG_TEST_HSA = (1 << 1), + ROCP_REG_TEST_ROCTX = (1 << 2), +}; + +template +inline void +resolve_symbols(int _open_mode = RTLD_LOCAL | RTLD_LAZY) +{ + auto* _open_mode_env = std::getenv("ROCP_REG_TEST_OPEN_MODE"); + if(_open_mode_env) + { + constexpr auto npos = std::string_view::npos; + auto _open_mode_v = std::string_view{ _open_mode_env }; + if(_open_mode_v.find("RTLD_GLOBAL") != npos) + _open_mode = RTLD_GLOBAL; + else if(_open_mode_v.find("RTLD_NOLOAD") != npos) + _open_mode = RTLD_NOLOAD; + else + _open_mode = RTLD_LOCAL; + + if(_open_mode_v.find("RTLD_NOW") != npos) + _open_mode |= RTLD_NOW; + else + _open_mode |= RTLD_LAZY; + } + + auto _resolve_dlopen = [_open_mode](void*& _handle, const char* _lib_name) { + fprintf( + stderr, "[%s] dlopen %s, %i\n", ROCP_REG_FILE_NAME, _lib_name, _open_mode); + _handle = dlopen(_lib_name, _open_mode); + if(!_handle) + { + fprintf(stderr, "Failure opening '%s'\n", _lib_name); + exit(EXIT_FAILURE); + } + }; + + auto _resolve_dlsym = [](auto& _func, void* _handle, const char* _func_name) { + if(!_func && _handle && _func_name) + { + auto* _func_v = dlsym(_handle, _func_name); + if(_func_v) *(void**) (&_func) = _func_v; + } + }; + + void* amdhip_handle = nullptr; + void* hsart_handle = nullptr; + void* roctx_handle = nullptr; + + if constexpr((Idx & ROCP_REG_TEST_HIP) == ROCP_REG_TEST_HIP) + { + hip_init_fn = hip_init; + if(!hip_init_fn) _resolve_dlopen(amdhip_handle, "libamdhip64.so"); + _resolve_dlsym(hip_init_fn, amdhip_handle, "hip_init"); + } + + if constexpr((Idx & ROCP_REG_TEST_HSA) == ROCP_REG_TEST_HSA) + { + hsa_init_fn = hsa_init; + if(!hsa_init_fn) _resolve_dlopen(hsart_handle, "libhsa-runtime64.so"); + _resolve_dlsym(hsa_init_fn, hsart_handle, "hsa_init"); + } + + if constexpr((Idx & ROCP_REG_TEST_ROCTX) == ROCP_REG_TEST_ROCTX) + { + roctxRangePush_fn = roctxRangePush; + roctxRangePop_fn = roctxRangePop; + if(!roctxRangePush_fn || !roctxRangePop_fn) + _resolve_dlopen(roctx_handle, "libroctx64.so"); + _resolve_dlsym(roctxRangePush_fn, roctx_handle, "roctxRangePush"); + _resolve_dlsym(roctxRangePop_fn, roctx_handle, "roctxRangePop"); + } +} +} // namespace diff --git a/tests/hsa-runtime/CMakeLists.txt b/tests/hsa-runtime/CMakeLists.txt new file mode 100644 index 0000000000..5408ea9637 --- /dev/null +++ b/tests/hsa-runtime/CMakeLists.txt @@ -0,0 +1,35 @@ +# +# +# + +if(NOT TARGET rocprofiler-register::rocprofiler-register) + # find_package(rocprofiler-register REQUIRED) +endif() + +add_library(hsa-runtime SHARED) +add_library(hsa-runtime::hsa-runtime ALIAS hsa-runtime) +target_sources(hsa-runtime PRIVATE hsa-runtime.cpp hsa-runtime.hpp) +target_include_directories(hsa-runtime + PUBLIC $) +target_link_libraries(hsa-runtime PRIVATE rocprofiler-register::rocprofiler-register) +set_target_properties( + hsa-runtime + PROPERTIES OUTPUT_NAME hsa-runtime64 + SOVERSION 2 + VERSION 2.1.0) +rocp_register_strip_target(hsa-runtime) + +add_library(hsa-runtime-invalid SHARED) +add_library(hsa-runtime::hsa-runtime-invalid ALIAS hsa-runtime-invalid) +target_sources(hsa-runtime-invalid PRIVATE hsa-runtime.cpp hsa-runtime.hpp) +target_include_directories(hsa-runtime-invalid + PUBLIC $) +target_link_libraries(hsa-runtime-invalid + PRIVATE rocprofiler-register::rocprofiler-register) +set_target_properties( + hsa-runtime-invalid + PROPERTIES OUTPUT_NAME hsa-runtime64 + SOVERSION 1 + VERSION 1.2.3 + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/invalid) +rocp_register_strip_target(hsa-runtime-invalid) diff --git a/tests/hsa-runtime/hsa-runtime.cpp b/tests/hsa-runtime/hsa-runtime.cpp new file mode 100644 index 0000000000..90a1433594 --- /dev/null +++ b/tests/hsa-runtime/hsa-runtime.cpp @@ -0,0 +1,149 @@ +#include "hsa-runtime.hpp" + +#include + +#include +#include +#include +#include + +#define ROCP_REG_VERSION \ + ROCPROFILER_REGISTER_COMPUTE_VERSION_3( \ + HSA_VERSION_MAJOR, HSA_VERSION_MINOR, HSA_VERSION_PATCH) + +ROCPROFILER_REGISTER_DEFINE_IMPORT(hsa, ROCP_REG_VERSION) + +#ifndef ROCP_REG_FILE_NAME +# define ROCP_REG_FILE_NAME \ + ::std::string{ __FILE__ } \ + .substr(::std::string_view{ __FILE__ }.find_last_of('/') + 1) \ + .c_str() +#endif + +namespace hsa +{ +namespace +{ +auto& +get_hsa_api_table_impl() +{ + static auto _table = std::atomic{ nullptr }; + return _table; +} + +void +register_profiler_impl() +{ + static auto _const_api_table = HsaApiTable{}; + initialize_hsa_api_table(&_const_api_table); + + // set this before any recursive opportunity arises + get_hsa_api_table_impl().exchange(&_const_api_table); + + // create a copy of the api table for modification by registration + static auto _profiler_api_table = HsaApiTable{}; + copy_hsa_api_table(&_profiler_api_table, &_const_api_table); + + void* _profiler_api_table_v = static_cast(&_profiler_api_table); + + auto lib_id = rocprofiler_register_library_indentifier_t{}; + auto success = + rocprofiler_register_library_api_table("hsa", + &ROCPROFILER_REGISTER_IMPORT_FUNC(hsa), + ROCP_REG_VERSION, + &_profiler_api_table_v, + 1, + &lib_id); + + if(success == 0) + { + printf("[%s] hsa identifier %lu\n", ROCP_REG_FILE_NAME, lib_id.handle); + auto* _api_table = &_const_api_table; + if(!get_hsa_api_table_impl().compare_exchange_strong(_api_table, + &_profiler_api_table)) + { + // with the current impl, if we ever get here, someone is calling one the + // functions in this anonymous namespace that shouldn't + std::cerr + << "register_profiler_impl expected the API table to be the internal " + "implementation and yet it is not. something went wrong.\n"; + abort(); + } + } + else if(success != ROCP_REG_NO_TOOLS) + { + std::cerr << "HSA library failed to register with rocprofiler-register: " + << rocprofiler_register_error_string(success) << "\n"; + exit(EXIT_FAILURE); + } +} + +void +register_profiler() +{ + // this registration scheme is designed to minimize overhead once + // registered (only pay cost of checking atomic boolean) + // once the profiler is registered. If the library has not + // been registered and two or more threads try to register concurrently + // the first thread to acquire the lock below, will block the + // threads until registration is complete. However, + // if the same thread performing the registration re-enters this function + // i.e. this library's API is called during registration, this function + // will prevent a deadlock by not attempting to re-enter the + // the call-once and not releasing any waiting threads by flipping + // the _is_registered field to true. + static auto _is_registered = std::atomic{ false }; + + if(!_is_registered.load(std::memory_order_acquire)) + { + using mutex_t = std::recursive_mutex; + using auto_lock_t = std::unique_lock; + static auto _once = std::once_flag{}; + static auto _mutex = mutex_t{}; + + // defer the lock so we can check for recursion + auto _lk = auto_lock_t{ _mutex, std::defer_lock }; + + // this will be true if the same thread currently executing the call_once invokes + // the library's API while registering the profiler (e.g. tool which wants to + // instrument HSA API invokes a HSA function while registering with the profiler) + // we allow this thread to proceed and access the "const" API table but + // return so it does not flip _is_registered to true, which would result + // in any subsequent threads not waiting until the library is fully registered, + // resulting in missed callbacks for the tools + if(_lk.owns_lock()) return; + + // ensures any subsequent threads wait until the first thread + // finishes registration + _lk.lock(); + // call_once to ensure that we only register once + std::call_once(_once, register_profiler_impl); + // the first thread has completed registration and all + // threads waiting on lock will be released and this + // block will not be entered again + _is_registered.exchange(true, std::memory_order_release); + } +} +} // namespace + +HsaApiTable* +get_hsa_api_table() +{ + register_profiler(); + return get_hsa_api_table_impl().load(std::memory_order_relaxed); +} + +void +hsa_init() +{ + printf("[%s] %s\n", ROCP_REG_FILE_NAME, __FUNCTION__); +} +} // namespace hsa + +extern "C" { +void +hsa_init(void) +{ + hsa::get_hsa_api_table()->hsa_init_fn(); +} +} diff --git a/tests/hsa-runtime/hsa-runtime.hpp b/tests/hsa-runtime/hsa-runtime.hpp new file mode 100644 index 0000000000..5dbc9c942a --- /dev/null +++ b/tests/hsa-runtime/hsa-runtime.hpp @@ -0,0 +1,40 @@ +#pragma once + +#define HSA_VERSION_MAJOR 2 +#define HSA_VERSION_MINOR 1 +#define HSA_VERSION_PATCH 0 + +#include + +extern "C" { +// fake hsa function +void +hsa_init(void) __attribute__((visibility("default"))); +} + +namespace hsa +{ +struct HsaApiTable +{ + uint64_t size = 0; + decltype(::hsa_init)* hsa_init_fn = nullptr; +}; + +void +hsa_init(); + +// populates hsa api table with function pointers +inline void +initialize_hsa_api_table(HsaApiTable* dst) +{ + dst->size = sizeof(HsaApiTable); + dst->hsa_init_fn = &::hsa::hsa_init; +} + +// copies the api table from src to dst +inline void +copy_hsa_api_table(HsaApiTable* dst, const HsaApiTable* src) +{ + *dst = *src; +} +} // namespace hsa diff --git a/tests/rocprofiler/CMakeLists.txt b/tests/rocprofiler/CMakeLists.txt new file mode 100644 index 0000000000..3fd75325c2 --- /dev/null +++ b/tests/rocprofiler/CMakeLists.txt @@ -0,0 +1,14 @@ +# +# mock rocprofiler library +# +add_library(rocprofiler SHARED) +add_library(rocprofiler::rocprofiler ALIAS rocprofiler) +target_sources(rocprofiler PRIVATE rocprofiler.cpp) +target_include_directories(rocprofiler PUBLIC $ + $) +set_target_properties( + rocprofiler + PROPERTIES OUTPUT_NAME rocprofiler64 + SOVERSION 2 + VERSION 2.0.0) +rocp_register_strip_target(rocprofiler) diff --git a/tests/rocprofiler/rocprofiler.cpp b/tests/rocprofiler/rocprofiler.cpp new file mode 100644 index 0000000000..9b26feb342 --- /dev/null +++ b/tests/rocprofiler/rocprofiler.cpp @@ -0,0 +1,135 @@ + +#include +#include +#include + +#include +#include +#include + +#ifndef ROCP_REG_FILE_NAME +# define ROCP_REG_FILE_NAME \ + ::std::string{ __FILE__ } \ + .substr(::std::string_view{ __FILE__ }.find_last_of('/') + 1) \ + .c_str() +#endif + +namespace rocprofiler +{ +void +hip_init() +{ + printf("[%s] %s\n", ROCP_REG_FILE_NAME, __FUNCTION__); +} + +void +hsa_init() +{ + printf("[%s] %s\n", ROCP_REG_FILE_NAME, __FUNCTION__); +} + +void +roctx_range_push(const char* name) +{ + printf("[%s][push] %s\n", ROCP_REG_FILE_NAME, name); +} + +void +roctx_range_pop(const char* name) +{ + printf("[%s][pop] %s\n", ROCP_REG_FILE_NAME, name); +} +} // namespace rocprofiler + +extern "C" { +struct rocprofiler_configure_result_t +{ + int (*initialize)(void*) = nullptr; + int (*finalize)(void*) = nullptr; + void* data = nullptr; +}; + +rocprofiler_configure_result_t* +rocprofiler_configure(uint32_t, const char*, uint32_t, uint32_t) + __attribute__((visibility("default"))); + +int +rocprofiler_set_api_table(const char*, uint64_t, uint64_t, void**, uint64_t) + __attribute__((visibility("default"))); + +rocprofiler_configure_result_t* +rocprofiler_configure(uint32_t version, + const char* runtime_version, + uint32_t priority, + uint32_t tool_id) +{ + (void) version; + (void) runtime_version; + (void) priority; + (void) tool_id; + + return nullptr; +} + +int +rocprofiler_set_api_table(const char* name, + uint64_t lib_version, + uint64_t lib_instance, + void** tables, + uint64_t num_tables) +{ + printf("[%s] %s :: %lu :: %lu :: %lu\n", + ROCP_REG_FILE_NAME, + name, + lib_version, + lib_instance, + num_tables); + + using hip_table_t = hip::HipApiTable; + using hsa_table_t = hsa::HsaApiTable; + using roctx_table_t = roctx::ROCTxApiTable; + + auto* _wrap_v = std::getenv("ROCP_REG_TEST_WRAP"); + bool _wrap = (_wrap_v != nullptr && std::stoi(_wrap_v) != 0); + + if(_wrap) + { + if(num_tables != 1) + throw std::runtime_error{ std::string{ "unexpected number of tables: " } + + std::to_string(num_tables) }; + + if(tables == nullptr) throw std::runtime_error{ "nullptr to tables" }; + if(tables[0] == nullptr) throw std::runtime_error{ "nullptr to tables[0]" }; + + if(std::string_view{ name } == "hip") + { + hip_table_t* _table = static_cast(tables[0]); + _table->hip_init_fn = &rocprofiler::hip_init; + } + else if(std::string_view{ name } == "hsa") + { + hsa_table_t* _table = static_cast(tables[0]); + _table->hsa_init_fn = &rocprofiler::hsa_init; + } + else if(std::string_view{ name } == "roctx") + { + roctx_table_t* _table = static_cast(tables[0]); + _table->roctxRangePush_fn = &rocprofiler::roctx_range_push; + _table->roctxRangePop_fn = &rocprofiler::roctx_range_pop; + } + } + + return 0; +} +} + +void + rocp_ctor(void) __attribute__((constructor)); +bool rocprofiler_test_lib_link = false; + +void +rocp_ctor() +{ + rocprofiler_test_lib_link = true; + printf("[%s] %s\n", ROCP_REG_FILE_NAME, __FUNCTION__); +} diff --git a/tests/roctx/CMakeLists.txt b/tests/roctx/CMakeLists.txt new file mode 100644 index 0000000000..05f9f5bac1 --- /dev/null +++ b/tests/roctx/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# +# + +if(NOT TARGET rocprofiler-register::rocprofiler-register) + find_package(rocprofiler-register REQUIRED) +endif() + +add_library(roctx SHARED) +add_library(roctx::roctx ALIAS roctx) +target_sources(roctx PRIVATE roctx.cpp roctx.hpp) +target_include_directories(roctx PUBLIC $) +target_link_libraries(roctx PRIVATE rocprofiler-register::rocprofiler-register) +set_target_properties( + roctx + PROPERTIES OUTPUT_NAME roctx64 + SOVERSION 4 + VERSION 4.6.1) +rocp_register_strip_target(roctx) diff --git a/tests/roctx/roctx.cpp b/tests/roctx/roctx.cpp new file mode 100644 index 0000000000..4d428a67ca --- /dev/null +++ b/tests/roctx/roctx.cpp @@ -0,0 +1,170 @@ +#ifdef NDEBUG +# undef NDEBUG +#endif + +#include "roctx.hpp" + +#include + +#include +#include +#include +#include +#include + +#define ROCP_REG_VERSION \ + ROCPROFILER_REGISTER_COMPUTE_VERSION_3( \ + ROCTX_VERSION_MAJOR, ROCTX_VERSION_MINOR, ROCTX_VERSION_PATCH) + +ROCPROFILER_REGISTER_DEFINE_IMPORT(roctx, ROCP_REG_VERSION) + +#ifndef ROCP_REG_FILE_NAME +# define ROCP_REG_FILE_NAME \ + ::std::string{ __FILE__ } \ + .substr(::std::string_view{ __FILE__ }.find_last_of('/') + 1) \ + .c_str() +#endif + +namespace roctx +{ +namespace +{ +auto& +get_roctx_api_table_impl() +{ + static auto _table = std::atomic{ nullptr }; + return _table; +} + +void +register_profiler_impl() +{ + static auto _const_api_table = ROCTxApiTable{}; + initialize_roctx_api_table(&_const_api_table); + + // set this before any recursive opportunity arises + get_roctx_api_table_impl().exchange(&_const_api_table); + + // create a copy of the api table for modification by registration + static auto _profiler_api_table = ROCTxApiTable{}; + copy_roctx_api_table(&_profiler_api_table, &_const_api_table); + + void* _profiler_api_table_v = static_cast(&_profiler_api_table); + + auto lib_id = rocprofiler_register_library_indentifier_t{}; + auto success = + rocprofiler_register_library_api_table("roctx", + &ROCPROFILER_REGISTER_IMPORT_FUNC(roctx), + ROCP_REG_VERSION, + &_profiler_api_table_v, + 1, + &lib_id); + + if(success == 0) + { + printf("[%s] roctx identifier %lu\n", ROCP_REG_FILE_NAME, lib_id.handle); + auto* _api_table = &_const_api_table; + if(!get_roctx_api_table_impl().compare_exchange_strong(_api_table, + &_profiler_api_table)) + { + // with the current impl, if we ever get here, someone is calling one the + // functions in this anonymous namespace that shouldn't + std::cerr + << "register_profiler_impl expected the API table to be the internal " + "implementation and yet it is not. something went wrong.\n"; + abort(); + } + } + else if(success != ROCP_REG_NO_TOOLS) + { + std::cerr << "ROCTx library failed to register with rocprofiler-register: " + << rocprofiler_register_error_string(success) << "\n"; + exit(EXIT_FAILURE); + } +} + +void +register_profiler() +{ + // this registration scheme is designed to minimize overhead once + // registered (only pay cost of checking atomic boolean) + // once the profiler is registered. If the library has not + // been registered and two or more threads try to register concurrently + // the first thread to acquire the lock below, will block the + // threads until registration is complete. However, + // if the same thread performing the registration re-enters this function + // i.e. this library's API is called during registration, this function + // will prevent a deadlock by not attempting to re-enter the + // the call-once and not releasing any waiting threads by flipping + // the _is_registered field to true. + static auto _is_registered = std::atomic{ false }; + + if(!_is_registered.load(std::memory_order_acquire)) + { + using mutex_t = std::recursive_mutex; + using auto_lock_t = std::unique_lock; + static auto _once = std::once_flag{}; + static auto _mutex = mutex_t{}; + + // defer the lock so we can check for recursion + auto _lk = auto_lock_t{ _mutex, std::defer_lock }; + + // this will be true if the same thread currently executing the call_once invokes + // the library's API while registering the profiler (e.g. tool which wants to + // instrument ROCTX API invokes a ROCTX function while registering with the + // profiler) we allow this thread to proceed and access the "const" API table but + // return so it does not flip _is_registered to true, which would result + // in any subsequent threads not waiting until the library is fully registered, + // resulting in missed callbacks for the tools + if(_lk.owns_lock()) return; + + // ensures any subsequent threads wait until the first thread + // finishes registration + _lk.lock(); + // call_once to ensure that we only register once + std::call_once(_once, register_profiler_impl); + // the first thread has completed registration and all + // threads waiting on lock will be released and this + // block will not be entered again + _is_registered.exchange(true, std::memory_order_release); + } +} +} // namespace + +ROCTxApiTable* +get_roctx_api_table() +{ + register_profiler(); + return get_roctx_api_table_impl().load(std::memory_order_relaxed); +} + +void +roctx_range_push(const char* name) +{ + printf("[%s][push] %s\n", ROCP_REG_FILE_NAME, name); +} + +void +roctx_range_pop(const char* name) +{ + printf("[%s][pop] %s\n", ROCP_REG_FILE_NAME, name); +} +} // namespace roctx + +extern "C" { +void +roctxRangePush(const char* name) +{ + auto&& _func = roctx::get_roctx_api_table()->roctxRangePush_fn; + assert(_func != nullptr); + _func(name); +} + +void +roctxRangePop(const char* name) +{ + auto&& _func = roctx::get_roctx_api_table()->roctxRangePop_fn; + if(_func == nullptr) throw std::runtime_error("nullptr"); + _func(name); +} +} diff --git a/tests/roctx/roctx.hpp b/tests/roctx/roctx.hpp new file mode 100644 index 0000000000..ce2ae3ec99 --- /dev/null +++ b/tests/roctx/roctx.hpp @@ -0,0 +1,46 @@ +#pragma once + +#define ROCTX_VERSION_MAJOR 4 +#define ROCTX_VERSION_MINOR 6 +#define ROCTX_VERSION_PATCH 1 + +#include + +extern "C" { +void +roctxRangePush(const char*) __attribute__((visibility("default"))); +void +roctxRangePop(const char*) __attribute__((visibility("default"))); +} + +namespace roctx +{ +struct ROCTxApiTable +{ + uint64_t size = 0; + decltype(::roctxRangePush)* roctxRangePush_fn = nullptr; + decltype(::roctxRangePop)* roctxRangePop_fn = nullptr; +}; + +void +roctx_range_push(const char*); + +void +roctx_range_pop(const char*); + +// populates roctx api table with function pointers +inline void +initialize_roctx_api_table(ROCTxApiTable* dst) +{ + dst->size = sizeof(ROCTxApiTable); + dst->roctxRangePush_fn = &::roctx::roctx_range_push; + dst->roctxRangePop_fn = &::roctx::roctx_range_pop; +} + +// copies the api table from src to dst +inline void +copy_roctx_api_table(ROCTxApiTable* dst, const ROCTxApiTable* src) +{ + *dst = *src; +} +} // namespace roctx diff --git a/tests/start-up-test/CMakeLists.txt b/tests/start-up-test/CMakeLists.txt new file mode 100644 index 0000000000..407eb4e3cc --- /dev/null +++ b/tests/start-up-test/CMakeLists.txt @@ -0,0 +1,3 @@ +# +# +# diff --git a/tests/test-amdhip-ctor-mt.cpp b/tests/test-amdhip-ctor-mt.cpp new file mode 100644 index 0000000000..60190a0bd5 --- /dev/null +++ b/tests/test-amdhip-ctor-mt.cpp @@ -0,0 +1,72 @@ + +#include +#include +#include +#include +#include +#include + +#include "common/fwd.hpp" + +void +run(const std::string& name, pthread_barrier_t* _barrier) +{ + if(_barrier) pthread_barrier_wait(_barrier); + + if(hsa_init_fn) + { + if(_barrier) pthread_barrier_wait(_barrier); + hsa_init_fn(); + } + + if(hip_init_fn) + { + if(_barrier) pthread_barrier_wait(_barrier); + hip_init_fn(); + } + + if(roctxRangePush_fn) + { + if(_barrier) pthread_barrier_wait(_barrier); + roctxRangePush_fn(name.c_str()); + } + + if(roctxRangePop_fn) + { + if(_barrier) pthread_barrier_wait(_barrier); + roctxRangePop_fn(name.c_str()); + } +} + +auto +run_threads(unsigned long n) +{ + resolve_symbols(); + + auto threads = std::vector{}; + auto names = std::vector{}; + + for(unsigned long i = 0; i < n; ++i) + names.emplace_back(std::string{ "thread-" } + std::to_string(i)); + + auto _barrier = pthread_barrier_t{}; + pthread_barrier_init(&_barrier, nullptr, n); + + for(unsigned long i = 0; i < n; ++i) + threads.emplace_back(run, names.at(i), &_barrier); + + for(auto& itr : threads) + itr.join(); + + pthread_barrier_destroy(&_barrier); + + return n; +} + +auto run_n = run_threads(4); + +int +main() +{ + return (run_n == 4) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/tests/test-amdhip-ctor.cpp b/tests/test-amdhip-ctor.cpp new file mode 100644 index 0000000000..64fd53c9d1 --- /dev/null +++ b/tests/test-amdhip-ctor.cpp @@ -0,0 +1,42 @@ + +#include +#include +#include + +#include "common/fwd.hpp" + +std::string +run(const std::string& name) +{ + resolve_symbols(); + + if(hsa_init_fn) + { + hsa_init_fn(); + } + + if(hip_init_fn) + { + hip_init_fn(); + } + + if(roctxRangePush_fn) + { + roctxRangePush_fn(name.c_str()); + } + + if(roctxRangePop_fn) + { + roctxRangePop_fn(name.c_str()); + } + + return name; +} + +auto run_name = run("thread-ctor"); + +int +main() +{ + return (run_name == "thread-ctor") ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/tests/test-amdhip-hsart-roctx.cpp b/tests/test-amdhip-hsart-roctx.cpp new file mode 100644 index 0000000000..7e4e34f4e3 --- /dev/null +++ b/tests/test-amdhip-hsart-roctx.cpp @@ -0,0 +1,43 @@ + +#include +#include + +#include "common/fwd.hpp" + +void +run(const std::string& name) +{ + if(hip_init_fn) + { + hip_init_fn(); + } + + if(hsa_init_fn) + { + hsa_init_fn(); + } + + if(roctxRangePush_fn) + { + roctxRangePush_fn(name.c_str()); + } + + if(roctxRangePop_fn) + { + roctxRangePop_fn(name.c_str()); + } +} + +int +main(int argc, char** argv) +{ + unsigned long n = 1; + if(argc > 1) n = std::stoul(argv[1]); + + resolve_symbols(); + + for(unsigned long i = 0; i < n; ++i) + run("thread-main"); + + return 0; +} diff --git a/tests/test-amdhip-roctx-mt.cpp b/tests/test-amdhip-roctx-mt.cpp new file mode 100644 index 0000000000..49f8a32056 --- /dev/null +++ b/tests/test-amdhip-roctx-mt.cpp @@ -0,0 +1,72 @@ + +#include +#include +#include +#include +#include + +#include "common/fwd.hpp" + +void +run(const std::string& name, pthread_barrier_t* _barrier) +{ + if(_barrier) pthread_barrier_wait(_barrier); + + if(hip_init_fn) + { + if(_barrier) pthread_barrier_wait(_barrier); + hip_init_fn(); + } + + if(hsa_init_fn) + { + if(_barrier) pthread_barrier_wait(_barrier); + hsa_init_fn(); + } + + if(roctxRangePush_fn) + { + if(_barrier) pthread_barrier_wait(_barrier); + roctxRangePush_fn(name.c_str()); + } + + if(roctxRangePop_fn) + { + if(_barrier) pthread_barrier_wait(_barrier); + roctxRangePop_fn(name.c_str()); + } +} + +void +run_threads(unsigned long n) +{ + auto threads = std::vector{}; + auto names = std::vector{}; + + for(unsigned long i = 0; i < n; ++i) + names.emplace_back(std::string{ "thread-" } + std::to_string(i)); + + auto _barrier = pthread_barrier_t{}; + pthread_barrier_init(&_barrier, nullptr, n); + + for(unsigned long i = 0; i < n; ++i) + threads.emplace_back(run, names.at(i), &_barrier); + + for(auto& itr : threads) + itr.join(); + + pthread_barrier_destroy(&_barrier); +} + +int +main(int argc, char** argv) +{ + unsigned long n = 4; + if(argc > 1) n = std::stoul(argv[1]); + + resolve_symbols(); + + run_threads(n); + + return 0; +} diff --git a/tests/test-amdhip-roctx.cpp b/tests/test-amdhip-roctx.cpp new file mode 100644 index 0000000000..142480a9c7 --- /dev/null +++ b/tests/test-amdhip-roctx.cpp @@ -0,0 +1,43 @@ + +#include +#include + +#include "common/fwd.hpp" + +void +run(const std::string& name) +{ + if(hip_init_fn) + { + hip_init_fn(); + } + + if(hsa_init_fn) + { + hsa_init_fn(); + } + + if(roctxRangePush_fn) + { + roctxRangePush_fn(name.c_str()); + } + + if(roctxRangePop_fn) + { + roctxRangePop_fn(name.c_str()); + } +} + +int +main(int argc, char** argv) +{ + unsigned long n = 1; + if(argc > 1) n = std::stoul(argv[1]); + + resolve_symbols(); + + for(unsigned long i = 0; i < n; ++i) + run("thread-main"); + + return 0; +}