Adding rocprofilerv2
Change-Id: Ic0cc280ba207d2b8f6ccae1cd4ac3184152fc1ad
[ROCm/rocprofiler commit: 8032adb64f]
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
add_subdirectory(profiler)
|
||||
add_subdirectory(tracer)
|
||||
@@ -0,0 +1,219 @@
|
||||
# Handle HSA Interception Tool Tests
|
||||
find_package(hsa-runtime64 REQUIRED CONFIG PATHS ${ROCM_PATH})
|
||||
file(GLOB PUBLIC_API_HEADERS "${PROJECT_SOURCE_DIR}/inc/*.h")
|
||||
foreach(header ${PUBLIC_API_HEADERS})
|
||||
get_filename_component(header_subdir ${header} DIRECTORY)
|
||||
install(FILES ${header}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/${header_subdir}
|
||||
COMPONENT runtime)
|
||||
endforeach()
|
||||
|
||||
get_property(HSA_RUNTIME_INCLUDE_DIRECTORIES TARGET hsa-runtime64::hsa-runtime64 PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
|
||||
find_file(HSA_H hsa.h
|
||||
PATHS ${HSA_RUNTIME_INCLUDE_DIRECTORIES}
|
||||
PATH_SUFFIXES hsa
|
||||
NO_DEFAULT_PATH
|
||||
REQUIRED)
|
||||
get_filename_component(HSA_RUNTIME_INC_PATH ${HSA_H} DIRECTORY)
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${HSA_RUNTIME_INC_PATH})
|
||||
|
||||
find_package(Clang REQUIRED CONFIG
|
||||
PATHS "${ROCM_PATH}"
|
||||
PATH_SUFFIXES "llvm/lib/cmake/clang")
|
||||
|
||||
# Set the HIP language runtime link flags as FindHIP does not set them.
|
||||
set(CMAKE_INSTALL_TESTDIR test/${PROJECT_NAME})
|
||||
set(CMAKE_EXECUTABLE_RUNTIME_HIP_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG})
|
||||
set(CMAKE_EXECUTABLE_RUNTIME_HIP_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP})
|
||||
set(CMAKE_EXECUTABLE_RPATH_LINK_HIP_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG})
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${ROCM_PATH}/lib/cmake/hip")
|
||||
set(CMAKE_HIP_ARCHITECTURES OFF)
|
||||
find_package(HIP REQUIRED MODULE)
|
||||
|
||||
#Enable CLANG-TIDY for static analysis
|
||||
# search for clang-tidy
|
||||
find_program(CLANG_TIDY_EXE NAMES "clang-tidy")
|
||||
if (CLANG_TIDY_EXE)
|
||||
set(CMAKE_CXX_CLANG_TIDY
|
||||
clang-tidy;
|
||||
-format-style='file';
|
||||
-header-filter=${CMAKE_CURRENT_SOURCE_DIR};
|
||||
)
|
||||
endif()
|
||||
# ############################################################################################################################################
|
||||
# App Based FeatureTests
|
||||
# ############################################################################################################################################
|
||||
|
||||
# installing the golden traces
|
||||
file(GLOB files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "gtests/apps/goldentraces/*.txt")
|
||||
foreach(file ${files})
|
||||
configure_file(${file} ${PROJECT_BINARY_DIR}/tests/featuretests/profiler/${file} COPYONLY)
|
||||
endforeach()
|
||||
|
||||
# Compile Applications
|
||||
# hip_helloworld
|
||||
set_source_files_properties(gtests/apps/hip/hello_world.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
hip_add_executable(hip_helloworld gtests/apps/hip/hello_world.cpp)
|
||||
set_target_properties(hip_helloworld PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/tests/featuretests/profiler/gtests/apps")
|
||||
|
||||
|
||||
#hip_vectoradd
|
||||
set_source_files_properties(gtests/apps/hip/vector_add.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
hip_add_executable(hip_vectoradd gtests/apps/hip/vector_add.cpp)
|
||||
set_target_properties(hip_vectoradd PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/tests/featuretests/profiler/gtests/apps")
|
||||
|
||||
|
||||
#openmp_helloworld
|
||||
# find_package(hip REQUIRED)
|
||||
# find_package(OpenMP)
|
||||
# if(OpenMP_CXX_FOUND)
|
||||
# # Source files.
|
||||
# set_source_files_properties(gtests/apps/openmp/hello_world.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
# hip_add_executable(openmp_helloworld gtests/apps/openmp/hello_world.cpp)
|
||||
# set_target_properties(openmp_helloworld PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/tests/featuretests/profiler/gtests/apps")
|
||||
|
||||
# # Link Libraries - HIP Device and OpenMP.
|
||||
# target_compile_options(openmp_helloworld PRIVATE ${OpenMP_CXX_FLAGS})
|
||||
# target_link_libraries(openmp_helloworld PRIVATE hip::device ${OpenMP_CXX_FLAGS})
|
||||
# endif()
|
||||
|
||||
#mpi_vectoradd
|
||||
find_package(MPI)
|
||||
if (MPI_CXX_FOUND)
|
||||
include_directories(SYSTEM ${MPI_INCLUDE_PATH})
|
||||
set_source_files_properties(gtests/apps/mpi/vector_add.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
hip_add_executable(mpi_vectoradd gtests/apps/mpi/vector_add.cpp)
|
||||
set_target_properties(mpi_vectoradd PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/tests/featuretests/profiler/gtests/apps")
|
||||
target_link_libraries(mpi_vectoradd ${MPI_C_LIBRARIES} stdc++fs)
|
||||
endif()
|
||||
|
||||
#hsa-mem_async_copy -- Not Enabled for Now
|
||||
# set_source_files_properties(gtests/apps/hsa/async_mem_copy.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
# hip_add_executable(hsa_async_mem_copy gtests/apps/hsa/async_mem_copy.cpp)
|
||||
# set_target_properties(hsa_async_mem_copy PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/tests/featuretests/profiler/gtests/apps")
|
||||
# target_link_libraries(hsa_async_mem_copy hsa-runtime64::hsa-runtime64 Threads::Threads dl stdc++fs)
|
||||
|
||||
|
||||
# Setup testing
|
||||
enable_testing()
|
||||
find_package(GTest REQUIRED)
|
||||
|
||||
# Add test cpp file
|
||||
add_executable(runFeatureTests
|
||||
gtests/gtests_main.cpp
|
||||
utils/test_utils.cpp
|
||||
gtests/apps/profiler_gtest.cpp
|
||||
gtests/apps/hip/hello_world_gtest.cpp
|
||||
gtests/apps/hip/vector_add_gtest.cpp
|
||||
gtests/apps/hsa/async_mem_copy_gtest.cpp
|
||||
gtests/apps/mpi/vector_add_gtest.cpp
|
||||
# gtests/apps/openmp/hello_world_gtest.cpp
|
||||
gtests/functional/loadunload_gtest.cpp
|
||||
)
|
||||
|
||||
target_include_directories(runFeatureTests PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/tests/featuretests/profiler)
|
||||
# Link test executable against gtest & gtest_main
|
||||
target_link_libraries(runFeatureTests PRIVATE hsa-runtime64::hsa-runtime64
|
||||
GTest::gtest GTest::gtest_main
|
||||
Threads::Threads dl stdc++fs)
|
||||
add_dependencies(tests runFeatureTests)
|
||||
|
||||
# ############################################################################################################################################
|
||||
# Functional Tests
|
||||
# ############################################################################################################################################
|
||||
|
||||
file(GLOB ROCPROFILER_UTIL_SRC_FILES ${PROJECT_SOURCE_DIR}/src/utils/helper.cpp)
|
||||
|
||||
set_source_files_properties(gtests/functional/multithread_gtest.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
# # Add test cpp file
|
||||
hip_add_executable(runFunctionalTests
|
||||
gtests/gtests_main.cpp
|
||||
${ROCPROFILER_UTIL_SRC_FILES}
|
||||
utils/test_utils.cpp
|
||||
#gtests/functional/multithread_gtest.cpp
|
||||
)
|
||||
target_include_directories(runFunctionalTests PRIVATE ${TEST_DIR} ${ROOT_DIR} ${HSA_RUNTIME_INC_PATH} ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/tests/featuretests/profiler)
|
||||
# # Link test executable against gtest & gtest_main
|
||||
target_link_libraries(runFunctionalTests PRIVATE ${ROCPROFILER_TARGET} ${ROCPROFILER_TARGET} hsa-runtime64::hsa-runtime64
|
||||
GTest::gtest GTest::gtest_main
|
||||
Threads::Threads dl stdc++fs amd_comgr)
|
||||
add_dependencies(tests runFunctionalTests)
|
||||
|
||||
# ############################################################################################################################################
|
||||
# Discrete Tests
|
||||
# ############################################################################################################################################
|
||||
|
||||
# Multi-Queue Dependency Test
|
||||
function(generate_hsaco TARGET_ID INPUT_FILE OUTPUT_FILE)
|
||||
separate_arguments(CLANG_ARG_LIST UNIX_COMMAND
|
||||
"-O2 -x cl -Xclang -finclude-default-header -cl-denorms-are-zero -cl-std=CL2.0 -Wl,--build-id=sha1
|
||||
-target amdgcn-amd-amdhsa -mcpu=${TARGET_ID} -o ${OUTPUT_FILE} ${INPUT_FILE}")
|
||||
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/tests/featuretests/profiler/${OUTPUT_FILE}
|
||||
COMMAND clang ${CLANG_ARG_LIST}
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/tests/featuretests/profiler/
|
||||
DEPENDS ${INPUT_FILE} clang
|
||||
COMMENT "Building ${OUTPUT_FILE}..."
|
||||
-E copy ${PROJECT_BINARY_DIR}/tests/featuretests/profiler/${OUTPUT_FILE} ${PROJECT_BINARY_DIR}/tests/featuretests/profiler/${target_id}_copy.hsaco
|
||||
VERBATIM)
|
||||
set(HSACO_TARGET_LIST ${HSACO_TARGET_LIST} ${PROJECT_BINARY_DIR}/tests/featuretests/profiler/${OUTPUT_FILE} PARENT_SCOPE)
|
||||
endfunction(generate_hsaco)
|
||||
|
||||
foreach(target_id ${GPU_TARGETS})
|
||||
## generate kernel bitcodes
|
||||
generate_hsaco(${target_id} ${CMAKE_CURRENT_SOURCE_DIR}/discretetests/binary/copy.cl ${target_id}_copy.hsaco)
|
||||
endforeach(target_id)
|
||||
add_custom_target(hsaco_targets DEPENDS ${HSACO_TARGET_LIST})
|
||||
|
||||
add_executable(multiqueue_testapp discretetests/binary/multiqueue_testapp.cpp)
|
||||
target_include_directories(multiqueue_testapp PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/inc ${PROJECT_SOURCE_DIR}/tests/featuretests/profiler)
|
||||
# Link test executable against gtest & gtest_main
|
||||
target_link_libraries(multiqueue_testapp PRIVATE ${ROCPROFILER_TARGET} hsa-runtime64::hsa-runtime64 GTest::gtest GTest::gtest_main stdc++fs Threads::Threads amd_comgr dl)
|
||||
add_dependencies(multiqueue_testapp hsaco_targets)
|
||||
add_dependencies(tests multiqueue_testapp )
|
||||
|
||||
add_executable(profiler_multiqueue_test discretetests/binary/multiqueue_test.cpp utils/csv_parser.cpp utils/test_utils.cpp)
|
||||
target_include_directories(profiler_multiqueue_test PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/tests/featuretests/profiler)
|
||||
target_link_libraries(profiler_multiqueue_test PRIVATE hsa-runtime64::hsa-runtime64 Threads::Threads dl stdc++fs amd_comgr)
|
||||
add_dependencies(tests profiler_multiqueue_test)
|
||||
|
||||
##### Profiler Discrete API Test #######
|
||||
set_source_files_properties(discretetests/api/multithreaded_test.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
hip_add_executable ( profiler_api_test discretetests/api/multithreaded_test.cpp utils/test_utils.cpp )
|
||||
target_link_libraries ( profiler_api_test ${ROCPROFILER_TARGET} ${ROCPROFILER_TARGET} hsa-runtime64::hsa-runtime64 Threads::Threads dl stdc++fs amd_comgr )
|
||||
target_include_directories(profiler_api_test PRIVATE ${TEST_DIR} ${ROOT_DIR} ${HSA_RUNTIME_INC_PATH} ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/tests/featuretests/profiler)
|
||||
add_dependencies(tests profiler_api_test)
|
||||
|
||||
set_source_files_properties(discretetests/api/spm_test.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
hip_add_executable ( profiler_api_spm_test discretetests/api/spm_test.cpp utils/test_utils.cpp )
|
||||
target_link_libraries ( profiler_api_spm_test ${ROCPROFILER_TARGET} ${ROCPROFILER_TARGET} hsa-runtime64::hsa-runtime64 Threads::Threads dl stdc++fs )
|
||||
target_include_directories(profiler_api_spm_test PRIVATE ${TEST_DIR} ${ROOT_DIR} ${HSA_RUNTIME_INC_PATH} ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/tests/featuretests/profiler)
|
||||
add_dependencies(tests profiler_api_spm_test)
|
||||
|
||||
|
||||
##### Profiler Discrete Binary Tests #######
|
||||
set_source_files_properties(discretetests/binary/multiprocess_test.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
hip_add_executable(profiler_multiprocess_test discretetests/binary/multiprocess_test.cpp utils/csv_parser.cpp utils/test_utils.cpp)
|
||||
target_include_directories(profiler_multiprocess_test PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/tests/featuretests/profiler)
|
||||
target_link_libraries(profiler_multiprocess_test PRIVATE hsa-runtime64::hsa-runtime64 Threads::Threads dl stdc++fs amd_comgr)
|
||||
add_dependencies(tests profiler_multiprocess_test)
|
||||
|
||||
set_source_files_properties(discretetests/binary/multithreaded_testapp.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
hip_add_executable(multithreaded_testapp discretetests/binary/multithreaded_testapp.cpp utils/test_utils.cpp)
|
||||
target_include_directories(multithreaded_testapp PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/featuretests/profiler)
|
||||
target_link_libraries(multithreaded_testapp hsa-runtime64::hsa-runtime64 Threads::Threads dl stdc++fs amd_comgr)
|
||||
add_dependencies(tests multithreaded_testapp)
|
||||
|
||||
set_source_files_properties(discretetests/binary/multithreaded_test.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
hip_add_executable(profiler_multithreaded_test discretetests/binary/multithreaded_test.cpp utils/csv_parser.cpp utils/test_utils.cpp)
|
||||
target_include_directories(profiler_multithreaded_test PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/featuretests/profiler)
|
||||
target_link_libraries(profiler_multithreaded_test PRIVATE hsa-runtime64::hsa-runtime64 Threads::Threads dl stdc++fs amd_comgr)
|
||||
add_dependencies(tests profiler_multithreaded_test)
|
||||
|
||||
add_test(AllTests runFeatureTests)
|
||||
|
||||
# Copy scripts, input files to samples folder
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/discretetests/run_discrete_tests.sh ${PROJECT_BINARY_DIR}/tests/featuretests/profiler/ COPYONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/discretetests/basic_metrics.txt ${PROJECT_BINARY_DIR}/tests/featuretests/profiler/ COPYONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gtests/apps/mpi/mpi_run.sh ${PROJECT_BINARY_DIR}/tests/featuretests/profiler/gtests/apps/ COPYONLY)
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/******************************************************************************
|
||||
Copyright (c) 2018 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 <hip/hip_runtime.h>
|
||||
#include <rocprofiler.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
/** \mainpage ROC Profiler API Test
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test is to test ROCmTools APIs from multiple threads
|
||||
* and verify if each API succeeds and multiple contexts are collected and
|
||||
* printed.
|
||||
*
|
||||
* An empty kernel is launched on multiple threads and profiling context is
|
||||
* collected and printed from each thread.
|
||||
*/
|
||||
|
||||
|
||||
// function to check profiler API status
|
||||
auto CheckApi = [](rocprofiler_status_t status) {
|
||||
if (status != ROCPROFILER_STATUS_SUCCESS) {
|
||||
std::cout << "ROCmTools API Error" << std::endl;
|
||||
}
|
||||
assert(status == ROCPROFILER_STATUS_SUCCESS);
|
||||
};
|
||||
|
||||
// empty kernel
|
||||
__global__ void kernel() { printf("empty kernel\n"); }
|
||||
|
||||
// callback function to dump profiler data
|
||||
void FlushCallback(const rocprofiler_record_header_t* record,
|
||||
const rocprofiler_record_header_t* end_record, rocprofiler_session_id_t session_id,
|
||||
rocprofiler_buffer_id_t buffer_id) {
|
||||
while (record < end_record) {
|
||||
if (!record) break;
|
||||
if (record->kind == ROCPROFILER_PROFILER_RECORD) {
|
||||
const rocprofiler_record_profiler_t* profiler_record =
|
||||
reinterpret_cast<const rocprofiler_record_profiler_t*>(record);
|
||||
size_t name_length;
|
||||
CheckApi(rocprofiler_query_kernel_info_size(ROCPROFILER_KERNEL_NAME, profiler_record->kernel_id,
|
||||
&name_length));
|
||||
const char* kernel_name_c = static_cast<const char*>(malloc(name_length * sizeof(char)));
|
||||
CheckApi(rocprofiler_query_kernel_info(ROCPROFILER_KERNEL_NAME, profiler_record->kernel_id,
|
||||
&kernel_name_c));
|
||||
int gpu_index = profiler_record->gpu_id.handle;
|
||||
uint64_t start_time = profiler_record->timestamps.begin.value;
|
||||
uint64_t end_time = profiler_record->timestamps.end.value;
|
||||
printf(
|
||||
"Kernel Info:\n\tGPU Index: %d\n\tKernel Name: %s\n\tStart "
|
||||
"Time: "
|
||||
"%lu\n\tEnd Time: %lu\n",
|
||||
gpu_index, kernel_name_c, start_time, end_time);
|
||||
}
|
||||
CheckApi(rocprofiler_next_record(record, &record, session_id, buffer_id));
|
||||
}
|
||||
}
|
||||
|
||||
// launches an empty kernel in profiler context
|
||||
void KernelLaunch() {
|
||||
// run empty kernel
|
||||
kernel<<<1, 1>>>();
|
||||
hipDeviceSynchronize();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Get the system cores
|
||||
int num_cpu_cores = GetNumberOfCores();
|
||||
|
||||
// create as many threads as number of cores in system
|
||||
std::vector<std::thread> threads(num_cpu_cores);
|
||||
|
||||
// inititalize profiler by creating rocmtool object
|
||||
CheckApi(rocprofiler_initialize());
|
||||
|
||||
// Counter Collection with timestamps
|
||||
rocprofiler_session_id_t session_id;
|
||||
std::vector<const char*> counters;
|
||||
counters.emplace_back("SQ_WAVES");
|
||||
|
||||
CheckApi(rocprofiler_create_session(ROCPROFILER_KERNEL_REPLAY_MODE, &session_id));
|
||||
|
||||
rocprofiler_buffer_id_t buffer_id;
|
||||
CheckApi(rocprofiler_create_buffer(session_id, FlushCallback, 0x9999, &buffer_id));
|
||||
|
||||
rocprofiler_filter_id_t filter_id;
|
||||
rocprofiler_filter_property_t property = {};
|
||||
CheckApi(rocprofiler_create_filter(session_id, ROCPROFILER_COUNTERS_COLLECTION,
|
||||
rocprofiler_filter_data_t{.counters_names = &counters[0]},
|
||||
counters.size(), &filter_id, property));
|
||||
|
||||
CheckApi(rocprofiler_set_filter_buffer(session_id, filter_id, buffer_id));
|
||||
|
||||
// activating profiler session
|
||||
CheckApi(rocprofiler_start_session(session_id));
|
||||
|
||||
// launch kernel on each thread
|
||||
for (int n = 0; n < num_cpu_cores; ++n) {
|
||||
threads[n] = std::thread(KernelLaunch);
|
||||
}
|
||||
|
||||
// wait for all kernel launches to complete
|
||||
for (int n = 0; n < num_cpu_cores; ++n) {
|
||||
threads[n].join();
|
||||
}
|
||||
|
||||
// deactivate session
|
||||
CheckApi(rocprofiler_terminate_session(session_id));
|
||||
|
||||
// dump profiler data
|
||||
CheckApi(rocprofiler_flush_data(session_id, buffer_id));
|
||||
|
||||
// destroy session
|
||||
CheckApi(rocprofiler_destroy_session(session_id));
|
||||
|
||||
// finalize profiler by destroying rocmtool object
|
||||
CheckApi(rocprofiler_finalize());
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/******************************************************************************
|
||||
Copyright (c) 2018 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 <hip/hip_runtime.h>
|
||||
#include <hsa/hsa.h>
|
||||
#include <rocprofiler.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define HIP_ASSERT(x) x
|
||||
#else
|
||||
#define HIP_ASSERT(x) (assert((x) == hipSuccess))
|
||||
#endif
|
||||
|
||||
|
||||
#define WIDTH 1024
|
||||
#define HEIGHT 1024
|
||||
|
||||
#define NUM (WIDTH * HEIGHT)
|
||||
|
||||
#define THREADS_PER_BLOCK_X 16
|
||||
#define THREADS_PER_BLOCK_Y 16
|
||||
#define THREADS_PER_BLOCK_Z 1
|
||||
|
||||
|
||||
/** \mainpage ROC Profiler API Test
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test is to test ROCmTools APIs to collect SPM.
|
||||
*
|
||||
* A simple vectoradd_float kernel is launched and the SPM results are printed
|
||||
* as console output
|
||||
*/
|
||||
|
||||
|
||||
// function to check spm tracing API status
|
||||
auto CheckApi = [](rocprofiler_status_t status) {
|
||||
if (status != ROCPROFILER_STATUS_SUCCESS) {
|
||||
std::cout << "ROCmTools API Error" << std::endl;
|
||||
}
|
||||
assert(status == ROCPROFILER_STATUS_SUCCESS);
|
||||
};
|
||||
|
||||
|
||||
void FlushCallback(const rocprofiler_record_header_t* record,
|
||||
const rocprofiler_record_header_t* end_record, rocprofiler_session_id_t session_id,
|
||||
rocprofiler_buffer_id_t buffer_id) {
|
||||
while (record < end_record) {
|
||||
if (!record)
|
||||
break;
|
||||
else if (record->kind == ROCPROFILER_SPM_RECORD) {
|
||||
const rocprofiler_record_spm_t* spm_record =
|
||||
reinterpret_cast<const rocprofiler_record_spm_t*>(record);
|
||||
size_t name_length;
|
||||
int se_num = 4;
|
||||
// iterate over each shader engine
|
||||
for (int i = 0; i < se_num; i++) {
|
||||
printf("\n\n-------------- shader_engine %d --------------\n\n", i);
|
||||
rocprofiler_record_se_spm_data_t se_spm = spm_record->shader_engine_data[i];
|
||||
for (int i = 0; i < 32; i++) {
|
||||
printf("%04x\n", se_spm.counters_data[i].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
CheckApi(rocprofiler_next_record(record, &record, session_id, buffer_id));
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void vectoradd_float(float* __restrict__ a, const float* __restrict__ b,
|
||||
const float* __restrict__ c, int width, int height) {
|
||||
int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int y = hipBlockDim_y * hipBlockIdx_y + hipThreadIdx_y;
|
||||
|
||||
int i = y * width + x;
|
||||
if (i < (width * height)) {
|
||||
a[i] = b[i] + c[i];
|
||||
}
|
||||
}
|
||||
|
||||
int LaunchVectorAddKernel() {
|
||||
float* hostA;
|
||||
float* hostB;
|
||||
float* hostC;
|
||||
|
||||
float* deviceA;
|
||||
float* deviceB;
|
||||
float* deviceC;
|
||||
|
||||
hipDeviceProp_t devProp;
|
||||
hipGetDeviceProperties(&devProp, 0);
|
||||
std::cout << " System minor " << devProp.minor << std::endl;
|
||||
std::cout << " System major " << devProp.major << std::endl;
|
||||
std::cout << " agent prop name " << devProp.name << std::endl;
|
||||
|
||||
|
||||
std::cout << "hip Device prop succeeded " << std::endl;
|
||||
|
||||
|
||||
int i;
|
||||
int errors;
|
||||
|
||||
hostA = (float*)malloc(NUM * sizeof(float));
|
||||
hostB = (float*)malloc(NUM * sizeof(float));
|
||||
hostC = (float*)malloc(NUM * sizeof(float));
|
||||
|
||||
// initialize the input data
|
||||
for (i = 0; i < NUM; i++) {
|
||||
hostB[i] = (float)i;
|
||||
hostC[i] = (float)i * 100.0f;
|
||||
}
|
||||
|
||||
HIP_ASSERT(hipMalloc((void**)&deviceA, NUM * sizeof(float)));
|
||||
HIP_ASSERT(hipMalloc((void**)&deviceB, NUM * sizeof(float)));
|
||||
HIP_ASSERT(hipMalloc((void**)&deviceC, NUM * sizeof(float)));
|
||||
|
||||
HIP_ASSERT(hipMemcpy(deviceB, hostB, NUM * sizeof(float), hipMemcpyHostToDevice));
|
||||
HIP_ASSERT(hipMemcpy(deviceC, hostC, NUM * sizeof(float), hipMemcpyHostToDevice));
|
||||
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
hipLaunchKernelGGL(vectoradd_float,
|
||||
dim3(WIDTH / THREADS_PER_BLOCK_X, HEIGHT / THREADS_PER_BLOCK_Y),
|
||||
dim3(THREADS_PER_BLOCK_X, THREADS_PER_BLOCK_Y), 0, 0, deviceA, deviceB,
|
||||
deviceC, WIDTH, HEIGHT);
|
||||
|
||||
|
||||
HIP_ASSERT(hipMemcpy(hostA, deviceA, NUM * sizeof(float), hipMemcpyDeviceToHost));
|
||||
|
||||
// verify the results
|
||||
errors = 0;
|
||||
for (i = 0; i < NUM; i++) {
|
||||
if (hostA[i] != (hostB[i] + hostC[i])) {
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if (errors != 0) {
|
||||
printf("FAILED: %d errors\n", errors);
|
||||
} else {
|
||||
printf("PASSED!\n");
|
||||
}
|
||||
|
||||
HIP_ASSERT(hipFree(deviceA));
|
||||
HIP_ASSERT(hipFree(deviceB));
|
||||
HIP_ASSERT(hipFree(deviceC));
|
||||
|
||||
free(hostA);
|
||||
free(hostB);
|
||||
free(hostC);
|
||||
|
||||
// hipResetDefaultAccelerator();
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// inititalize rocmtools
|
||||
hsa_init();
|
||||
CheckApi(rocprofiler_initialize());
|
||||
|
||||
// spm trace collection parameters
|
||||
rocprofiler_session_id_t session_id;
|
||||
rocprofiler_spm_parameter_t spm_parameters;
|
||||
const char* counter_name = "SQ_WAVES";
|
||||
spm_parameters.counters_names = &counter_name;
|
||||
spm_parameters.counters_count = 1;
|
||||
spm_parameters.gpu_agent_id = NULL;
|
||||
// spm_parameters.cpu_agent_id = NULL;
|
||||
spm_parameters.sampling_rate = 10000;
|
||||
// create a session
|
||||
CheckApi(rocprofiler_create_session(ROCPROFILER_KERNEL_REPLAY_MODE, &session_id));
|
||||
|
||||
// create a buffer to hold spm trace records for each kernel launch
|
||||
rocprofiler_buffer_id_t buffer_id;
|
||||
CheckApi(rocprofiler_create_buffer(session_id, FlushCallback, 0x99999999, &buffer_id));
|
||||
|
||||
// create a filter for collecting spm traces
|
||||
rocprofiler_filter_id_t filter_id;
|
||||
rocprofiler_filter_property_t property = {};
|
||||
CheckApi(rocprofiler_create_filter(session_id, ROCPROFILER_SPM_COLLECTION,
|
||||
rocprofiler_filter_data_t{.spm_parameters = &spm_parameters}, 1,
|
||||
&filter_id, property));
|
||||
|
||||
// set buffer for the filter
|
||||
CheckApi(rocprofiler_set_filter_buffer(session_id, filter_id, buffer_id));
|
||||
|
||||
// activating spm tracing session
|
||||
CheckApi(rocprofiler_start_session(session_id));
|
||||
|
||||
// Launch a kernel
|
||||
LaunchVectorAddKernel();
|
||||
|
||||
// deactivate spm tracing session
|
||||
// dump spm tracing data
|
||||
//
|
||||
CheckApi(rocprofiler_terminate_session(session_id));
|
||||
// CheckApi(rocprofiler_flush_data(session_id, buffer_id));
|
||||
|
||||
// destroy session
|
||||
CheckApi(rocprofiler_destroy_session(session_id));
|
||||
|
||||
// finalize spm tracing by destroying rocmtool object
|
||||
CheckApi(rocprofiler_finalize());
|
||||
hsa_shut_down();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pmc: SQ_WAVES GRBM_COUNT GRBM_GUI_ACTIVE
|
||||
@@ -0,0 +1,32 @@
|
||||
/* Copyright (c) 2022 Advanced Micro Devices, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE. */
|
||||
|
||||
__kernel void copyA(__global unsigned int* a, __global unsigned int* b) {
|
||||
uint tid = get_global_id(0);
|
||||
a[tid] = b[tid];
|
||||
}
|
||||
__kernel void copyB(__global unsigned int* a, __global unsigned int* b) {
|
||||
uint tid = get_global_id(0);
|
||||
a[tid] = b[tid];
|
||||
}
|
||||
__kernel void copyC(__global unsigned int* a, __global unsigned int* b) {
|
||||
uint tid = get_global_id(0);
|
||||
a[tid] = b[tid];
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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.
|
||||
*/
|
||||
|
||||
/** \mainpage ROC Profiler Multi Process Binary Test
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test is to test ROC profiler as a binary against a
|
||||
* multiprocess application.Test application launches an empty kernel
|
||||
* on multiple threads from both parent and child process.
|
||||
*
|
||||
* The test then parses the csv and verifies if the nuber of context collected
|
||||
* are equal to number of threads launched in test application.
|
||||
*
|
||||
* Test also does some basic verification if counter values are non-negative
|
||||
*/
|
||||
|
||||
#include <hip/hip_runtime.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
// empty kernel
|
||||
__global__ void kernel() {}
|
||||
|
||||
void KernelLaunch() {
|
||||
// run empty kernel
|
||||
kernel<<<1, 1>>>();
|
||||
hipDeviceSynchronize();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// create as many threads as number of cores in system
|
||||
int num_cpu_cores = GetNumberOfCores();
|
||||
|
||||
pid_t childpid = fork();
|
||||
|
||||
if (childpid > 0) { // Parent
|
||||
// create a pool of thrads
|
||||
std::vector<std::thread> threads(num_cpu_cores);
|
||||
for (int n = 0; n < num_cpu_cores / 2; ++n) {
|
||||
threads[n] = std::thread(KernelLaunch);
|
||||
}
|
||||
|
||||
for (int n = 0; n < num_cpu_cores / 2; ++n) {
|
||||
threads[n].join();
|
||||
}
|
||||
// wait for child exit
|
||||
wait(NULL);
|
||||
|
||||
} else if (!childpid) { // child
|
||||
// create a pool of thrads
|
||||
std::vector<std::thread> threads(num_cpu_cores);
|
||||
for (int n = 0; n < num_cpu_cores / 2; ++n) {
|
||||
threads[n] = std::thread(KernelLaunch);
|
||||
}
|
||||
|
||||
for (int n = 0; n < num_cpu_cores / 2; ++n) {
|
||||
threads[n].join();
|
||||
}
|
||||
} else { // failure
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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.
|
||||
*/
|
||||
|
||||
/** \mainpage ROC Profiler Binary Test
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test is to test ROC profiler as a binary against a
|
||||
* multithreaded application.Test application launches an empty kernel
|
||||
* on multiple threads.
|
||||
*
|
||||
* The test then parses the csv and verifies if the nuber of kernel dispatches
|
||||
* are equal to number of threads launched in test application.
|
||||
*
|
||||
* Test also does some basic verification if counter values are non-negative
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#include "utils/csv_parser.h"
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
// Multi Queue kernel dispatch count test
|
||||
int QueueDependencyTest(std::string profiler_output) {
|
||||
CSVParser parser;
|
||||
parser.ParseCSV(profiler_output);
|
||||
countermap counter_map = parser.GetCounterMap();
|
||||
|
||||
// number of kernel dispatches in test
|
||||
uint32_t dispatch_count = 3;
|
||||
|
||||
uint32_t dispatch_counter = 0;
|
||||
for (size_t i = 0; i < counter_map.size(); i++) {
|
||||
std::string* dispatch_id = parser.ReadCounter(i, 1);
|
||||
if (dispatch_id != nullptr) {
|
||||
if (dispatch_id->find("dispatch") != std::string::npos) {
|
||||
dispatch_counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dispatch count test: Number of dispatches must be equal to
|
||||
// number of kernel launches in test_app
|
||||
if (dispatch_counter == dispatch_count) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string ReadProfilerBuffer(const char* cmd) {
|
||||
std::vector<char> buffer(1028);
|
||||
std::string profiler_output;
|
||||
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
|
||||
if (!pipe) {
|
||||
throw std::runtime_error("popen() failed!");
|
||||
}
|
||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
||||
profiler_output += buffer.data();
|
||||
}
|
||||
return profiler_output;
|
||||
}
|
||||
|
||||
std::string InitMultiQueueTest() {
|
||||
std::string input_app_path = GetRunningPath("profiler_multiqueue_test");
|
||||
std::stringstream input_txt_path;
|
||||
input_txt_path << input_app_path << "gtests/apps/goldentraces/input.txt";
|
||||
std::string rocprofv2_path =
|
||||
GetRunningPath("build/tests/featuretests/profiler/profiler_multiqueue_test");
|
||||
std::stringstream command(rocprofv2_path);
|
||||
|
||||
command << "./rocprofv2 -i " << input_txt_path.str().c_str() << " " << input_app_path
|
||||
<< "multiqueue_testapp";
|
||||
|
||||
std::string result = ReadProfilerBuffer(command.str().c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int test_status = -1;
|
||||
std::string profiler_output;
|
||||
|
||||
// initialize multi queue dependecy test
|
||||
profiler_output = InitMultiQueueTest();
|
||||
|
||||
// multi queue dispatch count test
|
||||
test_status = QueueDependencyTest(profiler_output);
|
||||
|
||||
return test_status;
|
||||
}
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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.
|
||||
*/
|
||||
|
||||
/** \mainpage ROC Profiler Multi Queue Dependency Test
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test is to ensure ROC profiler does not go to deadlock
|
||||
* when multiple queue are created and they are dependent on each other
|
||||
*
|
||||
*/
|
||||
|
||||
#include "discretetests/binary/multiqueue_testapp.h"
|
||||
|
||||
#include "src/utils/exception.h"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
std::vector<hsa_agent_t> Device::all_devices;
|
||||
|
||||
int main() {
|
||||
hsa_status_t status;
|
||||
MQDependencyTest obj;
|
||||
|
||||
// Get Agent info
|
||||
obj.DeviceDiscovery();
|
||||
|
||||
char agent_name[64];
|
||||
status = hsa_agent_get_info(gpu[0].agent, HSA_AGENT_INFO_NAME, agent_name);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
// Getting Current Path
|
||||
std::string current_path = fs::current_path().generic_string();
|
||||
// Getting hasco Path
|
||||
std::string ko_path = current_path + "/featuretests/profiler/" +
|
||||
std::string(agent_name) + "_copy.hsaco";
|
||||
|
||||
MQDependencyTest::CodeObject code_object;
|
||||
if (!obj.LoadCodeObject(ko_path, gpu[0].agent, code_object)) {
|
||||
printf("Kernel file not found or not usable with given agent.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
MQDependencyTest::Kernel copyA;
|
||||
if (!obj.GetKernel(code_object, "copyA", gpu[0].agent, copyA)) {
|
||||
printf("Test kernel A not found.\n");
|
||||
abort();
|
||||
}
|
||||
MQDependencyTest::Kernel copyB;
|
||||
if (!obj.GetKernel(code_object, "copyB", gpu[0].agent, copyB)) {
|
||||
printf("Test kernel B not found.\n");
|
||||
abort();
|
||||
}
|
||||
MQDependencyTest::Kernel copyC;
|
||||
if (!obj.GetKernel(code_object, "copyC", gpu[0].agent, copyC)) {
|
||||
printf("Test kernel C not found.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
struct args_t {
|
||||
uint32_t* a;
|
||||
uint32_t* b;
|
||||
MQDependencyTest::OCLHiddenArgs hidden;
|
||||
};
|
||||
|
||||
args_t* args;
|
||||
args = static_cast<args_t*>(obj.hsaMalloc(sizeof(args_t), kernarg));
|
||||
memset(args, 0, sizeof(args_t));
|
||||
|
||||
uint32_t* a =
|
||||
static_cast<uint32_t*>(obj.hsaMalloc(64 * sizeof(uint32_t), kernarg));
|
||||
uint32_t* b =
|
||||
static_cast<uint32_t*>(obj.hsaMalloc(64 * sizeof(uint32_t), kernarg));
|
||||
|
||||
memset(a, 0, 64 * sizeof(uint32_t));
|
||||
memset(b, 1, 64 * sizeof(uint32_t));
|
||||
|
||||
// Create queue in gpu agent and prepare a kernel dispatch packet
|
||||
hsa_queue_t* queue1;
|
||||
status = hsa_queue_create(gpu[0].agent, 1024, HSA_QUEUE_TYPE_SINGLE, NULL,
|
||||
NULL, UINT32_MAX, UINT32_MAX, &queue1);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
// Create a signal with a value of 1 and attach it to the first kernel
|
||||
// dispatch packet
|
||||
hsa_signal_t completion_signal_1;
|
||||
status = hsa_signal_create(1, 0, NULL, &completion_signal_1);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
// First dispath packet on queue 1, Kernel A
|
||||
{
|
||||
MQDependencyTest::Aql packet{};
|
||||
packet.header.type = HSA_PACKET_TYPE_KERNEL_DISPATCH;
|
||||
packet.header.barrier = 1;
|
||||
packet.header.acquire = HSA_FENCE_SCOPE_SYSTEM;
|
||||
packet.header.release = HSA_FENCE_SCOPE_SYSTEM;
|
||||
|
||||
packet.dispatch.setup = 1;
|
||||
packet.dispatch.workgroup_size_x = 64;
|
||||
packet.dispatch.workgroup_size_y = 1;
|
||||
packet.dispatch.workgroup_size_z = 1;
|
||||
packet.dispatch.grid_size_x = 64;
|
||||
packet.dispatch.grid_size_y = 1;
|
||||
packet.dispatch.grid_size_z = 1;
|
||||
|
||||
packet.dispatch.group_segment_size = copyA.group;
|
||||
packet.dispatch.private_segment_size = copyA.scratch;
|
||||
packet.dispatch.kernel_object = copyA.handle;
|
||||
|
||||
packet.dispatch.kernarg_address = args;
|
||||
packet.dispatch.completion_signal = completion_signal_1;
|
||||
|
||||
args->a = a;
|
||||
args->b = b;
|
||||
// Tell packet processor of A to launch the first kernel dispatch packet
|
||||
obj.SubmitPacket(queue1, packet);
|
||||
}
|
||||
|
||||
// Create a signal with a value of 1 and attach it to the second kernel
|
||||
// dispatch packet
|
||||
hsa_signal_t completion_signal_2;
|
||||
status = hsa_signal_create(1, 0, NULL, &completion_signal_2);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
hsa_signal_t completion_signal_3;
|
||||
status = hsa_signal_create(1, 0, NULL, &completion_signal_3);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
// Create barrier-AND packet that is enqueued in queue 1
|
||||
{
|
||||
MQDependencyTest::Aql packet{};
|
||||
packet.header.type = HSA_PACKET_TYPE_BARRIER_AND;
|
||||
packet.header.barrier = 1;
|
||||
packet.header.acquire = HSA_FENCE_SCOPE_SYSTEM;
|
||||
packet.header.release = HSA_FENCE_SCOPE_SYSTEM;
|
||||
|
||||
packet.barrier_and.dep_signal[0] = completion_signal_2;
|
||||
obj.SubmitPacket(queue1, packet);
|
||||
}
|
||||
|
||||
// Second dispath packet on queue 1, Kernel C
|
||||
{
|
||||
MQDependencyTest::Aql packet{};
|
||||
packet.header.type = HSA_PACKET_TYPE_KERNEL_DISPATCH;
|
||||
packet.header.barrier = 1;
|
||||
packet.header.acquire = HSA_FENCE_SCOPE_SYSTEM;
|
||||
packet.header.release = HSA_FENCE_SCOPE_SYSTEM;
|
||||
|
||||
packet.dispatch.setup = 1;
|
||||
packet.dispatch.workgroup_size_x = 64;
|
||||
packet.dispatch.workgroup_size_y = 1;
|
||||
packet.dispatch.workgroup_size_z = 1;
|
||||
packet.dispatch.grid_size_x = 64;
|
||||
packet.dispatch.grid_size_y = 1;
|
||||
packet.dispatch.grid_size_z = 1;
|
||||
|
||||
packet.dispatch.group_segment_size = copyC.group;
|
||||
packet.dispatch.private_segment_size = copyC.scratch;
|
||||
packet.dispatch.kernel_object = copyC.handle;
|
||||
packet.dispatch.completion_signal = completion_signal_3;
|
||||
packet.dispatch.kernarg_address = args;
|
||||
|
||||
args->a = a;
|
||||
args->b = b;
|
||||
// Tell packet processor to launch the second kernel dispatch packet
|
||||
obj.SubmitPacket(queue1, packet);
|
||||
}
|
||||
|
||||
// Create queue 2
|
||||
hsa_queue_t* queue2;
|
||||
status = hsa_queue_create(gpu[0].agent, 1024, HSA_QUEUE_TYPE_SINGLE, NULL,
|
||||
NULL, UINT32_MAX, UINT32_MAX, &queue2);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
// Create barrier-AND packet that is enqueued in queue 2
|
||||
{
|
||||
MQDependencyTest::Aql packet{};
|
||||
packet.header.type = HSA_PACKET_TYPE_BARRIER_AND;
|
||||
packet.header.barrier = 1;
|
||||
packet.header.acquire = HSA_FENCE_SCOPE_SYSTEM;
|
||||
packet.header.release = HSA_FENCE_SCOPE_SYSTEM;
|
||||
|
||||
packet.barrier_and.dep_signal[0] = completion_signal_1;
|
||||
obj.SubmitPacket(queue2, packet);
|
||||
}
|
||||
|
||||
// Third dispath packet on queue 2, Kernel B
|
||||
{
|
||||
MQDependencyTest::Aql packet{};
|
||||
packet.header.type = HSA_PACKET_TYPE_KERNEL_DISPATCH;
|
||||
packet.header.barrier = 1;
|
||||
packet.header.acquire = HSA_FENCE_SCOPE_SYSTEM;
|
||||
packet.header.release = HSA_FENCE_SCOPE_SYSTEM;
|
||||
|
||||
packet.dispatch.setup = 1;
|
||||
packet.dispatch.workgroup_size_x = 64;
|
||||
packet.dispatch.workgroup_size_y = 1;
|
||||
packet.dispatch.workgroup_size_z = 1;
|
||||
packet.dispatch.grid_size_x = 64;
|
||||
packet.dispatch.grid_size_y = 1;
|
||||
packet.dispatch.grid_size_z = 1;
|
||||
|
||||
packet.dispatch.group_segment_size = copyB.group;
|
||||
packet.dispatch.private_segment_size = copyB.scratch;
|
||||
packet.dispatch.kernel_object = copyB.handle;
|
||||
|
||||
packet.dispatch.kernarg_address = args;
|
||||
packet.dispatch.completion_signal = completion_signal_2;
|
||||
|
||||
args->a = a;
|
||||
args->b = b;
|
||||
// Tell packet processor to launch the third kernel dispatch packet
|
||||
obj.SubmitPacket(queue2, packet);
|
||||
}
|
||||
|
||||
// Wait on the completion signal
|
||||
hsa_signal_wait_relaxed(completion_signal_1, HSA_SIGNAL_CONDITION_EQ, 0,
|
||||
UINT64_MAX, HSA_WAIT_STATE_BLOCKED);
|
||||
|
||||
// Wait on the completion signal
|
||||
hsa_signal_wait_relaxed(completion_signal_2, HSA_SIGNAL_CONDITION_EQ, 0,
|
||||
UINT64_MAX, HSA_WAIT_STATE_BLOCKED);
|
||||
|
||||
// Wait on the completion signal
|
||||
hsa_signal_wait_relaxed(completion_signal_3, HSA_SIGNAL_CONDITION_EQ, 0,
|
||||
UINT64_MAX, HSA_WAIT_STATE_BLOCKED);
|
||||
|
||||
for (int i = 0; i < 64; i++) {
|
||||
if (a[i] != b[i]) {
|
||||
printf("error at %d: expected %d, got %d\n", i, b[i], a[i]);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
// Clearing data structures and memory
|
||||
status = hsa_signal_destroy(completion_signal_1);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
status = hsa_signal_destroy(completion_signal_2);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
status = hsa_signal_destroy(completion_signal_3);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
if (queue1 != nullptr) {
|
||||
status = hsa_queue_destroy(queue1);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
if (queue2 != nullptr) {
|
||||
status = hsa_queue_destroy(queue2);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
status = hsa_memory_free(a);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
status = hsa_memory_free(b);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
status = hsa_executable_destroy(code_object.executable);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
|
||||
status = hsa_code_object_reader_destroy(code_object.code_obj_rdr);
|
||||
ASSERT_EQ(status, HSA_STATUS_SUCCESS);
|
||||
close(code_object.file);
|
||||
}
|
||||
+343
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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.
|
||||
*/
|
||||
#ifndef TESTS_FEATURETESTS_PROFILER_DISCRETETESTS_BINARY_MULTIQUEUE_TESTAPP_H_
|
||||
#define TESTS_FEATURETESTS_PROFILER_DISCRETETESTS_BINARY_MULTIQUEUE_TESTAPP_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <hsa/hsa.h>
|
||||
#include <hsa/hsa_api_trace.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "src/utils/exception.h"
|
||||
|
||||
#define ASSERT_EQ(val1, val2) \
|
||||
do { \
|
||||
if ((val1) != val2) { \
|
||||
assert(false); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
struct Device {
|
||||
struct Memory {
|
||||
hsa_amd_memory_pool_t pool;
|
||||
bool fine;
|
||||
bool kernarg;
|
||||
size_t size;
|
||||
size_t granule;
|
||||
};
|
||||
|
||||
hsa_agent_t agent;
|
||||
char name[64];
|
||||
std::vector<Memory> pools;
|
||||
uint32_t fine;
|
||||
uint32_t coarse;
|
||||
static std::vector<hsa_agent_t> all_devices;
|
||||
};
|
||||
|
||||
std::vector<Device> cpu, gpu;
|
||||
Device::Memory kernarg;
|
||||
|
||||
class MQDependencyTest {
|
||||
public:
|
||||
MQDependencyTest() { hsa_init(); }
|
||||
~MQDependencyTest() { hsa_shut_down(); }
|
||||
|
||||
struct CodeObject {
|
||||
hsa_file_t file;
|
||||
hsa_code_object_reader_t code_obj_rdr;
|
||||
hsa_executable_t executable;
|
||||
};
|
||||
|
||||
struct Kernel {
|
||||
uint64_t handle;
|
||||
uint32_t scratch;
|
||||
uint32_t group;
|
||||
uint32_t kernarg_size;
|
||||
uint32_t kernarg_align;
|
||||
};
|
||||
|
||||
union AqlHeader {
|
||||
struct {
|
||||
uint16_t type : 8;
|
||||
uint16_t barrier : 1;
|
||||
uint16_t acquire : 2;
|
||||
uint16_t release : 2;
|
||||
uint16_t reserved : 3;
|
||||
};
|
||||
uint16_t raw;
|
||||
};
|
||||
|
||||
struct BarrierValue {
|
||||
AqlHeader header;
|
||||
uint8_t AmdFormat;
|
||||
uint8_t reserved;
|
||||
uint32_t reserved1;
|
||||
hsa_signal_t signal;
|
||||
hsa_signal_value_t value;
|
||||
hsa_signal_value_t mask;
|
||||
uint32_t cond;
|
||||
uint32_t reserved2;
|
||||
uint64_t reserved3;
|
||||
uint64_t reserved4;
|
||||
hsa_signal_t completion_signal;
|
||||
};
|
||||
|
||||
union Aql {
|
||||
AqlHeader header;
|
||||
hsa_kernel_dispatch_packet_t dispatch;
|
||||
hsa_barrier_and_packet_t barrier_and;
|
||||
hsa_barrier_or_packet_t barrier_or;
|
||||
BarrierValue barrier_value;
|
||||
};
|
||||
|
||||
struct OCLHiddenArgs {
|
||||
uint64_t offset_x;
|
||||
uint64_t offset_y;
|
||||
uint64_t offset_z;
|
||||
void *printf_buffer;
|
||||
void *enqueue;
|
||||
void *enqueue2;
|
||||
void *multi_grid;
|
||||
};
|
||||
|
||||
bool LoadCodeObject(std::string filename, hsa_agent_t agent,
|
||||
CodeObject &code_object) {
|
||||
hsa_status_t err;
|
||||
|
||||
code_object.file = open(filename.c_str(), O_RDONLY);
|
||||
if (code_object.file == -1) {
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
|
||||
err = hsa_code_object_reader_create_from_file(code_object.file,
|
||||
&code_object.code_obj_rdr);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
err = hsa_executable_create_alt(HSA_PROFILE_FULL,
|
||||
HSA_DEFAULT_FLOAT_ROUNDING_MODE_DEFAULT,
|
||||
nullptr, &code_object.executable);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
err = hsa_executable_load_agent_code_object(code_object.executable, agent,
|
||||
code_object.code_obj_rdr,
|
||||
nullptr, nullptr);
|
||||
if (err != HSA_STATUS_SUCCESS) return false;
|
||||
|
||||
err = hsa_executable_freeze(code_object.executable, nullptr);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetKernel(const CodeObject &code_object, std::string kernel,
|
||||
hsa_agent_t agent, Kernel &kern) {
|
||||
hsa_executable_symbol_t symbol;
|
||||
hsa_status_t err = hsa_executable_get_symbol_by_name(
|
||||
code_object.executable, kernel.c_str(), &agent, &symbol);
|
||||
if (err != HSA_STATUS_SUCCESS) {
|
||||
err = hsa_executable_get_symbol_by_name(
|
||||
code_object.executable, (kernel + ".kd").c_str(), &agent, &symbol);
|
||||
if (err != HSA_STATUS_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// printf("\nkernel-name: %s\n", kernel.c_str());
|
||||
err = hsa_executable_symbol_get_info(
|
||||
symbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_OBJECT, &kern.handle);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
err = hsa_executable_symbol_get_info(
|
||||
symbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_PRIVATE_SEGMENT_SIZE,
|
||||
&kern.scratch);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
// printf("Scratch: %d\n", kern.scratch);
|
||||
|
||||
err = hsa_executable_symbol_get_info(
|
||||
symbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_GROUP_SEGMENT_SIZE,
|
||||
&kern.group);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
// printf("LDS: %d\n", kern.group);
|
||||
|
||||
// Remaining needs code object v2 or comgr.
|
||||
err = hsa_executable_symbol_get_info(
|
||||
symbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_KERNARG_SEGMENT_SIZE,
|
||||
&kern.kernarg_size);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
// printf("Kernarg Size: %d\n", kern.kernarg_size);
|
||||
|
||||
err = hsa_executable_symbol_get_info(
|
||||
symbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_KERNARG_SEGMENT_ALIGNMENT,
|
||||
&kern.kernarg_align);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
// printf("Kernarg Align: %d\n", kern.kernarg_align);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not for parallel insertion.
|
||||
bool SubmitPacket(hsa_queue_t *queue, Aql &pkt) {
|
||||
size_t mask = queue->size - 1;
|
||||
Aql *ring = static_cast<Aql *>(queue->base_address);
|
||||
|
||||
uint64_t write = hsa_queue_load_write_index_relaxed(queue);
|
||||
uint64_t read = hsa_queue_load_read_index_relaxed(queue);
|
||||
if (write - read + 1 > queue->size) return false;
|
||||
|
||||
Aql &dst = ring[write & mask];
|
||||
|
||||
uint16_t header = pkt.header.raw;
|
||||
pkt.header.raw = dst.header.raw;
|
||||
dst = pkt;
|
||||
__atomic_store_n(&dst.header.raw, header, __ATOMIC_RELEASE);
|
||||
pkt.header.raw = header;
|
||||
|
||||
hsa_queue_store_write_index_release(queue, write + 1);
|
||||
hsa_signal_store_screlease(queue->doorbell_signal, write);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void *hsaMalloc(size_t size, const Device::Memory &mem) {
|
||||
void *ret;
|
||||
hsa_status_t err = hsa_amd_memory_pool_allocate(mem.pool, size, 0, &ret);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
err = hsa_amd_agents_allow_access(Device::all_devices.size(),
|
||||
&Device::all_devices[0], nullptr, ret);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *hsaMalloc(size_t size, const Device &dev, bool fine) {
|
||||
uint32_t index = fine ? dev.fine : dev.coarse;
|
||||
assert(index != -1u && "Memory type unavailable.");
|
||||
return hsaMalloc(size, dev.pools[index]);
|
||||
}
|
||||
|
||||
bool DeviceDiscovery() {
|
||||
hsa_status_t err;
|
||||
err = hsa_iterate_agents(
|
||||
[](hsa_agent_t agent, void *) {
|
||||
hsa_status_t err;
|
||||
|
||||
Device dev;
|
||||
dev.agent = agent;
|
||||
|
||||
dev.fine = -1u;
|
||||
dev.coarse = -1u;
|
||||
|
||||
err = hsa_agent_get_info(agent, HSA_AGENT_INFO_NAME, dev.name);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
hsa_device_type_t type;
|
||||
err = hsa_agent_get_info(agent, HSA_AGENT_INFO_DEVICE, &type);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
err = hsa_amd_agent_iterate_memory_pools(
|
||||
agent,
|
||||
[](hsa_amd_memory_pool_t pool, void *data) {
|
||||
std::vector<Device::Memory> &pools =
|
||||
*reinterpret_cast<std::vector<Device::Memory> *>(data);
|
||||
hsa_status_t err;
|
||||
|
||||
hsa_amd_segment_t segment;
|
||||
err = hsa_amd_memory_pool_get_info(
|
||||
pool, HSA_AMD_MEMORY_POOL_INFO_SEGMENT, &segment);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
if (segment != HSA_AMD_SEGMENT_GLOBAL)
|
||||
return HSA_STATUS_SUCCESS;
|
||||
|
||||
uint32_t flags;
|
||||
err = hsa_amd_memory_pool_get_info(
|
||||
pool, HSA_AMD_MEMORY_POOL_INFO_GLOBAL_FLAGS, &flags);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
Device::Memory mem;
|
||||
mem.pool = pool;
|
||||
mem.fine =
|
||||
(flags & HSA_AMD_MEMORY_POOL_GLOBAL_FLAG_FINE_GRAINED);
|
||||
mem.kernarg =
|
||||
(flags & HSA_AMD_MEMORY_POOL_GLOBAL_FLAG_KERNARG_INIT);
|
||||
|
||||
err = hsa_amd_memory_pool_get_info(
|
||||
pool, HSA_AMD_MEMORY_POOL_INFO_SIZE, &mem.size);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
err = hsa_amd_memory_pool_get_info(
|
||||
pool, HSA_AMD_MEMORY_POOL_INFO_RUNTIME_ALLOC_GRANULE,
|
||||
&mem.granule);
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
pools.push_back(mem);
|
||||
return HSA_STATUS_SUCCESS;
|
||||
},
|
||||
static_cast<void *>(&dev.pools));
|
||||
|
||||
if (!dev.pools.empty()) {
|
||||
for (size_t i = 0; i < dev.pools.size(); i++) {
|
||||
if (dev.pools[i].fine && dev.pools[i].kernarg && dev.fine == -1u)
|
||||
dev.fine = i;
|
||||
if (dev.pools[i].fine && !dev.pools[i].kernarg) dev.fine = i;
|
||||
if (!dev.pools[i].fine) dev.coarse = i;
|
||||
}
|
||||
|
||||
if (type == HSA_DEVICE_TYPE_CPU)
|
||||
cpu.push_back(dev);
|
||||
else
|
||||
gpu.push_back(dev);
|
||||
|
||||
Device::all_devices.push_back(dev.agent);
|
||||
}
|
||||
|
||||
return HSA_STATUS_SUCCESS;
|
||||
},
|
||||
nullptr);
|
||||
|
||||
[]() {
|
||||
for (auto &dev : cpu) {
|
||||
for (auto &mem : dev.pools) {
|
||||
if (mem.fine && mem.kernarg) {
|
||||
kernarg = mem;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}();
|
||||
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
|
||||
|
||||
if (cpu.empty() || gpu.empty() || kernarg.pool.handle == 0) return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
#endif // TESTS_FEATURETESTS_PROFILER_DISCRETETESTS_BINARY_MULTIQUEUE_TESTAPP_H_
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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.
|
||||
*/
|
||||
|
||||
/** \mainpage ROC Profiler Binary Test
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test is to test ROC profiler as a binary against a
|
||||
* multithreaded application.Test application launches an empty kernel
|
||||
* on multiple threads.
|
||||
*
|
||||
* The test then parses the csv and verifies if the nuber of kernel dispatches
|
||||
* are equal to number of threads launched in test application.
|
||||
*
|
||||
* Test also does some basic verification if counter values are non-negative
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/csv_parser.h"
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
// kernel dispatch count test
|
||||
int DispatchCountTest(std::string profiler_output) {
|
||||
CSVParser parser;
|
||||
parser.ParseCSV(profiler_output);
|
||||
countermap counter_map = parser.GetCounterMap();
|
||||
|
||||
int dispatch_counter = 0;
|
||||
for (auto i = 0; i < counter_map.size(); i++) {
|
||||
std::string* dispatch_id = parser.ReadCounter(i, 1);
|
||||
if (dispatch_id != nullptr) {
|
||||
if (dispatch_id->find("dispatch") != std::string::npos) {
|
||||
dispatch_counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dispatch count test: Number of dispatches must be equal to
|
||||
// number of kernel launches in test_app
|
||||
if (dispatch_counter == GetNumberOfCores()) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string ReadProfilerBuffer(const char* cmd) {
|
||||
std::vector<char> buffer(1028);
|
||||
std::string profiler_output;
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
|
||||
if (!pipe) {
|
||||
throw std::runtime_error("popen() failed!");
|
||||
}
|
||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
||||
profiler_output += buffer.data();
|
||||
}
|
||||
return profiler_output;
|
||||
}
|
||||
|
||||
std::string InitCounterTest() {
|
||||
std::string input_path = GetRunningPath("profiler_multithreaded_test");
|
||||
std::string rocprofv2_path = GetRunningPath(
|
||||
"build/tests/featuretests/profiler/profiler_multithreaded_test");
|
||||
std::stringstream command;
|
||||
command << rocprofv2_path + "./rocprofv2 -i "
|
||||
<< input_path + "basic_metrics.txt "
|
||||
<< input_path + "multithreaded_testapp";
|
||||
std::string result = ReadProfilerBuffer(command.str().c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int test_status = -1;
|
||||
|
||||
// initialize kernel dispatch test
|
||||
std::string profiler_output = InitCounterTest();
|
||||
// kernel dispatch count test
|
||||
test_status = DispatchCountTest(profiler_output);
|
||||
|
||||
return test_status;
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/******************************************************************************
|
||||
Copyright (c) 2018 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.
|
||||
*******************************************************************************/
|
||||
|
||||
/** \mainpage ROC Profiler Multi-Threaded Test Application
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* Test application launches an empty kernel on multiple threads.
|
||||
*
|
||||
* In subsequent tests, ROC profiler is run against this applicaiton
|
||||
* to confirm if collected contexts are valid.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <hip/hip_runtime.h>
|
||||
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
/** \mainpage ROC Profiler Test APplication
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test application is to launch an empty kernel
|
||||
* on multiple threads and multiple gpu's.
|
||||
*
|
||||
* Number of threads are caluculated based on the cores in the system
|
||||
* Number of gpus's are calculated based on the gpu's in the system
|
||||
*/
|
||||
|
||||
// empty kernel
|
||||
__global__ void kernel() {}
|
||||
|
||||
// launches kernel on multiple gpu's
|
||||
void KernelLaunch() {
|
||||
// Multi-GPU
|
||||
int gpu_count = 0;
|
||||
hipGetDeviceCount(&gpu_count);
|
||||
|
||||
for (uint32_t gpu_id = 0; gpu_id < gpu_count; gpu_id++) {
|
||||
// run empty kernel
|
||||
kernel<<<1, 1>>>();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// create as many threads as number of cores in system
|
||||
int threads_count = GetNumberOfCores();
|
||||
|
||||
// create a pool of thrads
|
||||
std::vector<std::thread> threads(threads_count);
|
||||
|
||||
// launch kernel on each thread
|
||||
for (int n = 0; n < threads_count; ++n) {
|
||||
threads[n] = std::thread(KernelLaunch);
|
||||
}
|
||||
// wait for all kernel launches to complete
|
||||
for (int n = 0; n < threads_count; ++n) {
|
||||
threads[n].join();
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
|
||||
################################################################################
|
||||
# Copyright (c) 2018 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.
|
||||
################################################################################
|
||||
|
||||
# test filter input
|
||||
test_filter=-1
|
||||
if [ -n "$1" ] ; then
|
||||
test_filter=$1
|
||||
fi
|
||||
|
||||
# test check routine
|
||||
test_status=0
|
||||
test_runnum=0
|
||||
test_number=0
|
||||
failed_tests="Failed tests:"
|
||||
|
||||
xeval_test() {
|
||||
test_number=$test_number
|
||||
}
|
||||
|
||||
ncolors=$(tput colors || echo 0)
|
||||
if [ -n "$ncolors" ] && [ $ncolors -ge 8 ]; then
|
||||
bright="$(tput bold || echo)"
|
||||
red="$(tput setaf 1 || echo)"
|
||||
green="$(tput setaf 2 || echo)"
|
||||
blue="$(tput setaf 4 || echo)"
|
||||
normal="$(tput sgr0 || echo)"
|
||||
fi
|
||||
|
||||
eval_test() {
|
||||
label=$1
|
||||
cmdline=$2
|
||||
test_name=$3
|
||||
if [ $test_filter = -1 -o $test_filter = $test_number ] ; then
|
||||
echo "$label: \"$cmdline\""
|
||||
test_runnum=$((test_runnum + 1))
|
||||
eval "$cmdline" > /dev/null 2>&1
|
||||
if [ $? != 0 ] ; then
|
||||
echo "${bright:-}${blue:-}$test_name: ${red:-}FAILED${normal:-}"
|
||||
failed_tests="$failed_tests\n $test_number: \"$label\""
|
||||
test_status=$(($test_status + 1))
|
||||
else
|
||||
echo "${bright:-}${blue:-}$test_name: ${green:-}PASSED${normal:-}"
|
||||
fi
|
||||
fi
|
||||
test_number=$((test_number + 1))
|
||||
}
|
||||
|
||||
CURRENT_DIR="$( dirname -- "$0"; )";
|
||||
|
||||
## Discrete multi-threaded/multi-gpu api test
|
||||
eval_test "${bright:-}${green:-}running multi-threaded api test..."${normal:-} ${CURRENT_DIR}/profiler_api_test api_test
|
||||
|
||||
## Discrete multi-process binary test
|
||||
eval_test "${bright:-}${green:-}running multi-process binary test..."${normal:-} ${CURRENT_DIR}/profiler_multiprocess_test multiprocess_test
|
||||
|
||||
## Discrete multi-threaded binary test
|
||||
eval_test "${bright:-}${green:-}running multi-threaded binary test..."${normal:-} ${CURRENT_DIR}/profiler_multithreaded_test multithreaded_test
|
||||
|
||||
## Discrete multi-queue binary test
|
||||
#eval_test "${bright:-}${green:-}running multi-queue binary test..."${normal:-} ${CURRENT_DIR}/profiler_multiqueue_test multiqueue_test
|
||||
|
||||
echo "$test_number tests total / $test_runnum tests run / $test_status tests failed"
|
||||
if [ $test_status != 0 ] ; then
|
||||
echo $failed_tests
|
||||
fi
|
||||
exit $test_status
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
0x5faaa0 agent cpu
|
||||
0x5fbb30 agent gpu
|
||||
844346791235313
|
||||
|
||||
|
||||
ROCMTools: Collecting the following counters:
|
||||
- GRBM_COUNT
|
||||
|
||||
Enabling Counter Collection
|
||||
System minor 0
|
||||
System major 9
|
||||
agent prop name AMD Radeon VII
|
||||
input string:
|
||||
GdkknVnqkc
|
||||
|
||||
output string:
|
||||
HelloWorld
|
||||
Passed!
|
||||
dispatch[2], gpu_id(0), queue_id(1), queue_index(0), pid(1531373), tid(0), grd(0), wgr(0), lds(0), scr(0), arch_vgpr(0), accum_vgpr(0), sgpr(0), wave_size(0), sig(0), obj(140646043297024), kernel-name("helloworld"), start_time(844346969235689), end_time(844346969239689)
|
||||
, GRBM_COUNT (20292)
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
0x2147aa0 agent cpu
|
||||
0x2148b30 agent gpu
|
||||
844395826761899
|
||||
|
||||
|
||||
ROCMTools: Collecting the following counters:
|
||||
- GRBM_COUNT
|
||||
|
||||
Enabling Counter Collection
|
||||
System minor 0
|
||||
System major 9
|
||||
agent prop name AMD Radeon VII
|
||||
hip Device prop succeeded
|
||||
PASSED!
|
||||
dispatch[2], gpu_id(0), queue_id(1), queue_index(0), pid(1531435), tid(0), grd(0), wgr(0), lds(0), scr(0), arch_vgpr(0), accum_vgpr(0), sgpr(0), wave_size(0), sig(0), obj(140553153857024), kernel-name("vectoradd_float"), start_time(844396006072252), end_time(844396006104732)
|
||||
, GRBM_COUNT (67002)
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
0xd1eeb0 agent cpu
|
||||
0xd4b380 agent gpu
|
||||
844434431085362
|
||||
|
||||
|
||||
ROCMTools: Collecting the following counters:
|
||||
- GRBM_COUNT
|
||||
|
||||
Enabling Counter Collection
|
||||
Only 1 GPU found with required VRAM. Peer-to-Peer copy will be skipped.
|
||||
CPU is "AMD Ryzen 9 5950X 16-Core Processor"
|
||||
GPU1 is "gfx906"
|
||||
Copying 4096 bytes from gpu1 memory to system memory...
|
||||
Success!
|
||||
Copying 4096 bytes from system memory to gpu1 memory...
|
||||
Success!
|
||||
@@ -0,0 +1 @@
|
||||
pmc: GRBM_COUNT
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
0x55e2aaab1540 agent cpu
|
||||
0x55e2aab9f700 agent gpu
|
||||
844463523587280
|
||||
|
||||
|
||||
ROCMTools: Collecting the following counters:
|
||||
- GRBM_COUNT
|
||||
|
||||
Enabling Counter Collection
|
||||
0x12f9580 agent cpu
|
||||
0x1340580 agent gpu
|
||||
844463824808245
|
||||
|
||||
|
||||
ROCMTools: Collecting the following counters:
|
||||
- GRBM_COUNT
|
||||
|
||||
0xdcb320 agent cpu
|
||||
0xe122e0 agent gpu
|
||||
844463824808355
|
||||
|
||||
|
||||
ROCMTools: Collecting the following counters:
|
||||
- GRBM_COUNT
|
||||
|
||||
Enabling Counter Collection
|
||||
Enabling Counter Collection
|
||||
device count and rank is1: 2
|
||||
Rank Id: 0 | Device Id : 0 | Num Devices: 1
|
||||
device count and rank is1: 2
|
||||
Rank Id: 1 | Device Id : 0 | Num Devices: 1
|
||||
Max error: 0.000000
|
||||
Max error: 0.000000
|
||||
dispatch[2], gpu_id(0), queue_id(1), queue_index(0), pid(1531660), tid(0), grd(0), wgr(0), lds(0), scr(0), arch_vgpr(0), accum_vgpr(0), sgpr(0), wave_size(0), sig(0), obj(140604145903232), kernel-name("add"), start_time(844464004374381), end_time(844464006775011)
|
||||
, GRBM_COUNT (3724176)
|
||||
dispatch[2], gpu_id(0), queue_id(1), queue_index(0), pid(1531661), tid(0), grd(0), wgr(0), lds(0), scr(0), arch_vgpr(0), accum_vgpr(0), sgpr(0), wave_size(0), sig(0), obj(140242024941184), kernel-name("add"), start_time(844464004374753), end_time(844464006776661)
|
||||
, GRBM_COUNT (3724418)
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
ROCMTools: Collecting the following counters:
|
||||
- GRBM_COUNT
|
||||
PASSED!
|
||||
dispatch[2], gpu-id(0), kernel-name("hip_helloworld"), time(7853273641921013,7853273641924568)
|
||||
GRBM_COUNT (21840)
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hip/hip_runtime.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#define SUCCESS 0
|
||||
#define FAILURE 1
|
||||
|
||||
__global__ void helloworld(char *in, char *out) {
|
||||
int num = hipThreadIdx_x + hipBlockDim_x * hipBlockIdx_x;
|
||||
out[num] = in[num] + 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
hipDeviceProp_t devProp;
|
||||
hipGetDeviceProperties(&devProp, 0);
|
||||
std::cout << " System minor " << devProp.minor << std::endl;
|
||||
std::cout << " System major " << devProp.major << std::endl;
|
||||
std::cout << " agent prop name " << devProp.name << std::endl;
|
||||
|
||||
/* Initial input,output for the host and create memory objects for the
|
||||
* kernel*/
|
||||
const char *input = "GdkknVnqkc";
|
||||
size_t strlength = strlen(input);
|
||||
std::cout << "input string:" << std::endl;
|
||||
std::cout << input << std::endl;
|
||||
char *output = reinterpret_cast<char *>(malloc(strlength + 1));
|
||||
|
||||
char *inputBuffer;
|
||||
char *outputBuffer;
|
||||
hipMalloc(reinterpret_cast<void **>(&inputBuffer),
|
||||
(strlength + 1) * sizeof(char));
|
||||
hipMalloc(reinterpret_cast<void **>(&outputBuffer),
|
||||
(strlength + 1) * sizeof(char));
|
||||
|
||||
hipMemcpy(inputBuffer, input, (strlength + 1) * sizeof(char),
|
||||
hipMemcpyHostToDevice);
|
||||
|
||||
hipLaunchKernelGGL(helloworld, dim3(1), dim3(strlength), 0, 0, inputBuffer,
|
||||
outputBuffer);
|
||||
|
||||
hipMemcpy(output, outputBuffer, (strlength + 1) * sizeof(char),
|
||||
hipMemcpyDeviceToHost);
|
||||
|
||||
hipFree(inputBuffer);
|
||||
hipFree(outputBuffer);
|
||||
|
||||
output[strlength] = '\0'; // Add the terminal character to the end of output.
|
||||
std::cout << "\noutput string:" << std::endl;
|
||||
std::cout << output << std::endl;
|
||||
|
||||
free(output);
|
||||
|
||||
std::cout << "Passed!\n";
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 <vector>
|
||||
|
||||
#include "gtests/apps/profiler_gtest.h"
|
||||
|
||||
constexpr auto kGoldenOutputHelloworld = "hip_helloworld_golden_traces.txt";
|
||||
|
||||
class HelloWorldTest : public ProfilerTest {
|
||||
protected:
|
||||
std::vector<KernelInfo> golden_kernel_info;
|
||||
void SetUp() {
|
||||
ProfilerTest::SetUp("hip_helloworld");
|
||||
GetKernelInfoForGoldenOutput("hip_helloworld", kGoldenOutputHelloworld, &golden_kernel_info);
|
||||
}
|
||||
};
|
||||
|
||||
// Test:1 Compares total num of kernel-names in golden output against current
|
||||
// profiler output
|
||||
TEST_F(HelloWorldTest, WhenRunningProfilerWithAppThenKernelNumbersMatchWithGoldenOutput) {
|
||||
// kernel info in current profiler run
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
EXPECT_EQ(golden_kernel_info.size(), current_kernel_info.size());
|
||||
}
|
||||
|
||||
// Test:2 Compares order of kernel-names in golden output against current
|
||||
// profiler output
|
||||
TEST_F(HelloWorldTest, WhenRunningProfilerWithAppThenKernelNamessMatchWithGoldenOutput) {
|
||||
// kernel info in current profiler run
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
EXPECT_EQ(golden_kernel_info[0].kernel_name, current_kernel_info[0].kernel_name);
|
||||
EXPECT_EQ(golden_kernel_info[1].kernel_name, current_kernel_info[1].kernel_name);
|
||||
}
|
||||
|
||||
// Test:3 Compares order of kernel-names in golden output against current
|
||||
// profiler output
|
||||
TEST_F(HelloWorldTest, WhenRunningProfilerWithAppThenKernelDurationShouldBePositive) {
|
||||
// kernel info in current profiler run
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
EXPECT_GT(current_kernel_info.size(), 0);
|
||||
}
|
||||
|
||||
// Test:4 Compares end-time is greater than start-time in current
|
||||
// profiler output
|
||||
TEST_F(HelloWorldTest, WhenRunningProfilerWithAppThenEndTimeIsGreaterThenStartTime) {
|
||||
// kernel info in current profiler run
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
for (auto& itr : current_kernel_info) {
|
||||
if (!(itr.start_time).empty() && !(itr.end_time).empty()) {
|
||||
EXPECT_GT(itr.end_time, itr.start_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include "hip/hip_runtime.h"
|
||||
|
||||
#define HIP_ASSERT(x) (assert((x) == hipSuccess))
|
||||
|
||||
#define WIDTH 1024
|
||||
#define HEIGHT 1024
|
||||
|
||||
#define NUM (WIDTH * HEIGHT)
|
||||
|
||||
#define THREADS_PER_BLOCK_X 16
|
||||
#define THREADS_PER_BLOCK_Y 16
|
||||
#define THREADS_PER_BLOCK_Z 1
|
||||
|
||||
__global__ void vectoradd_float(float *__restrict__ a,
|
||||
const float *__restrict__ b,
|
||||
const float *__restrict__ c, int width,
|
||||
int height) {
|
||||
int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int y = hipBlockDim_y * hipBlockIdx_y + hipThreadIdx_y;
|
||||
|
||||
int i = y * width + x;
|
||||
if (i < (width * height)) {
|
||||
a[i] = b[i] + c[i];
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
float *hostA;
|
||||
float *hostB;
|
||||
float *hostC;
|
||||
|
||||
float *deviceA;
|
||||
float *deviceB;
|
||||
float *deviceC;
|
||||
|
||||
hipDeviceProp_t devProp;
|
||||
hipGetDeviceProperties(&devProp, 0);
|
||||
std::cout << " System minor " << devProp.minor << std::endl;
|
||||
std::cout << " System major " << devProp.major << std::endl;
|
||||
std::cout << " agent prop name " << devProp.name << std::endl;
|
||||
|
||||
std::cout << "hip Device prop succeeded " << std::endl;
|
||||
|
||||
int i;
|
||||
int errors;
|
||||
|
||||
hostA = reinterpret_cast<float *>(malloc(NUM * sizeof(float)));
|
||||
hostB = reinterpret_cast<float *>(malloc(NUM * sizeof(float)));
|
||||
hostC = reinterpret_cast<float *>(malloc(NUM * sizeof(float)));
|
||||
|
||||
// initialize the input data
|
||||
for (i = 0; i < NUM; i++) {
|
||||
hostB[i] = static_cast<float>(i);
|
||||
hostC[i] = static_cast<float>(i) * 100.0f;
|
||||
}
|
||||
|
||||
HIP_ASSERT(
|
||||
hipMalloc(reinterpret_cast<void **>(&deviceA), NUM * sizeof(float)));
|
||||
HIP_ASSERT(
|
||||
hipMalloc(reinterpret_cast<void **>(&deviceB), NUM * sizeof(float)));
|
||||
HIP_ASSERT(
|
||||
hipMalloc(reinterpret_cast<void **>(&deviceC), NUM * sizeof(float)));
|
||||
|
||||
HIP_ASSERT(
|
||||
hipMemcpy(deviceB, hostB, NUM * sizeof(float), hipMemcpyHostToDevice));
|
||||
HIP_ASSERT(
|
||||
hipMemcpy(deviceC, hostC, NUM * sizeof(float), hipMemcpyHostToDevice));
|
||||
|
||||
hipLaunchKernelGGL(
|
||||
vectoradd_float,
|
||||
dim3(WIDTH / THREADS_PER_BLOCK_X, HEIGHT / THREADS_PER_BLOCK_Y),
|
||||
dim3(THREADS_PER_BLOCK_X, THREADS_PER_BLOCK_Y), 0, 0, deviceA, deviceB,
|
||||
deviceC, WIDTH, HEIGHT);
|
||||
|
||||
HIP_ASSERT(
|
||||
hipMemcpy(hostA, deviceA, NUM * sizeof(float), hipMemcpyDeviceToHost));
|
||||
|
||||
// verify the results
|
||||
errors = 0;
|
||||
for (i = 0; i < NUM; i++) {
|
||||
if (hostA[i] != (hostB[i] + hostC[i])) {
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if (errors != 0) {
|
||||
printf("FAILED: %d errors\n", errors);
|
||||
} else {
|
||||
printf("PASSED!\n");
|
||||
}
|
||||
|
||||
HIP_ASSERT(hipFree(deviceA));
|
||||
HIP_ASSERT(hipFree(deviceB));
|
||||
HIP_ASSERT(hipFree(deviceC));
|
||||
|
||||
free(hostA);
|
||||
free(hostB);
|
||||
free(hostC);
|
||||
|
||||
// hipResetDefaultAccelerator();
|
||||
|
||||
return errors;
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 <vector>
|
||||
|
||||
#include "gtests/apps/profiler_gtest.h"
|
||||
|
||||
constexpr auto kGoldenOutputVectorAdd = "hip_vectoradd_golden_traces.txt";
|
||||
|
||||
class VectorAddTest : public ProfilerTest {
|
||||
protected:
|
||||
std::vector<KernelInfo> golden_kernel_info;
|
||||
void SetUp() {
|
||||
ProfilerTest::SetUp("hip_vectoradd");
|
||||
GetKernelInfoForGoldenOutput("hip_vectoradd", kGoldenOutputVectorAdd, &golden_kernel_info);
|
||||
}
|
||||
};
|
||||
|
||||
// Test:1 Compares total num of kernel-names in golden output against current
|
||||
// profiler output
|
||||
TEST_F(VectorAddTest, WhenRunningProfilerWithAppThenKernelNumbersMatchWithGoldenOutput) {
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
EXPECT_EQ(golden_kernel_info.size(), current_kernel_info.size());
|
||||
}
|
||||
|
||||
// Test:2 Compares order of kernel-names in golden output against current
|
||||
// profiler output
|
||||
TEST_F(VectorAddTest, WhenRunningProfilerWithAppThenKernelNamessMatchWithGoldenOutput) {
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
EXPECT_EQ(golden_kernel_info[0].kernel_name, current_kernel_info[0].kernel_name);
|
||||
EXPECT_EQ(golden_kernel_info[1].kernel_name, current_kernel_info[1].kernel_name);
|
||||
}
|
||||
|
||||
// Test:3 Compares order of kernel-names in golden output against current
|
||||
// profiler output
|
||||
TEST_F(VectorAddTest, WhenRunningProfilerWithAppThenKernelDurationShouldBePositive) {
|
||||
// kernel info in current profiler run
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
EXPECT_GT(current_kernel_info.size(), 0);
|
||||
}
|
||||
|
||||
// Test:4 Compares end-time is greater than start-time in current
|
||||
// profiler output
|
||||
TEST_F(VectorAddTest, WhenRunningProfilerWithAppThenEndTimeIsGreaterThenStartTime) {
|
||||
// kernel info in current profiler run
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
for (auto& itr : current_kernel_info) {
|
||||
if (!(itr.start_time).empty() && !(itr.end_time).empty()) {
|
||||
EXPECT_GT(itr.end_time, itr.start_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
* =============================================================================
|
||||
* ROC Runtime Conformance Release License
|
||||
* =============================================================================
|
||||
* The University of Illinois/NCSA
|
||||
* Open Source License (NCSA)
|
||||
*
|
||||
* Copyright (c) 2017, Advanced Micro Devices, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Developed by:
|
||||
*
|
||||
* AMD Research and AMD ROC Software Development
|
||||
*
|
||||
* Advanced Micro Devices, Inc.
|
||||
*
|
||||
* www.amd.com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal with 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:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimers.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimers in
|
||||
* the documentation and/or other materials provided with the distribution.
|
||||
* - Neither the names of <Name of Development Group, Name of Institution>,
|
||||
* nor the names of its contributors may be used to endorse or promote
|
||||
* products derived from this Software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#include "hsa/hsa.h"
|
||||
#include "hsa/hsa_ext_amd.h"
|
||||
|
||||
#define RET_IF_HSA_ERR(err) \
|
||||
{ \
|
||||
if ((err) != HSA_STATUS_SUCCESS) { \
|
||||
const char *msg = 0; \
|
||||
hsa_status_string(err, &msg); \
|
||||
std::cout << "hsa api call failure at line " << __LINE__ \
|
||||
<< ", file: " << __FILE__ << ". Call returned " << err \
|
||||
<< std::endl; \
|
||||
std::cout << msg << std::endl; \
|
||||
return (err); \
|
||||
} \
|
||||
}
|
||||
|
||||
static const uint32_t kTestFillValue1 = 0xabcdef12;
|
||||
static const uint32_t kTestFillValue2 = 0xba5eba11;
|
||||
static const uint32_t kTestFillValue3 = 0xfeed5a1e;
|
||||
static const uint32_t kTestInitValue = 0xbaadf00d;
|
||||
|
||||
// This structure holds an agent pointer and associated memory pool to be used
|
||||
// for this test program.
|
||||
struct async_mem_cpy_agent {
|
||||
hsa_agent_t dev;
|
||||
hsa_amd_memory_pool_t pool;
|
||||
size_t granule;
|
||||
void *ptr;
|
||||
};
|
||||
struct async_mem_cpy_pool_query {
|
||||
async_mem_cpy_agent *pool_info;
|
||||
hsa_agent_t peer_device;
|
||||
};
|
||||
struct callback_args {
|
||||
struct async_mem_cpy_agent cpu;
|
||||
struct async_mem_cpy_agent gpu1;
|
||||
struct async_mem_cpy_agent gpu2;
|
||||
};
|
||||
// Find the least common multiple of 2 numbers
|
||||
static uint32_t lcm(uint32_t a, uint32_t b) {
|
||||
int tmp_a;
|
||||
int tmp_b;
|
||||
tmp_a = a;
|
||||
tmp_b = b;
|
||||
while (tmp_a != tmp_b) {
|
||||
if (tmp_a < tmp_b) {
|
||||
tmp_a = tmp_a + a;
|
||||
} else {
|
||||
tmp_b = tmp_b + b;
|
||||
}
|
||||
}
|
||||
return tmp_a;
|
||||
}
|
||||
// This function is a callback for hsa_amd_agent_iterate_memory_pools()
|
||||
// and will test whether the provided memory pool is 1) in the GLOBAL
|
||||
// segment, 2) allows allocation and 3) is accessible by the provided
|
||||
// agent. The "data" input parameter is assumed to be pointing to a
|
||||
// struct async_mem_cpy_agent. If the provided pool meets these criteria,
|
||||
// HSA_STATUS_INFO_BREAK is returned.
|
||||
static hsa_status_t FindPool(hsa_amd_memory_pool_t in_pool, void *data) {
|
||||
hsa_amd_segment_t segment;
|
||||
hsa_status_t err;
|
||||
if (nullptr == data) {
|
||||
return HSA_STATUS_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
struct async_mem_cpy_pool_query *args =
|
||||
(struct async_mem_cpy_pool_query *)data;
|
||||
err = hsa_amd_memory_pool_get_info(in_pool, HSA_AMD_MEMORY_POOL_INFO_SEGMENT,
|
||||
&segment);
|
||||
RET_IF_HSA_ERR(err);
|
||||
if (segment != HSA_AMD_SEGMENT_GLOBAL) {
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
bool canAlloc;
|
||||
err = hsa_amd_memory_pool_get_info(
|
||||
in_pool, HSA_AMD_MEMORY_POOL_INFO_RUNTIME_ALLOC_ALLOWED, &canAlloc);
|
||||
RET_IF_HSA_ERR(err);
|
||||
if (!canAlloc) {
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
if (args->peer_device.handle != 0) {
|
||||
hsa_amd_memory_pool_access_t access =
|
||||
HSA_AMD_MEMORY_POOL_ACCESS_NEVER_ALLOWED;
|
||||
err = hsa_amd_agent_memory_pool_get_info(
|
||||
args->peer_device, in_pool, HSA_AMD_AGENT_MEMORY_POOL_INFO_ACCESS,
|
||||
&access);
|
||||
RET_IF_HSA_ERR(err);
|
||||
if (access == HSA_AMD_MEMORY_POOL_ACCESS_NEVER_ALLOWED) {
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
err = hsa_amd_memory_pool_get_info(
|
||||
in_pool, HSA_AMD_MEMORY_POOL_INFO_RUNTIME_ALLOC_GRANULE,
|
||||
&args->pool_info->granule);
|
||||
RET_IF_HSA_ERR(err);
|
||||
args->pool_info->pool = in_pool;
|
||||
return HSA_STATUS_INFO_BREAK;
|
||||
}
|
||||
// This function is meant to be a callback to hsa_iterate_agents. For each
|
||||
// input agent the iterator provides as input, this function will check to
|
||||
// see if the input agent is a CPU agent. If so, it will update the
|
||||
// async_mem_cpy_agent structure pointed to by the input parameter "data".
|
||||
// Return values:
|
||||
// HSA_STATUS_INFO_BREAK -- CPU agent has been found and stored. Iterator
|
||||
// should stop iterating
|
||||
// HSA_STATUS_SUCCESS -- CPU agent has not yet been found; iterator
|
||||
// should keep iterating
|
||||
// Other -- Some error occurred
|
||||
static hsa_status_t FindCPUDevice(hsa_agent_t agent, void *data) {
|
||||
if (data == NULL) {
|
||||
return HSA_STATUS_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
hsa_device_type_t hsa_device_type;
|
||||
hsa_status_t err =
|
||||
hsa_agent_get_info(agent, HSA_AGENT_INFO_DEVICE, &hsa_device_type);
|
||||
RET_IF_HSA_ERR(err);
|
||||
if (hsa_device_type == HSA_DEVICE_TYPE_CPU) {
|
||||
struct async_mem_cpy_agent *args = (struct async_mem_cpy_agent *)data;
|
||||
args->dev = agent;
|
||||
async_mem_cpy_pool_query pool_query;
|
||||
pool_query.peer_device.handle = 0;
|
||||
pool_query.pool_info = args;
|
||||
err = hsa_amd_agent_iterate_memory_pools(agent, FindPool, &pool_query);
|
||||
if (err == HSA_STATUS_INFO_BREAK) { // we found what we were looking for
|
||||
return HSA_STATUS_INFO_BREAK;
|
||||
} else {
|
||||
args->dev = {0};
|
||||
return err;
|
||||
}
|
||||
}
|
||||
// Returning HSA_STATUS_SUCCESS tells the calling iterator to keep iterating
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
// This function is meant to be a callback to hsa_iterate_agents. It will
|
||||
// attempt to find 2, or at least 1 GPU agent suitable for our test. The data
|
||||
// input parameter should point to a callback_args struct. The 2 GPU fields
|
||||
// will be updated as GPUs are discovered.
|
||||
// Return values:
|
||||
// HSA_STATUS_INFO_BREAK -- 2 GPU agents have been found and stored. Iterator
|
||||
// should stop iterating
|
||||
// HSA_STATUS_SUCCESS -- 2 GPU agents have not yet been found; 0 or 1 may
|
||||
// have been found; iterator function should keep iterating
|
||||
// Other -- Some error occurred
|
||||
static hsa_status_t FindGPUs(hsa_agent_t agent, void *data) {
|
||||
if (data == NULL) {
|
||||
return HSA_STATUS_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
hsa_device_type_t hsa_device_type;
|
||||
hsa_status_t err =
|
||||
hsa_agent_get_info(agent, HSA_AGENT_INFO_DEVICE, &hsa_device_type);
|
||||
RET_IF_HSA_ERR(err);
|
||||
if (hsa_device_type != HSA_DEVICE_TYPE_GPU) {
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
struct callback_args *args = (struct callback_args *)data;
|
||||
struct async_mem_cpy_agent *gpu;
|
||||
async_mem_cpy_pool_query pool_query = {0, 0};
|
||||
if (args->gpu1.dev.handle == 0) {
|
||||
gpu = &args->gpu1;
|
||||
} else {
|
||||
gpu = &args->gpu2;
|
||||
// Check that gpu1 has peer access into the selected pool.
|
||||
pool_query.peer_device = args->gpu1.dev;
|
||||
}
|
||||
// Make sure GPU device has pool host can access
|
||||
gpu->dev = agent;
|
||||
pool_query.pool_info = gpu;
|
||||
err = hsa_amd_agent_iterate_memory_pools(agent, FindPool, &pool_query);
|
||||
if (err == HSA_STATUS_INFO_BREAK) {
|
||||
if (gpu == &args->gpu2) {
|
||||
// We found 2 gpu's
|
||||
return HSA_STATUS_INFO_BREAK;
|
||||
} else {
|
||||
// Keep looking for another gpu
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
gpu->dev = {0};
|
||||
}
|
||||
RET_IF_HSA_ERR(err);
|
||||
// Returning HSA_STATUS_SUCCESS tells the calling iterator to keep iterating
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
// This is the main test, showing various paths of async. copy. Source and
|
||||
// destination agents and their respective pools should already be discovered.
|
||||
// Additionally, buffer from the pools should already be allocated and availble
|
||||
// from the input parameters.
|
||||
static hsa_status_t AsyncCpyTest(async_mem_cpy_agent *dst,
|
||||
async_mem_cpy_agent *src, callback_args *args,
|
||||
size_t sz, uint32_t val) {
|
||||
hsa_status_t err;
|
||||
hsa_signal_t copy_signal;
|
||||
// Initialize the system and destination buffers with a value so we can later
|
||||
// validate it has been overwritten
|
||||
void *sysPtr = args->cpu.ptr;
|
||||
err = hsa_amd_memory_fill(sysPtr, kTestInitValue, sz / sizeof(uint32_t));
|
||||
RET_IF_HSA_ERR(err);
|
||||
if (dst->ptr != sysPtr) {
|
||||
err = hsa_amd_memory_fill(dst->ptr, kTestInitValue, sz / sizeof(uint32_t));
|
||||
RET_IF_HSA_ERR(err);
|
||||
}
|
||||
// Fill the source buffer with the provided uint32_t value
|
||||
err = hsa_amd_memory_fill(src->ptr, val, sz / sizeof(uint32_t));
|
||||
RET_IF_HSA_ERR(err);
|
||||
// Make sure the target and destination agents have access to the buffer.
|
||||
hsa_agent_t ag_list[2] = {dst->dev, src->dev};
|
||||
err = hsa_amd_agents_allow_access(2, ag_list, NULL, dst->ptr);
|
||||
RET_IF_HSA_ERR(err);
|
||||
// Create a signal that will be used to inform us when the copy is done
|
||||
err = hsa_signal_create(1, 0, NULL, ©_signal);
|
||||
RET_IF_HSA_ERR(err);
|
||||
// Do the copy...
|
||||
err = hsa_amd_memory_async_copy(dst->ptr, dst->dev, src->ptr, src->dev, sz, 0,
|
||||
NULL, copy_signal);
|
||||
RET_IF_HSA_ERR(err);
|
||||
// Here we do a blocking wait. Alternatively, we could also use a
|
||||
// non-blocking wait in a loop, and do other work while waiting.
|
||||
if (hsa_signal_wait_relaxed(copy_signal, HSA_SIGNAL_CONDITION_LT, 1, -1,
|
||||
HSA_WAIT_STATE_BLOCKED) != 0) {
|
||||
printf("Async copy returned error value.\n");
|
||||
return HSA_STATUS_ERROR;
|
||||
}
|
||||
// Verify the copy was successful; copy from the dst buffer to the sysBuf,
|
||||
// (if the result is not already in sys. mem.) and check the sysBuf values
|
||||
if (dst->ptr != sysPtr) {
|
||||
if (src->ptr != sysPtr) {
|
||||
// In this case, we need to give the gpu dev that owns dst->ptr access
|
||||
// to the system memory we are going to copy to.
|
||||
hsa_agent_t ag_list_ck[2] = {dst->dev, args->cpu.dev};
|
||||
err = hsa_amd_agents_allow_access(2, ag_list_ck, NULL, sysPtr);
|
||||
RET_IF_HSA_ERR(err);
|
||||
}
|
||||
// Reset signal to 1
|
||||
hsa_signal_store_screlease(copy_signal, 1);
|
||||
err = hsa_amd_memory_async_copy(sysPtr, args->cpu.dev, dst->ptr, dst->dev,
|
||||
sz, 0, NULL, copy_signal);
|
||||
RET_IF_HSA_ERR(err);
|
||||
if (hsa_signal_wait_relaxed(copy_signal, HSA_SIGNAL_CONDITION_LT, 1, -1,
|
||||
HSA_WAIT_STATE_BLOCKED) != 0) {
|
||||
printf("Async copy returned error value.\n");
|
||||
return HSA_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
// Check that the contents of the buffer are what is expected.
|
||||
for (uint32_t i = 0; i < sz / sizeof(uint32_t); ++i) {
|
||||
if (reinterpret_cast<uint32_t *>(sysPtr)[i] != val) {
|
||||
fprintf(stdout, "Expected 0x%x but got 0x%x in buffer at index %d.\n",
|
||||
val, reinterpret_cast<uint32_t *>(sysPtr)[i], i);
|
||||
return HSA_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
return HSA_STATUS_SUCCESS;
|
||||
}
|
||||
// This program illustrates the usage of the asynchronous copy capability of
|
||||
// the RocR runtime library. The program will create a system memory buffer and
|
||||
// a local buffer for each GPU, up to 2 GPUs, if the system has at least 2
|
||||
// GPUs. The program will copy data to/from the host from/to the GPU. If 2
|
||||
// GPUs are available, the program will also copy data from one to the other.
|
||||
int main() {
|
||||
hsa_status_t err;
|
||||
struct callback_args args;
|
||||
bool twoGPUs = false;
|
||||
err = hsa_init();
|
||||
RET_IF_HSA_ERR(err);
|
||||
// First, find the cpu agent and associated pool
|
||||
args.cpu = {0, 0, 0};
|
||||
err = hsa_iterate_agents(FindCPUDevice, reinterpret_cast<void *>(&args.cpu));
|
||||
assert(err == HSA_STATUS_INFO_BREAK);
|
||||
if (err != HSA_STATUS_INFO_BREAK) {
|
||||
return -1;
|
||||
}
|
||||
// Now, find 1 or 2 (if possible) GPUs and associated pool(s) for our test
|
||||
args.gpu1 = {0, 0, 0};
|
||||
args.gpu2 = {0, 0, 0};
|
||||
err = hsa_iterate_agents(FindGPUs, &args);
|
||||
if (err == HSA_STATUS_INFO_BREAK) {
|
||||
twoGPUs = true;
|
||||
} else {
|
||||
// See if we at least have 1 GPU
|
||||
if (args.gpu1.dev.handle == 0) {
|
||||
fprintf(
|
||||
stdout,
|
||||
"GPU with accessible VRAM not found; at least 1 required. Exiting\n");
|
||||
return -1;
|
||||
}
|
||||
fprintf(stdout, "Only 1 GPU found with required VRAM. "
|
||||
"Peer-to-Peer copy will be skipped.\n");
|
||||
}
|
||||
// We will use the smallest amount of allocatable memory that works for all
|
||||
// potential sources and destinations of the copy
|
||||
size_t sz = lcm(args.cpu.granule, args.gpu1.granule);
|
||||
// Allocate memory on each source/destination
|
||||
if (twoGPUs) {
|
||||
sz = lcm(sz, args.gpu2.granule);
|
||||
err = hsa_amd_memory_pool_allocate(
|
||||
args.gpu2.pool, sz, 0, reinterpret_cast<void **>(&args.gpu2.ptr));
|
||||
RET_IF_HSA_ERR(err);
|
||||
}
|
||||
err = hsa_amd_memory_pool_allocate(args.cpu.pool, sz, 0,
|
||||
reinterpret_cast<void **>(&args.cpu.ptr));
|
||||
RET_IF_HSA_ERR(err);
|
||||
err = hsa_amd_memory_pool_allocate(args.gpu1.pool, sz, 0,
|
||||
reinterpret_cast<void **>(&args.gpu1.ptr));
|
||||
RET_IF_HSA_ERR(err);
|
||||
char name[64];
|
||||
err = hsa_agent_get_info(args.cpu.dev, HSA_AGENT_INFO_NAME, &name);
|
||||
fprintf(stdout, "CPU is \"%s\"\n", name);
|
||||
err = hsa_agent_get_info(args.gpu1.dev, HSA_AGENT_INFO_NAME, &name);
|
||||
fprintf(stdout, "GPU1 is \"%s\"\n", name);
|
||||
if (twoGPUs) {
|
||||
err = hsa_agent_get_info(args.gpu2.dev, HSA_AGENT_INFO_NAME, &name);
|
||||
fprintf(stdout, "GPU2 is \"%s\"\n", name);
|
||||
}
|
||||
fprintf(stdout, "Copying %lu bytes from gpu1 memory to system memory...\n",
|
||||
sz);
|
||||
err = AsyncCpyTest(&args.cpu, &args.gpu1, &args, sz, kTestFillValue1);
|
||||
RET_IF_HSA_ERR(err);
|
||||
fprintf(stdout, "Success!\n");
|
||||
fprintf(stdout, "Copying %lu bytes from system memory to gpu1 memory...\n",
|
||||
sz);
|
||||
err = AsyncCpyTest(&args.gpu1, &args.cpu, &args, sz, kTestFillValue2);
|
||||
RET_IF_HSA_ERR(err);
|
||||
fprintf(stdout, "Success!\n");
|
||||
if (twoGPUs) {
|
||||
fprintf(stdout, "Copying %lu bytes from gpu1 memory to gpu2 memory...\n",
|
||||
sz);
|
||||
err = AsyncCpyTest(&args.gpu2, &args.gpu1, &args, sz, kTestFillValue3);
|
||||
RET_IF_HSA_ERR(err);
|
||||
fprintf(stdout, "Success!\n");
|
||||
}
|
||||
// Clean up
|
||||
err = hsa_amd_memory_pool_free(args.cpu.ptr);
|
||||
RET_IF_HSA_ERR(err);
|
||||
err = hsa_amd_memory_pool_free(args.gpu1.ptr);
|
||||
RET_IF_HSA_ERR(err);
|
||||
if (twoGPUs) {
|
||||
err = hsa_amd_memory_pool_free(args.gpu2.ptr);
|
||||
RET_IF_HSA_ERR(err);
|
||||
}
|
||||
}
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 <stdio.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gtests/apps/profiler_gtest.h"
|
||||
|
||||
constexpr auto kGOldenOutputAsyncCopy = "hsa_async_mem_copy_golden_traces.txt";
|
||||
|
||||
class HSATest : public ProfilerTest {
|
||||
protected:
|
||||
std::vector<KernelInfo> golden_kernel_info;
|
||||
void SetUp() {
|
||||
ProfilerTest::SetUp("hsa_async_mem_copy");
|
||||
GetKernelInfoForGoldenOutput("hsa_async_mem_copy", kGOldenOutputAsyncCopy,
|
||||
&golden_kernel_info);
|
||||
}
|
||||
};
|
||||
|
||||
// Test:1 Given profiler don't intercept any hsa calls in this app
|
||||
// we dont collect any counters by default. Expectation is, both vectors are
|
||||
// empty
|
||||
TEST_F(HSATest,
|
||||
WhenRunningProfilerWithAppThenKernelNumbersMatchWithGoldenOutput) {
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
|
||||
EXPECT_EQ(current_kernel_info.size(), 0);
|
||||
EXPECT_EQ(golden_kernel_info.size(), 0);
|
||||
|
||||
EXPECT_EQ(golden_kernel_info.size(), current_kernel_info.size());
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
'
|
||||
--------------------------------------------------------------------------
|
||||
Running as root is *strongly* discouraged as any mistake (e.g., in
|
||||
defining TMPDIR) or bug can result in catastrophic damage to the OS
|
||||
file system, leaving your system in an unusable state.
|
||||
|
||||
We strongly suggest that you run mpirun as a non-root user.
|
||||
|
||||
You can override this protection by adding the --allow-run-as-root option
|
||||
to the cmd line or by setting two environment variables in the following way:
|
||||
the variable OMPI_ALLOW_RUN_AS_ROOT=1 to indicate the desire to override this
|
||||
protection, and OMPI_ALLOW_RUN_AS_ROOT_CONFIRM=1 to confirm the choice and
|
||||
add one more layer of certainty that you want to do so.
|
||||
We reiterate our advice against doing so - please proceed at your own risk.
|
||||
--------------------------------------------------------------------------
|
||||
'
|
||||
|
||||
MPIRUN=mpirun
|
||||
if ! command -v $MPIRUN &> /dev/null
|
||||
then
|
||||
echo "$MPIRUN could not be found. checking libs"
|
||||
if [ -f "/usr/lib64/openmpi/bin/mpirun" ]
|
||||
then
|
||||
MPIRUN=/usr/lib64/openmpi/bin/mpirun
|
||||
else
|
||||
if [ -f "/usr/lib64/mpi/gcc/openmpi2/bin/mpirun" ]
|
||||
then
|
||||
MPIRUN=/usr/lib64/mpi/gcc/openmpi2/bin/mpirun
|
||||
else
|
||||
echo "$MPIRUN could not be found. exiting"
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
SCRIPT=$(realpath "$0")
|
||||
SCRIPTPATH=$(dirname "$SCRIPT")
|
||||
$MPIRUN --allow-run-as-root -np 2 $SCRIPTPATH/mpi_vectoradd mdrun -pin on -nsteps 10 -resetstep 9 -ntomp 64 -noconfout -nb gpu -bonded gpu -pme gpu -v -gpu_id 0
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 <mpi.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "hip/hip_runtime.h"
|
||||
|
||||
#define HIP_RC(call) \
|
||||
do { \
|
||||
hipError_t err = call; \
|
||||
if (hipSuccess != err) { \
|
||||
printf("HIP ERROR (code = %d, %s) at %s:%d\n", err, \
|
||||
hipGetErrorString(err), __FILE__, __LINE__); \
|
||||
assert(0); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define HIP_KL(call) \
|
||||
do { \
|
||||
call; \
|
||||
hipError_t err = hipGetLastError(); \
|
||||
if (hipSuccess != err) { \
|
||||
printf("HIP ERROR (code = %d, %s) at %s:%d\n", err, \
|
||||
hipGetErrorString(err), __FILE__, __LINE__); \
|
||||
assert(0); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// CUDA kernel to add elements of two arrays
|
||||
__global__ void add(int n, float *x, float *y) {
|
||||
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int stride = blockDim.x * gridDim.x;
|
||||
for (int i = index; i < n; i += stride)
|
||||
y[i] = x[i] + y[i];
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int N = 1 << 20;
|
||||
float *x = new float[N];
|
||||
float *y = new float[N];
|
||||
float *d_x;
|
||||
float *d_y;
|
||||
|
||||
int myId;
|
||||
int devId;
|
||||
int numRank;
|
||||
int deviceCount;
|
||||
|
||||
// init MPI
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myId);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &numRank);
|
||||
hipGetDeviceCount(&deviceCount);
|
||||
|
||||
std::cout << "device count and rank is" << deviceCount << ": " << numRank
|
||||
<< std::endl;
|
||||
|
||||
// set the device ID to the rank ID mod deviceCount (in this case 4 since
|
||||
// there are 4 devices on a node)
|
||||
devId = myId % deviceCount;
|
||||
// set the device ID
|
||||
hipSetDevice(devId);
|
||||
|
||||
printf("Rank Id: %d | Device Id : %d | Num Devices: %d\n", myId, devId,
|
||||
deviceCount);
|
||||
fflush(stdout);
|
||||
|
||||
// Allocate Unified Memory -- accessible from CPU or GPU
|
||||
hipMallocManaged(&d_x, N * sizeof(float));
|
||||
hipMallocManaged(&d_y, N * sizeof(float));
|
||||
|
||||
// initialize x and y arrays on the host
|
||||
for (int i = 0; i < N; i++) {
|
||||
x[i] = 1.0f;
|
||||
y[i] = 2.0f;
|
||||
}
|
||||
|
||||
HIP_RC(hipMemcpy(d_x, x, N * sizeof(float), hipMemcpyHostToDevice));
|
||||
HIP_RC(hipMemcpy(d_y, y, N * sizeof(float), hipMemcpyHostToDevice));
|
||||
|
||||
// Launch kernel on 1M elements on the GPU
|
||||
int blockSize = 256;
|
||||
int numBlocks = (N + blockSize - 1) / blockSize;
|
||||
HIP_KL(hipLaunchKernelGGL(add, numBlocks, blockSize, 0, 0, N, d_x, d_y));
|
||||
|
||||
// Wait for GPU to finish before accessing on host
|
||||
HIP_RC(hipDeviceSynchronize());
|
||||
|
||||
HIP_RC(hipMemcpy(x, d_x, N * sizeof(float), hipMemcpyDeviceToHost));
|
||||
HIP_RC(hipMemcpy(y, d_y, N * sizeof(float), hipMemcpyDeviceToHost));
|
||||
|
||||
// Check for errors (all values should be 3.0f)
|
||||
float maxError = 0.0f;
|
||||
for (int i = 0; i < N; i++)
|
||||
maxError = fmax(maxError, fabs(y[i] - 3.0f));
|
||||
printf("Max error: %f\n", maxError);
|
||||
|
||||
// Free memory
|
||||
HIP_RC(hipFree(d_x));
|
||||
HIP_RC(hipFree(d_y));
|
||||
|
||||
delete[] x;
|
||||
delete[] y;
|
||||
|
||||
MPI_Finalize();
|
||||
return 0;
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gtests/apps/profiler_gtest.h"
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
constexpr auto kGoldenOutputMpi = "mpi_vectoradd_golden_traces.txt";
|
||||
|
||||
class MPITest : public ProfilerTest {
|
||||
protected:
|
||||
void ProcessMPIApplication(const char *app_name);
|
||||
void ExecuteAndParseApplication(std::stringstream &ss);
|
||||
|
||||
void SetUp() {
|
||||
/*To supress No protocol found prints*/
|
||||
setenv("HWLOC_COMPONENTS", "-gl", 1);
|
||||
|
||||
// run as standalone test
|
||||
ProfilerTest::SetUp("mpi_vectoradd");
|
||||
|
||||
// run mpirun script
|
||||
// ProcessMPIApplication("mpi_run.sh");
|
||||
}
|
||||
};
|
||||
|
||||
void MPITest::ProcessMPIApplication(const char *app_name) {
|
||||
std::string app_path =
|
||||
GetRunningPath("tests/featuretests/profiler/runFeatureTests");
|
||||
std::string lib_path = app_path;
|
||||
|
||||
std::stringstream hsa_tools_lib_path;
|
||||
|
||||
hsa_tools_lib_path << app_path << "librocprofiler_tool.so";
|
||||
setenv("LD_PRELOAD", hsa_tools_lib_path.str().c_str(), true);
|
||||
|
||||
std::stringstream os;
|
||||
os << app_path << "tests/featuretests/profiler/gtests/apps/" << app_name;
|
||||
ExecuteAndParseApplication(os);
|
||||
}
|
||||
|
||||
void MPITest::ExecuteAndParseApplication(std::stringstream &ss) {
|
||||
FILE *handle = popen(ss.str().c_str(), "r");
|
||||
ASSERT_NE(handle, nullptr);
|
||||
char *ln{NULL};
|
||||
std::string temp{""};
|
||||
size_t len{0};
|
||||
|
||||
while (getline(&ln, &len, handle) != -1) {
|
||||
temp = temp + std::string(ln);
|
||||
}
|
||||
|
||||
free(ln);
|
||||
size_t pos{0};
|
||||
std::string delimiter{"\n"};
|
||||
while ((pos = temp.find(delimiter)) != std::string::npos) {
|
||||
output_lines.push_back(temp.substr(0, pos));
|
||||
temp.erase(0, pos + delimiter.length());
|
||||
}
|
||||
|
||||
pclose(handle);
|
||||
}
|
||||
|
||||
// Test:1 Compares total num of kernel-names in golden output against current
|
||||
// profiler output
|
||||
TEST_F(MPITest,
|
||||
WhenRunningProfilerWithAppThenKernelNumbersMatchWithGoldenOutput) {
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
EXPECT_GT(current_kernel_info.size(), 0);
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright (c) 2020-present 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.
|
||||
*/
|
||||
|
||||
// OpenMP program to print Hello World
|
||||
// using C language is supported by HIP
|
||||
|
||||
// OpenMP header
|
||||
#include <omp.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// HIP header
|
||||
#include <hip/hip_runtime.h>
|
||||
|
||||
#define NUM_THREADS 16
|
||||
#define CHECK(cmd) \
|
||||
{ \
|
||||
hipError_t error = cmd; \
|
||||
if (error != hipSuccess) { \
|
||||
fprintf(stderr, "error: '%s'(%d) at %s:%d\n", hipGetErrorString(error), \
|
||||
error, __FILE__, __LINE__); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
__global__ void hip_helloworld(unsigned omp_id, int *A_d) {
|
||||
// Note: the printf command will only work if printf is enabled in your build.
|
||||
// printf("Hello World... from HIP thread = %u\n", omp_id);
|
||||
|
||||
A_d[omp_id] = omp_id;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int *A_h, *A_d;
|
||||
size_t Nbytes = NUM_THREADS * sizeof(int);
|
||||
|
||||
hipDeviceProp_t props;
|
||||
CHECK(hipGetDeviceProperties(&props, 0 /*deviceID*/));
|
||||
// printf("info: running on device %s\n", props.name);
|
||||
|
||||
A_h = reinterpret_cast<int *>(malloc(Nbytes));
|
||||
CHECK(hipMalloc(&A_d, Nbytes));
|
||||
for (int i = 0; i < NUM_THREADS; i++) {
|
||||
A_h[i] = 0;
|
||||
}
|
||||
CHECK(hipMemcpy(A_d, A_h, Nbytes, hipMemcpyHostToDevice));
|
||||
|
||||
// Beginning of parallel region
|
||||
#pragma omp parallel num_threads(NUM_THREADS)
|
||||
{
|
||||
// fprintf(stderr, "Hello World... from OMP thread = %d\n",
|
||||
// omp_get_thread_num());
|
||||
|
||||
hipLaunchKernelGGL(hip_helloworld, dim3(1), dim3(1), 0, 0,
|
||||
omp_get_thread_num(), A_d);
|
||||
}
|
||||
// Ending of parallel region
|
||||
|
||||
hipStreamSynchronize(0);
|
||||
CHECK(hipMemcpy(A_h, A_d, Nbytes, hipMemcpyDeviceToHost));
|
||||
// printf("Device Results:\n");
|
||||
for (int i = 0; i < NUM_THREADS; i++) {
|
||||
// printf(" A_d[%d] = %d\n", i, A_h[i]);
|
||||
}
|
||||
|
||||
printf("PASSED!\n");
|
||||
|
||||
free(A_h);
|
||||
CHECK(hipFree(A_d));
|
||||
return 0;
|
||||
}
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright (c) 2020-present 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 <vector>
|
||||
|
||||
#include "gtests/apps/profiler_gtest.h"
|
||||
|
||||
constexpr auto kGoldenOutputOpenMP = "openmp_helloworld_golden_traces.txt";
|
||||
|
||||
class OpenMPTest : public ProfilerTest {
|
||||
protected:
|
||||
std::vector<KernelInfo> golden_kernel_info;
|
||||
void SetUp() {
|
||||
ProfilerTest::SetUp("openmp_helloworld");
|
||||
GetKernelInfoForGoldenOutput("openmp_helloworld", kGoldenOutputOpenMP,
|
||||
&golden_kernel_info);
|
||||
}
|
||||
};
|
||||
|
||||
// Test:1 Compares total num of kernel-names in golden output against current
|
||||
// profiler output
|
||||
TEST_F(OpenMPTest,
|
||||
WhenRunningProfilerWithAppThenKernelNumbersMatchWithGoldenOutput) {
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
EXPECT_EQ(golden_kernel_info.size(), current_kernel_info.size());
|
||||
}
|
||||
|
||||
// Test:2 Compares order of kernel-names in golden output against current
|
||||
// profiler output
|
||||
TEST_F(OpenMPTest,
|
||||
WhenRunningProfilerWithAppThenKernelNamessMatchWithGoldenOutput) {
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
EXPECT_EQ(golden_kernel_info[0].kernel_name,
|
||||
current_kernel_info[0].kernel_name);
|
||||
EXPECT_EQ(golden_kernel_info[1].kernel_name,
|
||||
current_kernel_info[1].kernel_name);
|
||||
}
|
||||
|
||||
// Test:3 Compares order of kernel-names in golden output against current
|
||||
// profiler output
|
||||
TEST_F(OpenMPTest,
|
||||
WhenRunningProfilerWithAppThenKernelDurationShouldBePositive) {
|
||||
// kernel info in current profiler run
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
EXPECT_GT(current_kernel_info.size(), 0);
|
||||
}
|
||||
|
||||
// Test:4 Compares end-time is greater than start-time in current
|
||||
// profiler output
|
||||
TEST_F(OpenMPTest,
|
||||
WhenRunningProfilerWithAppThenEndTimeIsGreaterThenStartTime) {
|
||||
// kernel info in current profiler run
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
for (auto &itr : current_kernel_info) {
|
||||
if (!(itr.end_time).empty()) {
|
||||
EXPECT_GT(itr.end_time, itr.start_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 "gtests/apps/profiler_gtest.h"
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
/**
|
||||
* Sets application enviornment by seting HSA_TOOLS_LIB.
|
||||
*/
|
||||
void ApplicationParser::SetApplicationEnv(const char* app_name) {
|
||||
std::string app_path = GetRunningPath("tests/featuretests/profiler/runFeatureTests");
|
||||
|
||||
std::stringstream counter_path;
|
||||
counter_path << app_path << "tests/featuretests/profiler/gtests/apps/goldentraces/input.txt";
|
||||
setenv("COUNTERS_PATH", counter_path.str().c_str(), true);
|
||||
|
||||
std::stringstream hsa_tools_lib_path;
|
||||
hsa_tools_lib_path << app_path << "librocprofiler_tool.so";
|
||||
setenv("LD_PRELOAD", hsa_tools_lib_path.str().c_str(), true);
|
||||
|
||||
std::stringstream os;
|
||||
os << app_path << "tests/featuretests/profiler/gtests/apps/" << app_name;
|
||||
|
||||
ProcessApplication(os);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses kernel-info after running profiler against curent application
|
||||
* and saves them in a vector.
|
||||
*/
|
||||
void ApplicationParser::GetKernelInfoForRunningApplication(
|
||||
std::vector<KernelInfo>* kernel_info_output) {
|
||||
KernelInfo kinfo;
|
||||
for (std::string line : output_lines) {
|
||||
if (std::regex_match(line, std::regex("(dispatch)(.*)"))) {
|
||||
int spos = line.find("[");
|
||||
int epos = line.find("]", spos);
|
||||
std::string sub = line.substr(spos + 1, epos - spos - 1);
|
||||
kinfo.dispatch_id = sub;
|
||||
kernel_info_output->push_back(kinfo);
|
||||
|
||||
// Kernel-Name
|
||||
size_t found = line.find("kernel-name");
|
||||
if (found != std::string::npos) {
|
||||
int spos = found;
|
||||
int epos = line.find(")", spos);
|
||||
int length = std::string("kernel-name").length();
|
||||
std::string sub = line.substr(spos + length + 1, epos - spos - length - 1);
|
||||
|
||||
kinfo.kernel_name = sub;
|
||||
kernel_info_output->push_back(kinfo);
|
||||
}
|
||||
// Start-Time
|
||||
found = line.find("start_time");
|
||||
if (found != std::string::npos) {
|
||||
int spos = found;
|
||||
int epos = line.find(",", spos);
|
||||
int length = std::string("start_time").length();
|
||||
std::string sub = line.substr(spos + length + 1, epos - spos - length - 1);
|
||||
kinfo.start_time = sub;
|
||||
kernel_info_output->push_back(kinfo);
|
||||
}
|
||||
// End-Time
|
||||
found = line.find("end_time");
|
||||
if (found != std::string::npos) {
|
||||
int spos = line.find(",", found);
|
||||
int epos = line.find(")", spos);
|
||||
std::string sub = line.substr(spos + 1, epos - spos - 1);
|
||||
kinfo.end_time = sub;
|
||||
kernel_info_output->push_back(kinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses kernel-names from a pre-saved golden out files
|
||||
* and saves them in a vector.
|
||||
*/
|
||||
void ApplicationParser::GetKernelInfoForGoldenOutput(const char* app_name, std::string file_name,
|
||||
std::vector<KernelInfo>* kernel_info_output) {
|
||||
std::string entry;
|
||||
std::string path = GetRunningPath("runFeatureTests");
|
||||
entry = path.append("gtests/apps/goldentraces/") + file_name;
|
||||
// parse kernel info fields for golden output
|
||||
ParseKernelInfoFields(entry, kernel_info_output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a given appllication and saves profiler output.
|
||||
* These output lines can be letter passed for kernel informations
|
||||
* i.e: kernel_names
|
||||
*/
|
||||
void ApplicationParser::ProcessApplication(std::stringstream& ss) {
|
||||
FILE* handle = popen(ss.str().c_str(), "r");
|
||||
ASSERT_NE(handle, nullptr);
|
||||
|
||||
char* ln{NULL};
|
||||
std::string temp{""};
|
||||
size_t len{0};
|
||||
|
||||
while (getline(&ln, &len, handle) != -1) {
|
||||
temp = temp + std::string(ln);
|
||||
}
|
||||
|
||||
free(ln);
|
||||
size_t pos{0};
|
||||
std::string delimiter{"\n"};
|
||||
while ((pos = temp.find(delimiter)) != std::string::npos) {
|
||||
output_lines.push_back(temp.substr(0, pos));
|
||||
temp.erase(0, pos + delimiter.length());
|
||||
}
|
||||
|
||||
pclose(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses kernel-info for golden output file
|
||||
* and saves them in a vector.
|
||||
*/
|
||||
void ApplicationParser::ParseKernelInfoFields(const std::string& s,
|
||||
std::vector<KernelInfo>* kernel_info_output) {
|
||||
std::string line;
|
||||
KernelInfo kinfo;
|
||||
|
||||
std::ifstream golden_file(s);
|
||||
while (!golden_file.eof()) {
|
||||
getline(golden_file, line);
|
||||
if (std::regex_match(line, std::regex("(dispatch)(.*)"))) {
|
||||
int spos = line.find("[");
|
||||
int epos = line.find("]", spos);
|
||||
std::string sub = line.substr(spos + 1, epos - spos - 1);
|
||||
kinfo.dispatch_id = sub;
|
||||
kernel_info_output->push_back(kinfo);
|
||||
|
||||
// Kernel-Name
|
||||
size_t found = line.find("kernel-name");
|
||||
if (found != std::string::npos) {
|
||||
int spos = found;
|
||||
int epos = line.find(")", spos);
|
||||
int length = std::string("kernel-name").length();
|
||||
std::string sub = line.substr(spos + length + 1, epos - spos - length - 1);
|
||||
|
||||
kinfo.kernel_name = sub;
|
||||
kernel_info_output->push_back(kinfo);
|
||||
}
|
||||
// Start-Time
|
||||
found = line.find("start_time");
|
||||
if (found != std::string::npos) {
|
||||
int spos = found;
|
||||
int epos = line.find(",", spos);
|
||||
int length = std::string("start_time").length();
|
||||
std::string sub = line.substr(spos + length + 1, epos - spos - length - 1);
|
||||
kinfo.start_time = sub;
|
||||
kernel_info_output->push_back(kinfo);
|
||||
}
|
||||
// End-Time
|
||||
found = line.find("end_time");
|
||||
if (found != std::string::npos) {
|
||||
int spos = line.find(",", found);
|
||||
int epos = line.find(")", spos);
|
||||
std::string sub = line.substr(spos + 1, epos - spos - 1);
|
||||
kinfo.end_time = sub;
|
||||
kernel_info_output->push_back(kinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
golden_file.close();
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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.
|
||||
*/
|
||||
#ifndef TESTS_FEATURETESTS_PROFILER_GTESTS_APPS_PROFILER_GTEST_H_
|
||||
#define TESTS_FEATURETESTS_PROFILER_GTESTS_APPS_PROFILER_GTEST_H_
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/* --------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @Synopsis Implementation of a Parser class for Profiler output
|
||||
* Parses pre-saved golden output for kernel info and saves them in a vector
|
||||
* Executes appliaction(passed as param:app_name) and saves parsed kernel info
|
||||
* in a vector.
|
||||
* Subsequent tests can use this to parse different applications
|
||||
*/
|
||||
/* --------------------------------------------------------------------------*/
|
||||
|
||||
class ApplicationParser : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp(const char *app_name) { SetApplicationEnv(app_name); }
|
||||
virtual void TearDown() {}
|
||||
//!< This can be appended for other kernel info fields; eg: Agent-Name etc.
|
||||
struct KernelInfo {
|
||||
std::string dispatch_id;
|
||||
std::string gpu_id;
|
||||
std::string queue_id;
|
||||
std::string queue_index;
|
||||
std::string pid;
|
||||
std::string tid;
|
||||
std::string obj;
|
||||
std::string kernel_name;
|
||||
std::string start_time;
|
||||
std::string end_time;
|
||||
};
|
||||
|
||||
//!< saves lines of profiler output
|
||||
std::vector<std::string> output_lines;
|
||||
|
||||
public:
|
||||
//!< Sets application enviornment by seting HSA_TOOLS_LIB.
|
||||
void SetApplicationEnv(const char *app_name);
|
||||
|
||||
//!< Parses kernel-info from a pre-saved golden out files
|
||||
// and saves them in a vector.
|
||||
void GetKernelInfoForGoldenOutput(
|
||||
const char *app_name, std::string filename,
|
||||
std::vector<KernelInfo> *kernel_info_output);
|
||||
|
||||
//!< Parses kernel-info after running profiler against curent application
|
||||
// and saves them in a vector.
|
||||
void GetKernelInfoForRunningApplication(
|
||||
std::vector<KernelInfo> *kernel_info_output);
|
||||
|
||||
private:
|
||||
//!< Runs a given appllication and saves profiler output.
|
||||
// These output lines can be letter passed for kernel informations
|
||||
// i.e: kernel_names
|
||||
void ProcessApplication(std::stringstream &ss);
|
||||
|
||||
//!< Parses kernel info fields from given input
|
||||
// i.e: kernel_names, kernel_duration
|
||||
void ParseKernelInfoFields(const std::string &s,
|
||||
std::vector<KernelInfo> *kernel_info_output);
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @Synopsis Implementation of a ProfilerTest
|
||||
* Subsequent tests can use this to parse different applications
|
||||
*/
|
||||
/* --------------------------------------------------------------------------*/
|
||||
|
||||
class ProfilerTest : public ApplicationParser {
|
||||
protected:
|
||||
virtual void SetUp(const char *app_name) {
|
||||
ApplicationParser::SetUp(app_name);
|
||||
}
|
||||
};
|
||||
#endif // TESTS_FEATURETESTS_PROFILER_GTESTS_APPS_PROFILER_GTEST_H_
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/* Copyright (c) 2022 Advanced Micro Devices, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE. */
|
||||
#include <gtest/gtest.h>
|
||||
#include <hsa/hsa.h>
|
||||
|
||||
// Run 2 loops of {hsa_init(); hsa_iterate_agents(); hsa_shut_down()} to test
|
||||
// that the profiler tool correctly unloaded after the 1st iteration and then
|
||||
// reloaded for the 2nd iteration.
|
||||
class LoadUnloadTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
// start basic app
|
||||
hsa_init();
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
// stop basic app and unset tools lib
|
||||
hsa_shut_down();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(LoadUnloadTest, WhenLoadingFirstTimeThenToolLoadsUnloadsSuccessfully) {
|
||||
// Tool loaded in the setup
|
||||
// Tool unloaded in teardown
|
||||
|
||||
// iterate for gpu's
|
||||
hsa_status_t status = hsa_iterate_agents(
|
||||
[](hsa_agent_t agent, void *) {
|
||||
hsa_device_type_t type;
|
||||
return hsa_agent_get_info(agent, HSA_AGENT_INFO_DEVICE, &type);
|
||||
},
|
||||
nullptr);
|
||||
|
||||
EXPECT_EQ(HSA_STATUS_SUCCESS, status);
|
||||
}
|
||||
|
||||
TEST_F(LoadUnloadTest, WhenLoadingSecondTimeThenToolLoadsUnloadsSuccessfully) {
|
||||
// Tool loaded in the setup
|
||||
// Tool unloaded in teardown
|
||||
|
||||
// iterate for gpu's
|
||||
hsa_status_t status = hsa_iterate_agents(
|
||||
[](hsa_agent_t agent, void *) {
|
||||
hsa_device_type_t type;
|
||||
return hsa_agent_get_info(agent, HSA_AGENT_INFO_DEVICE, &type);
|
||||
},
|
||||
nullptr);
|
||||
|
||||
EXPECT_EQ(HSA_STATUS_SUCCESS, status);
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
/******************************************************************************
|
||||
Copyright (c) 2018 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 <gtest/gtest.h>
|
||||
#include <hip/hip_runtime.h>
|
||||
#include <rocprofiler.h>
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "src/utils/helper.h"
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
/** \mainpage ROC Profiler API Test
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test is to check ROCmTools APIs from multiple threads
|
||||
* and verify if each API succeeds and multiple contexts are collected and
|
||||
* verified.
|
||||
*
|
||||
* An empty kernel is launched on multiple threads and profiling context is
|
||||
* collected and verified from each thread.
|
||||
*/
|
||||
|
||||
// empty kernel
|
||||
__global__ void kernel() {}
|
||||
|
||||
class ProfilerAPITest : public ::testing::Test {
|
||||
protected:
|
||||
// function to check profiler API status
|
||||
static void CheckApi(rocprofiler_status_t status) {
|
||||
ASSERT_EQ(status, ROCPROFILER_STATUS_SUCCESS);
|
||||
};
|
||||
|
||||
// launches an empty kernel in profiler context
|
||||
static void KernelLaunch() {
|
||||
// run empty kernel
|
||||
kernel<<<1, 1>>>();
|
||||
hipDeviceSynchronize();
|
||||
}
|
||||
|
||||
// callback function to dump profiler data
|
||||
static void FlushCallback(const rocprofiler_record_header_t* record,
|
||||
const rocprofiler_record_header_t* end_record,
|
||||
int64_t session_id) {
|
||||
while (record < end_record) {
|
||||
if (!record) break;
|
||||
if (record->kind == ROCPROFILER_PROFILER_RECORD) {
|
||||
const rocprofiler_record_profiler_t* profiler_record =
|
||||
reinterpret_cast<const rocprofiler_record_profiler_t*>(record);
|
||||
size_t name_length;
|
||||
CheckApi(rocprofiler_query_kernel_info_size(
|
||||
ROCPROFILER_KERNEL_NAME, profiler_record->kernel_id, &name_length));
|
||||
const char* kernel_name_c =
|
||||
static_cast<const char*>(malloc(name_length * sizeof(char)));
|
||||
CheckApi(rocprofiler_query_kernel_info(ROCPROFILER_KERNEL_NAME,
|
||||
profiler_record->kernel_id,
|
||||
&kernel_name_c));
|
||||
int gpu_index = profiler_record->gpu_id.handle;
|
||||
uint64_t start_time = profiler_record->timestamps.begin.value;
|
||||
uint64_t end_time = profiler_record->timestamps.end.value;
|
||||
|
||||
// Check for each kernel if endtime > starttime
|
||||
ASSERT_GT(end_time, start_time);
|
||||
|
||||
// Check for each kernel name_length is +ve
|
||||
ASSERT_GT(name_length, 0);
|
||||
|
||||
// Check kernel name
|
||||
ASSERT_EQ(
|
||||
rocmtools::truncate_name(rocmtools::cxx_demangle(kernel_name_c)),
|
||||
"kernel");
|
||||
}
|
||||
CheckApi(rocprofiler_next_record(record, &record));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ProfilerAPITest, WhenRunningMultipleThreadsProfilerAPIsWorkFine) {
|
||||
// Get the system cores
|
||||
int num_cpu_cores = GetNumberOfCores();
|
||||
|
||||
// create as many threads as number of cores in system
|
||||
std::vector<std::thread> threads(num_cpu_cores);
|
||||
|
||||
// inititalize profiler by creating rocmtool object
|
||||
CheckApi(rocprofiler_initialize());
|
||||
|
||||
// Counter Collection with timestamps
|
||||
rocprofiler_session_id_t session_id;
|
||||
std::vector<const char*> counters;
|
||||
counters.emplace_back("SQ_WAVES");
|
||||
CheckApi(rocprofiler_create_session(ROCPROFILER_APPLICATION_REPLAY_MODE,
|
||||
&session_id));
|
||||
CheckApi(rocprofiler_add_session_mode(session_id, ROCPROFILER_ASYNC_FLUSH,
|
||||
ROCPROFILER_COUNTERS_COLLECTION));
|
||||
CheckApi(rocprofiler_set_session_async_callback(
|
||||
session_id, ROCPROFILER_COUNTERS_COLLECTION,
|
||||
rocprofiler_session_buffer_size_t{0x8000}, FlushCallback,
|
||||
rocprofiler_flush_buffer_interval_t{0}));
|
||||
rocprofiler_filter_t filter{ROCPROFILER_FILTER_PROFILER_COUNTER_NAMES,
|
||||
&counters[0],
|
||||
rocprofiler_filter_data_count_t{counters.size()}};
|
||||
CheckApi(rocprofiler_session_set_filters(ROCPROFILER_COUNTERS_COLLECTION,
|
||||
&filter, rocprofiler_filters_count_t{1},
|
||||
session_id));
|
||||
|
||||
// activating profiler session
|
||||
CheckApi(rocprofiler_start_session(session_id));
|
||||
|
||||
// launch kernel on each thread
|
||||
for (int n = 0; n < num_cpu_cores; ++n) {
|
||||
threads[n] = std::thread(KernelLaunch);
|
||||
}
|
||||
|
||||
// wait for all kernel launches to complete
|
||||
for (int n = 0; n < num_cpu_cores; ++n) {
|
||||
threads[n].join();
|
||||
}
|
||||
// dump profiler data
|
||||
CheckApi(rocprofiler_flush_data(session_id));
|
||||
|
||||
// deactivate session
|
||||
CheckApi(rocprofiler_terminate_session(session_id));
|
||||
|
||||
// destroy session
|
||||
CheckApi(rocprofiler_destroy_session(session_id));
|
||||
|
||||
// finalize profiler by destroying rocmtool object
|
||||
CheckApi(rocprofiler_finalize());
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// Entry Point for Gtests Infra
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
//testing::GTEST_FLAG(filter)="-HSATest.*";
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 "utils/csv_parser.h"
|
||||
|
||||
namespace rocmtools {
|
||||
namespace tests {
|
||||
namespace utility {
|
||||
|
||||
// Tokenize a comma separated string and saves result in vector
|
||||
int CSVParser::GetTockenizedString(std::string str,
|
||||
std::vector<std::string> &stringVec,
|
||||
char delim) {
|
||||
char *token = strtok(const_cast<char *>(str.c_str()), &delim);
|
||||
while (token) {
|
||||
std::string temp = token;
|
||||
stringVec.push_back(temp);
|
||||
token = strtok(NULL, &delim);
|
||||
}
|
||||
|
||||
return stringVec.size();
|
||||
}
|
||||
|
||||
// Get map for collected counters
|
||||
countermap &CSVParser::GetCounterMap() { return counter_map_; }
|
||||
|
||||
// Read counter value based on row-column
|
||||
std::string *CSVParser::ReadCounter(uint32_t row, uint32_t col) {
|
||||
auto itr = counter_map_.find(row);
|
||||
|
||||
if (itr != counter_map_.end()) {
|
||||
std::map<uint32_t, std::string> &rowmap = itr->second;
|
||||
auto it = rowmap.find(col);
|
||||
if (it != rowmap.end()) {
|
||||
return &(it->second);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Parses CSV file and saves result in a map
|
||||
void CSVParser::ParseCSV(const char *path) {
|
||||
FILE *pFile = fopen(path, "r");
|
||||
|
||||
if (pFile) {
|
||||
// Relocate the file pointer on the stream.
|
||||
fseek(pFile, 0, SEEK_END);
|
||||
// returns the current file position of the specified stream
|
||||
// with respect to the starting of the file
|
||||
uint32_t uSize = ftell(pFile);
|
||||
// Make the position pointer of the file pFile point
|
||||
// to the beginning of the file
|
||||
rewind(pFile);
|
||||
|
||||
char *fileBuffer = new char[uSize];
|
||||
size_t size = fread(fileBuffer, 1, uSize, pFile);
|
||||
if (size < 0) std::cerr << "Incorrect File!" << std::endl;
|
||||
|
||||
std::map<uint32_t, std::string> rowmap;
|
||||
uint32_t uiIndex = 1;
|
||||
|
||||
char *pBegin = fileBuffer;
|
||||
char *pEnd = strchr(pBegin, '\n');
|
||||
|
||||
// The beginning of the second line, discarding the first line
|
||||
pBegin = pEnd + 1;
|
||||
pEnd = strchr(pBegin, '\n');
|
||||
|
||||
while (pEnd) {
|
||||
std::string tmp;
|
||||
tmp.insert(0, pBegin, pEnd - pBegin);
|
||||
assert(!tmp.empty());
|
||||
// Store the string of each line in the map,
|
||||
// the key is the sequence number,
|
||||
// and the value is the string
|
||||
rowmap[uiIndex++] = tmp;
|
||||
|
||||
pBegin = pEnd + 1;
|
||||
pEnd = strchr(pBegin, '\n');
|
||||
}
|
||||
// clear buffers
|
||||
delete[] fileBuffer;
|
||||
fileBuffer = nullptr;
|
||||
pBegin = nullptr;
|
||||
pEnd = nullptr;
|
||||
|
||||
auto itr = rowmap.begin();
|
||||
for (; itr != rowmap.end(); ++itr) {
|
||||
std::vector<std::string> countervec;
|
||||
std::map<uint32_t, std::string> rowmap_tmp;
|
||||
assert(GetTockenizedString(itr->second, countervec) > 0);
|
||||
|
||||
std::vector<std::string>::size_type idx = 0;
|
||||
for (; idx != countervec.size(); ++idx) {
|
||||
rowmap_tmp[idx + 1] = countervec[idx];
|
||||
}
|
||||
counter_map_[itr->first] = rowmap_tmp;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(pFile);
|
||||
}
|
||||
|
||||
// Parses profiler output buffer and saves result in a map
|
||||
void CSVParser::ParseCSV(std::string buffer) {
|
||||
std::vector<char> buff(buffer.begin(), buffer.end());
|
||||
char *pBegin = &buff[0];
|
||||
char *pEnd = strchr(pBegin, '\n');
|
||||
|
||||
// The beginning of the second line, discarding the first line
|
||||
pBegin = pEnd + 1;
|
||||
pEnd = strchr(pBegin, '\n');
|
||||
std::map<uint32_t, std::string> rowmap;
|
||||
uint32_t uiIndex = 1;
|
||||
|
||||
while (pEnd) {
|
||||
std::string tmp;
|
||||
tmp.insert(0, pBegin, pEnd - pBegin);
|
||||
// Store the string of each line in the map,
|
||||
// the key is the sequence number,
|
||||
// and the value is the string
|
||||
rowmap[uiIndex++] = tmp;
|
||||
|
||||
pBegin = pEnd + 1;
|
||||
pEnd = strchr(pBegin, '\n');
|
||||
}
|
||||
|
||||
// clear buffers
|
||||
buff.clear();
|
||||
pBegin = nullptr;
|
||||
pEnd = nullptr;
|
||||
|
||||
auto itr = rowmap.begin();
|
||||
for (; itr != rowmap.end(); ++itr) {
|
||||
std::vector<std::string> countervec;
|
||||
std::map<uint32_t, std::string> rowmap_tmp;
|
||||
GetTockenizedString(itr->second, countervec);
|
||||
|
||||
std::vector<std::string>::size_type idx = 0;
|
||||
for (; idx != countervec.size(); ++idx) {
|
||||
rowmap_tmp[idx + 1] = countervec[idx];
|
||||
}
|
||||
counter_map_[itr->first] = rowmap_tmp;
|
||||
}
|
||||
}
|
||||
} // namespace utility
|
||||
} // namespace tests
|
||||
} // namespace rocmtools
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
/*
|
||||
Copyright (c) 2015-2016 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.
|
||||
*/
|
||||
#ifndef TESTS_FEATURETESTS_PROFILER_UTILS_CSV_PARSER_H_
|
||||
#define TESTS_FEATURETESTS_PROFILER_UTILS_CSV_PARSER_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/* --------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @Synopsis Implementation of a CSV Parser class for Profiler output
|
||||
* when running to collect counters.Subsequent counter collection tests
|
||||
* can use this to parse different applications.
|
||||
*/
|
||||
/* --------------------------------------------------------------------------*/
|
||||
namespace rocmtools {
|
||||
namespace tests {
|
||||
namespace utility {
|
||||
using countermap = std::map<uint32_t, std::map<uint32_t, std::string>>;
|
||||
|
||||
class CSVParser {
|
||||
public:
|
||||
CSVParser() {}
|
||||
|
||||
/**
|
||||
* Parses CSV file and saves result in a map
|
||||
*
|
||||
* Stores csv data as a 2-D array in row-column format
|
||||
* Skips first line of input csv as it only contains field names
|
||||
*
|
||||
* @param[in] path Pointer to the csv path.
|
||||
*
|
||||
* @return Returns 0 on success and -1 on error.
|
||||
*/
|
||||
void ParseCSV(const char *path);
|
||||
|
||||
/**
|
||||
* Parses profiler output buffer and saves result in a map
|
||||
*
|
||||
* Stores csv data as a 2-D array in row-column format
|
||||
* Skips first line of input csv as it only contains field names
|
||||
*
|
||||
* @param[in] path Pointer to the csv path.
|
||||
*
|
||||
* @return Returns 0 on success and -1 on error.
|
||||
*/
|
||||
void ParseCSV(std::string buffer);
|
||||
|
||||
/**
|
||||
* Read counter value based on row-column
|
||||
*
|
||||
* @param[in] row row number to be read in csv.
|
||||
*
|
||||
* @param[in] col column to be read in csv.(i.e: counter value)
|
||||
*
|
||||
* @return If found, returns counter value as a string pointer, nullptr
|
||||
* otherwise.
|
||||
*/
|
||||
std::string *ReadCounter(uint32_t row, uint32_t col);
|
||||
|
||||
/**
|
||||
* Tokenize a comma separated string and saves result in vector
|
||||
*
|
||||
* @param[in] str input string to be tokenized
|
||||
*
|
||||
* @param[in] csvtable vector to store tokenized values
|
||||
*
|
||||
* @param[in] delim delimitre used for tokenizing
|
||||
*
|
||||
* @return returns vector size of delimitd values
|
||||
*/
|
||||
int GetTockenizedString(std::string str, std::vector<std::string> &csvtable,
|
||||
char delim = ',');
|
||||
|
||||
/**
|
||||
* A getter for a map of collected counters
|
||||
* *
|
||||
* @return Returns a map of collected counters.
|
||||
*/
|
||||
countermap &GetCounterMap();
|
||||
|
||||
private:
|
||||
// map for counter collection
|
||||
countermap counter_map_;
|
||||
};
|
||||
} // namespace utility
|
||||
} // namespace tests
|
||||
} // namespace rocmtools
|
||||
|
||||
using rocmtools::tests::utility::countermap;
|
||||
using rocmtools::tests::utility::CSVParser;
|
||||
#endif // TESTS_FEATURETESTS_PROFILER_UTILS_CSV_PARSER_H_
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 "utils/test_utils.h"
|
||||
|
||||
namespace rocmtools {
|
||||
namespace tests {
|
||||
namespace utility {
|
||||
|
||||
// This function returns the running path of executable
|
||||
std::string GetRunningPath(std::string string_to_erase) {
|
||||
std::string path;
|
||||
char *real_path;
|
||||
Dl_info dl_info;
|
||||
|
||||
if (0 != dladdr(reinterpret_cast<void *>(main), &dl_info)) {
|
||||
std::string to_erase = string_to_erase;
|
||||
path = dl_info.dli_fname;
|
||||
real_path = realpath(path.c_str(), NULL);
|
||||
if (real_path == nullptr) {
|
||||
throw(std::string("Error! in extracting real path"));
|
||||
}
|
||||
path.clear(); // reset path
|
||||
path.append(real_path);
|
||||
|
||||
size_t pos = path.find(to_erase);
|
||||
if (pos != std::string::npos) path.erase(pos, to_erase.length());
|
||||
} else {
|
||||
throw(std::string("Error! in extracting real path"));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
// This function returns number of cores
|
||||
// available in system
|
||||
int GetNumberOfCores() {
|
||||
std::ifstream cpuinfo("/proc/cpuinfo");
|
||||
const int num_cpu_cores = std::count(
|
||||
std::istream_iterator<std::string>(cpuinfo),
|
||||
std::istream_iterator<std::string>(), std::string("processor"));
|
||||
return num_cpu_cores;
|
||||
}
|
||||
|
||||
} // namespace utility
|
||||
} // namespace tests
|
||||
} // namespace rocmtools
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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.
|
||||
*/
|
||||
#ifndef TESTS_FEATURETESTS_PROFILER_UTILS_TEST_UTILS_H_
|
||||
#define TESTS_FEATURETESTS_PROFILER_UTILS_TEST_UTILS_H_
|
||||
|
||||
#include <cxxabi.h> // for __cxa_demangle
|
||||
#include <dlfcn.h> // for dladdr
|
||||
#include <execinfo.h> // for backtrace
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
|
||||
namespace rocmtools {
|
||||
namespace tests {
|
||||
namespace utility {
|
||||
|
||||
// Get current running path
|
||||
std::string GetRunningPath(std::string string_to_erase);
|
||||
|
||||
// Get Number of cores in the system
|
||||
int GetNumberOfCores();
|
||||
|
||||
} // namespace utility
|
||||
} // namespace tests
|
||||
} // namespace rocmtools
|
||||
|
||||
// used for dl_addr to locate the running
|
||||
// path for executable
|
||||
int main(int argc, char** argv);
|
||||
|
||||
using rocmtools::tests::utility::GetNumberOfCores;
|
||||
using rocmtools::tests::utility::GetRunningPath;
|
||||
|
||||
#endif // TESTS_FEATURETESTS_PROFILER_UTILS_TEST_UTILS_H_
|
||||
@@ -0,0 +1,40 @@
|
||||
# Set the HIP language runtime link flags as FindHIP does not set them.
|
||||
set(CMAKE_INSTALL_TESTDIR test/${PROJECT_NAME})
|
||||
set(CMAKE_EXECUTABLE_RUNTIME_HIP_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG})
|
||||
set(CMAKE_EXECUTABLE_RUNTIME_HIP_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP})
|
||||
set(CMAKE_EXECUTABLE_RPATH_LINK_HIP_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG})
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${ROCM_PATH}/lib/cmake/hip")
|
||||
set(CMAKE_HIP_ARCHITECTURES OFF)
|
||||
find_package(HIP REQUIRED MODULE)
|
||||
|
||||
# Setup testing
|
||||
enable_testing()
|
||||
find_package(GTest REQUIRED)
|
||||
|
||||
# installing the golden traces
|
||||
file(GLOB files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "gtests/apps/goldentraces/*.txt")
|
||||
foreach(file ${files})
|
||||
configure_file(${file} ${PROJECT_BINARY_DIR}/tests/featuretests/tracer/${file} COPYONLY)
|
||||
endforeach()
|
||||
|
||||
# Compile Applications
|
||||
# hip_helloworld
|
||||
set_source_files_properties(gtests/apps/hip/hello_world.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
hip_add_executable(tracer_hip_helloworld gtests/apps/hip/hello_world.cpp)
|
||||
set_target_properties(tracer_hip_helloworld PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/tests/featuretests/tracer/gtests/apps")
|
||||
|
||||
# Add test cpp file
|
||||
add_executable(runTracerFeatureTests
|
||||
gtests/gtests_main.cpp
|
||||
utils/test_utils.cpp
|
||||
gtests/apps/tracer_gtest.cpp
|
||||
gtests/apps/hip/hello_world_gtest.cpp
|
||||
)
|
||||
|
||||
# Link test executable against gtest & gtest_main
|
||||
target_include_directories(runTracerFeatureTests PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/tests/featuretests/tracer)
|
||||
target_link_libraries(runTracerFeatureTests PRIVATE hsa-runtime64::hsa-runtime64
|
||||
GTest::gtest GTest::gtest_main
|
||||
Threads::Threads dl stdc++fs)
|
||||
add_dependencies(tests runTracerFeatureTests)
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
0x2fbdf0 agent cpu
|
||||
0x2fcc70 agent gpu
|
||||
9598333364898937
|
||||
Enabling API Tracing
|
||||
Record [1], Domain(HIP_API_DOMAIN), Begin(9598333370773048), End(9598333370809238), Correlation ID( 1), ROCTX ID(2), Function(hipGetDeviceProperties)
|
||||
Record [3], Domain(HIP_API_DOMAIN), Begin(9598333370859109), End(9598333370912969), Correlation ID( 2), ROCTX ID(0), Function(hipMalloc)
|
||||
Record [5], Domain(HIP_API_DOMAIN), Begin(9598333370924259), End(9598333370928959), Correlation ID( 3), ROCTX ID(0), Function(hipMalloc)
|
||||
Record [7], Domain(HIP_API_DOMAIN), Begin(9598333370940519), End(9598333575713652), Correlation ID( 4), ROCTX ID(0), Function(hipMemcpy)
|
||||
Record [9], Domain(HIP_API_DOMAIN), Begin(9598333575750182), End(9598333575768982), Correlation ID( 5), ROCTX ID(0), Function(__hipPushCallConfiguration)
|
||||
Record [11], Domain(HIP_API_DOMAIN), Begin(9598333575779902), End(9598333575783532), Correlation ID( 6), ROCTX ID(0), Function(__hipPopCallConfiguration)
|
||||
Record [13], Domain(HIP_API_DOMAIN), Begin(9598333575791112), End(9598333576071305), Correlation ID( 7), ROCTX ID(0), Function(hipLaunchKernel), Kernel Name(helloworld(char*, char*))
|
||||
Record [15], Domain(HIP_API_DOMAIN), Begin(9598333576098325), End(9598333576567689), Correlation ID( 8), ROCTX ID(0), Function(hipMemcpy)
|
||||
Record [17], Domain(HIP_API_DOMAIN), Begin(9598333576581979), End(9598333576591729), Correlation ID( 9), ROCTX ID(0), Function(hipFree)
|
||||
Record [19], Domain(HIP_API_DOMAIN), Begin(9598333576600359), End(9598333576603379), Correlation ID( 10), ROCTX ID(0), Function(hipFree)
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hip/hip_runtime.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#define SUCCESS 0
|
||||
#define FAILURE 1
|
||||
|
||||
__global__ void helloworld(char* in, char* out) {
|
||||
int num = hipThreadIdx_x + hipBlockDim_x * hipBlockIdx_x;
|
||||
out[num] = in[num] + 1;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
hipDeviceProp_t devProp;
|
||||
hipGetDeviceProperties(&devProp, 0);
|
||||
|
||||
/* Initial input,output for the host and create memory objects for the
|
||||
* kernel*/
|
||||
const char* input = "GdkknVnqkc";
|
||||
size_t strlength = strlen(input);
|
||||
|
||||
char* output = reinterpret_cast<char*>(malloc(strlength + 1));
|
||||
|
||||
char* inputBuffer;
|
||||
char* outputBuffer;
|
||||
hipMalloc(reinterpret_cast<void**>(&inputBuffer), (strlength + 1) * sizeof(char));
|
||||
hipMalloc(reinterpret_cast<void**>(&outputBuffer), (strlength + 1) * sizeof(char));
|
||||
|
||||
hipMemcpy(inputBuffer, input, (strlength + 1) * sizeof(char), hipMemcpyHostToDevice);
|
||||
|
||||
hipLaunchKernelGGL(helloworld, dim3(1), dim3(strlength), 0, 0, inputBuffer, outputBuffer);
|
||||
|
||||
hipMemcpy(output, outputBuffer, (strlength + 1) * sizeof(char), hipMemcpyDeviceToHost);
|
||||
|
||||
hipFree(inputBuffer);
|
||||
hipFree(outputBuffer);
|
||||
|
||||
output[strlength] = '\0'; // Add the terminal character to the end of output.
|
||||
|
||||
free(output);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 <vector>
|
||||
|
||||
#include "gtests/apps/tracer_gtest.h"
|
||||
|
||||
constexpr auto kGoldenOutputHelloworld = "hip_helloworld_golden_traces.txt";
|
||||
|
||||
class HelloWorldTest : public ProfilerTest {
|
||||
protected:
|
||||
std::vector<KernelInfo> golden_kernel_info;
|
||||
void SetUp() {
|
||||
ProfilerTest::SetUp("tracer_hip_helloworld", "--hip-api ");
|
||||
GetKernelInfoForGoldenOutput("tracer_hip_helloworld", kGoldenOutputHelloworld,
|
||||
&golden_kernel_info);
|
||||
}
|
||||
};
|
||||
|
||||
// Test:1 Compares total num of kernel-names in golden output against current
|
||||
// profiler output
|
||||
TEST_F(HelloWorldTest, WhenRunningTracerWithAppThenKernelInfoMatchWithGoldenOutput) {
|
||||
// kernel info in current profiler run
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
EXPECT_EQ(golden_kernel_info.size(), current_kernel_info.size());
|
||||
}
|
||||
|
||||
// Test:2 Compares order of kernel-names in golden output against current
|
||||
// profiler output
|
||||
TEST_F(HelloWorldTest, WhenRunningProfilerWithAppThenFunctionNamessMatchWithGoldenOutput) {
|
||||
// kernel info in current profiler run
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
EXPECT_EQ(golden_kernel_info[0].function, current_kernel_info[0].function);
|
||||
EXPECT_EQ(golden_kernel_info[1].function, current_kernel_info[1].function);
|
||||
}
|
||||
|
||||
// Test:3 Compares order of kernel-names in golden output against current
|
||||
// profiler output
|
||||
TEST_F(HelloWorldTest, WhenRunningProfilerWithAppThenKernelDurationShouldBePositive) {
|
||||
// kernel info in current profiler run
|
||||
std::vector<KernelInfo> current_kernel_info;
|
||||
|
||||
GetKernelInfoForRunningApplication(¤t_kernel_info);
|
||||
ASSERT_TRUE(current_kernel_info.size());
|
||||
|
||||
EXPECT_GT(current_kernel_info.size(), 0);
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 "gtests/apps/tracer_gtest.h"
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
/**
|
||||
* Sets application enviornment by seting HSA_TOOLS_LIB.
|
||||
*/
|
||||
void ApplicationParser::SetApplicationEnv(const char* app_name, const char* trace_option) {
|
||||
std::string app_path = GetRunningPath("tests/featuretests/tracer/runTracerFeatureTests");
|
||||
|
||||
std::stringstream hsa_tools_lib_path;
|
||||
hsa_tools_lib_path << app_path << "librocprofiler_tool.so";
|
||||
setenv("LD_PRELOAD", hsa_tools_lib_path.str().c_str(), true);
|
||||
|
||||
// set --hip-api option
|
||||
setenv("ROCPROFILER_HIP_API_TRACE", "1", true);
|
||||
|
||||
std::stringstream os;
|
||||
os << app_path << "tests/featuretests/tracer/gtests/apps/" << app_name;
|
||||
ProcessApplication(os);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses kernel-info after running profiler against curent application
|
||||
* and saves them in a vector.
|
||||
*/
|
||||
void ApplicationParser::GetKernelInfoForRunningApplication(
|
||||
std::vector<KernelInfo>* kernel_info_output) {
|
||||
KernelInfo kinfo;
|
||||
for (std::string line : output_lines) {
|
||||
if (std::regex_match(line, std::regex("(Record)(.*)"))) {
|
||||
int spos = line.find("[");
|
||||
int epos = line.find("]", spos);
|
||||
std::string sub = line.substr(spos + 1, epos - spos - 1);
|
||||
kinfo.record_id = sub;
|
||||
kernel_info_output->push_back(kinfo);
|
||||
|
||||
// Kernel-Name
|
||||
size_t found = line.find("Function");
|
||||
if (found != std::string::npos) {
|
||||
int spos = found;
|
||||
int epos = line.find(")", spos);
|
||||
int length = std::string("kernel-name").length();
|
||||
std::string sub = line.substr(spos + length + 1, epos - spos - length - 1);
|
||||
|
||||
kinfo.function = sub;
|
||||
kernel_info_output->push_back(kinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses kernel-names from a pre-saved golden out files
|
||||
* and saves them in a vector.
|
||||
*/
|
||||
void ApplicationParser::GetKernelInfoForGoldenOutput(const char* app_name, std::string file_name,
|
||||
std::vector<KernelInfo>* kernel_info_output) {
|
||||
std::string entry;
|
||||
std::string path = GetRunningPath("runTracerFeatureTests");
|
||||
entry = path.append("gtests/apps/goldentraces/") + file_name;
|
||||
|
||||
// parse kernel info fields for golden output
|
||||
ParseKernelInfoFields(entry, kernel_info_output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a given appllication and saves profiler output.
|
||||
* These output lines can be letter passed for kernel informations
|
||||
* i.e: kernel_names
|
||||
*/
|
||||
void ApplicationParser::ProcessApplication(std::stringstream& ss) {
|
||||
FILE* handle = popen(ss.str().c_str(), "r");
|
||||
ASSERT_NE(handle, nullptr);
|
||||
|
||||
char* ln{NULL};
|
||||
std::string temp{""};
|
||||
size_t len{0};
|
||||
|
||||
while (getline(&ln, &len, handle) != -1) {
|
||||
temp = temp + std::string(ln);
|
||||
}
|
||||
|
||||
free(ln);
|
||||
size_t pos{0};
|
||||
std::string delimiter{"\n"};
|
||||
while ((pos = temp.find(delimiter)) != std::string::npos) {
|
||||
output_lines.push_back(temp.substr(0, pos));
|
||||
temp.erase(0, pos + delimiter.length());
|
||||
}
|
||||
|
||||
pclose(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses kernel-info for golden output file
|
||||
* and saves them in a vector.
|
||||
*/
|
||||
void ApplicationParser::ParseKernelInfoFields(const std::string& s,
|
||||
std::vector<KernelInfo>* kernel_info_output) {
|
||||
std::string line;
|
||||
KernelInfo kinfo;
|
||||
|
||||
std::ifstream golden_file(s);
|
||||
while (!golden_file.eof()) {
|
||||
getline(golden_file, line);
|
||||
if (std::regex_match(line, std::regex("(Record)(.*)"))) {
|
||||
int spos = line.find("[");
|
||||
int epos = line.find("]", spos);
|
||||
std::string sub = line.substr(spos + 1, epos - spos - 1);
|
||||
kinfo.record_id = sub;
|
||||
kernel_info_output->push_back(kinfo);
|
||||
|
||||
// Kernel-Name
|
||||
size_t found = line.find("Function");
|
||||
if (found != std::string::npos) {
|
||||
int spos = found;
|
||||
int epos = line.find(")", spos);
|
||||
int length = std::string("kernel-name").length();
|
||||
std::string sub = line.substr(spos + length + 1, epos - spos - length - 1);
|
||||
|
||||
kinfo.function = sub;
|
||||
kernel_info_output->push_back(kinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
golden_file.close();
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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.
|
||||
*/
|
||||
#ifndef TESTS_FEATURETESTS_TRACER_GTESTS_APPS_TRACER_GTEST_H_
|
||||
#define TESTS_FEATURETESTS_TRACER_GTESTS_APPS_TRACER_GTEST_H_
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/* --------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @Synopsis Implementation of a Parser class for Profiler output
|
||||
* Parses pre-saved golden output for kernel info and saves them in a vector
|
||||
* Executes appliaction(passed as param:app_name) and saves parsed kernel info
|
||||
* in a vector.
|
||||
* Subsequent tests can use this to parse different applications
|
||||
*/
|
||||
/* --------------------------------------------------------------------------*/
|
||||
|
||||
class ApplicationParser : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp(const char* app_name, const char* trace_option) {
|
||||
SetApplicationEnv(app_name, trace_option);
|
||||
}
|
||||
virtual void TearDown() {}
|
||||
//!< This can be appended for other kernel info fields; eg: Agent-Name etc.
|
||||
struct KernelInfo {
|
||||
std::string record_id;
|
||||
std::string domain;
|
||||
std::string begin_time;
|
||||
std::string end_time;
|
||||
std::string corelation_id;
|
||||
std::string roctx_id;
|
||||
std::string function;
|
||||
};
|
||||
|
||||
//!< saves lines of profiler output
|
||||
std::vector<std::string> output_lines;
|
||||
|
||||
public:
|
||||
//!< Sets application enviornment by seting HSA_TOOLS_LIB.
|
||||
void SetApplicationEnv(const char* app_name, const char* trace_option);
|
||||
|
||||
//!< Parses kernel-info from a pre-saved golden out files
|
||||
// and saves them in a vector.
|
||||
void GetKernelInfoForGoldenOutput(const char* app_name, std::string filename,
|
||||
std::vector<KernelInfo>* kernel_info_output);
|
||||
|
||||
//!< Parses kernel-info after running profiler against curent application
|
||||
// and saves them in a vector.
|
||||
void GetKernelInfoForRunningApplication(std::vector<KernelInfo>* kernel_info_output);
|
||||
|
||||
private:
|
||||
//!< Runs a given appllication and saves profiler output.
|
||||
// These output lines can be letter passed for kernel informations
|
||||
// i.e: kernel_names
|
||||
void ProcessApplication(std::stringstream& ss);
|
||||
|
||||
//!< Parses kernel info fields from given input
|
||||
// i.e: kernel_names, kernel_duration
|
||||
void ParseKernelInfoFields(const std::string& s, std::vector<KernelInfo>* kernel_info_output);
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @Synopsis Implementation of a ProfilerTest
|
||||
* Subsequent tests can use this to parse different applications
|
||||
*/
|
||||
/* --------------------------------------------------------------------------*/
|
||||
|
||||
class ProfilerTest : public ApplicationParser {
|
||||
protected:
|
||||
virtual void SetUp(const char* app_name, const char* trace_option) {
|
||||
ApplicationParser::SetUp(app_name, trace_option);
|
||||
}
|
||||
};
|
||||
#endif // TESTS_FEATURETESTS_TRACER_GTESTS_APPS_TRACER_GTEST_H_
|
||||
@@ -0,0 +1,9 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// Entry Point for Gtests Infra
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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 "utils/test_utils.h"
|
||||
|
||||
namespace rocmtools {
|
||||
namespace tests {
|
||||
namespace utility {
|
||||
|
||||
// This function returns the running path of executable
|
||||
std::string GetRunningPath(std::string string_to_erase) {
|
||||
std::string path;
|
||||
char* real_path;
|
||||
Dl_info dl_info;
|
||||
|
||||
if (0 != dladdr(reinterpret_cast<void*>(main), &dl_info)) {
|
||||
std::string to_erase = string_to_erase;
|
||||
path = dl_info.dli_fname;
|
||||
real_path = realpath(path.c_str(), NULL);
|
||||
if (real_path == nullptr) {
|
||||
throw(std::string("Error! in extracting real path"));
|
||||
}
|
||||
path.clear(); // reset path
|
||||
path.append(real_path);
|
||||
|
||||
size_t pos = path.find(to_erase);
|
||||
if (pos != std::string::npos) path.erase(pos, to_erase.length());
|
||||
} else {
|
||||
throw(std::string("Error! in extracting real path"));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
} // namespace utility
|
||||
} // namespace tests
|
||||
} // namespace rocmtools
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016 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.
|
||||
*/
|
||||
#ifndef TESTS_FEATURETESTS_TRACER_UTILS_TEST_UTILS_H_
|
||||
#define TESTS_FEATURETESTS_TRACER_UTILS_TEST_UTILS_H_
|
||||
|
||||
#include <cxxabi.h> // for __cxa_demangle
|
||||
#include <dlfcn.h> // for dladdr
|
||||
#include <execinfo.h> // for backtrace
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
|
||||
namespace rocmtools {
|
||||
namespace tests {
|
||||
namespace utility {
|
||||
|
||||
// Get current running path
|
||||
std::string GetRunningPath(std::string string_to_erase);
|
||||
|
||||
} // namespace utility
|
||||
} // namespace tests
|
||||
} // namespace rocmtools
|
||||
|
||||
// used for dl_addr to locate the running
|
||||
// path for executable
|
||||
int main(int argc, char** argv);
|
||||
|
||||
using rocmtools::tests::utility::GetRunningPath;
|
||||
|
||||
#endif // TESTS_FEATURETESTS_TRACER_UTILS_TEST_UTILS_H_
|
||||
Reference in New Issue
Block a user