diff --git a/projects/roctracer/CMakeLists.txt b/projects/roctracer/CMakeLists.txt index 72ee504bd4..682fda8947 100644 --- a/projects/roctracer/CMakeLists.txt +++ b/projects/roctracer/CMakeLists.txt @@ -94,6 +94,7 @@ install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/inc/ext/prof_protocol.h DESTINATION install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/inc/ext/hsa_rt_utils.hpp DESTINATION include/ext ) install ( FILES ${PROJECT_BINARY_DIR}/inc-link DESTINATION ../include RENAME ${ROCTRACER_NAME} ) install ( FILES ${PROJECT_BINARY_DIR}/so-link DESTINATION ../lib RENAME ${ROCTRACER_LIBRARY}.so ) +install ( FILES ${PROJECT_BINARY_DIR}/test/libtracer_tool.so DESTINATION tool ) ## Packaging directives set ( CPACK_GENERATOR "DEB" "RPM" "TGZ" ) diff --git a/projects/roctracer/inc/roctracer.h b/projects/roctracer/inc/roctracer.h index 61c7debaaf..b8d4f346e4 100644 --- a/projects/roctracer/inc/roctracer.h +++ b/projects/roctracer/inc/roctracer.h @@ -76,12 +76,19 @@ const char* roctracer_error_string(); // Activity domain type typedef activity_domain_t roctracer_domain_t; -// Return ID string by given domain and activity/API ID +// Return Op string by given domain and Op codes // NULL returned on the error and the library errno is set const char* roctracer_op_string( - const uint32_t& domain, // tracing domain - const uint32_t& op, // activity op ID - const uint32_t& kind); // activity kind + uint32_t domain, // tracing domain + uint32_t op, // activity op ID + uint32_t kind); // activity kind + +// Return Op code and kind by given string +roctracer_status_t roctracer_op_code( + uint32_t domain, // tracing domain + const char* str, // [in] op string + uint32_t* op, // [out] op code + uint32_t* kind = NULL); // [out] op kind code // Set properties roctracer_status_t roctracer_set_properties( diff --git a/projects/roctracer/script/hsaap.py b/projects/roctracer/script/hsaap.py index ed2e5df1f7..31a8076809 100755 --- a/projects/roctracer/script/hsaap.py +++ b/projects/roctracer/script/hsaap.py @@ -307,6 +307,7 @@ class API_DescrParser: self.add_section('API callback functions', '', self.gen_callbacks) self.add_section('API intercepting code', '', self.gen_intercept) self.add_section('API get_name function', ' ', self.gen_get_name) + self.add_section('API get_code function', ' ', self.gen_get_code) self.content += '\n};};\n' self.content += '#endif // PROF_API_IMPL\n' @@ -418,6 +419,17 @@ class API_DescrParser: self.content += ' return "unknown";\n' self.content += '}\n' + # generate API code function + def gen_get_code(self, n, name, call, struct): + if n == -1: + self.content += 'static uint32_t GetApiCode(const char* str) {\n' + return + if call != '-': + self.content += ' if (strcmp("' + call + '", str) == 0) return ' + self.api_id[call] + ';\n' + else: + self.content += ' return HSA_API_ID_NUMBER;\n' + self.content += '}\n' + # generate stream operator def gen_out_stream(self, n, name, call, struct): if n == -1: diff --git a/projects/roctracer/src/core/roctracer.cpp b/projects/roctracer/src/core/roctracer.cpp index 1f3f6c117e..a2747e34b4 100644 --- a/projects/roctracer/src/core/roctracer.cpp +++ b/projects/roctracer/src/core/roctracer.cpp @@ -386,13 +386,17 @@ PUBLIC_API const char* roctracer_error_string() { return strdup(roctracer::util::Logger::LastMessage().c_str()); } -// Return ID string by given domain and activity/API ID +// Return Op string by given domain and activity/API codes // NULL returned on the error and the library errno is set -PUBLIC_API const char* roctracer_op_string(const uint32_t& domain, const uint32_t& id, const uint32_t& kind) { +PUBLIC_API const char* roctracer_op_string( + uint32_t domain, + uint32_t op, + uint32_t kind) +{ API_METHOD_PREFIX switch (domain) { case ACTIVITY_DOMAIN_HSA_API: { - return roctracer::hsa_support::GetApiName(id); + return roctracer::hsa_support::GetApiName(op); break; } case ACTIVITY_DOMAIN_HCC_OPS: { @@ -400,7 +404,7 @@ PUBLIC_API const char* roctracer_op_string(const uint32_t& domain, const uint32_ break; } case ACTIVITY_DOMAIN_HIP_API: { - return hipApiName(id); + return hipApiName(op); break; } default: @@ -409,6 +413,26 @@ PUBLIC_API const char* roctracer_op_string(const uint32_t& domain, const uint32_ API_METHOD_CATCH(NULL) } +// Return Op code and kind by given string +PUBLIC_API roctracer_status_t roctracer_op_code( + uint32_t domain, + const char* str, + uint32_t* op, + uint32_t* kind) +{ + API_METHOD_PREFIX + switch (domain) { + case ACTIVITY_DOMAIN_HSA_API: { + *op = roctracer::hsa_support::GetApiCode(str); + if (kind != NULL) *kind = 0; + break; + } + default: + EXC_RAISING(ROCTRACER_STATUS_BAD_DOMAIN, "limited domain ID(" << domain << ")"); + } + API_METHOD_SUFFIX +} + static inline uint32_t get_op_num(const uint32_t& domain) { switch (domain) { case ACTIVITY_DOMAIN_HCC_OPS: return hc::HSA_OP_ID_NUMBER; diff --git a/projects/roctracer/test/CMakeLists.txt b/projects/roctracer/test/CMakeLists.txt index 6a0dfddbb4..ef74c04466 100644 --- a/projects/roctracer/test/CMakeLists.txt +++ b/projects/roctracer/test/CMakeLists.txt @@ -23,6 +23,9 @@ cmake_minimum_required ( VERSION 2.8.12 ) set ( CMAKE_VERBOSE_MAKEFILE TRUE CACHE BOOL "Verbose Output" FORCE ) +## Path to HSA test +set ( HSA_TEST_DIR "${TEST_DIR}/hsa/test" ) + ## test run script set ( RUN_SCRIPT "${TEST_DIR}/run.sh" ) @@ -35,20 +38,19 @@ add_custom_target( mytest ) ## Util sources -file( GLOB UTIL_SRC "${TEST_HSA}/util/*.cpp" ) +file( GLOB UTIL_SRC "${HSA_TEST_DIR}/util/*.cpp" ) ## Build test library set ( TEST_LIB "tracer_tool" ) set ( TEST_LIB_SRC ${TEST_DIR}/tool/tracer_tool.cpp ${UTIL_SRC} ) add_library ( ${TEST_LIB} SHARED ${TEST_LIB_SRC} ) -target_include_directories ( ${TEST_LIB} PRIVATE ${TEST_HSA} ${ROOT_DIR} ${HSA_RUNTIME_INC_PATH} ${HIP_INC_DIR} ${HCC_INC_DIR} ) +target_include_directories ( ${TEST_LIB} PRIVATE ${HSA_TEST_DIR} ${ROOT_DIR} ${HSA_RUNTIME_INC_PATH} ${HIP_INC_DIR} ${HCC_INC_DIR} ) target_link_libraries ( ${TEST_LIB} ${ROCTRACER_TARGET} ${HSA_RUNTIME_LIB} c stdc++ dl pthread rt ) -## HSA test -set ( TEST_HSA "${TEST_DIR}/hsa/test" ) +## Build HSA test execute_process ( COMMAND sh -xc "if [ ! -e ${TEST_DIR}/hsa ] ; then git clone https://github.com/ROCmSoftwarePlatform/hsa-class.git ${TEST_DIR}/hsa; fi" ) execute_process ( COMMAND sh -xc "if [ -e ${TEST_DIR}/hsa ] ; then cd ${TEST_DIR}/hsa && git checkout 3e7a87f; fi" ) -set ( TEST_DIR ${TEST_HSA} ) +set ( TEST_DIR ${HSA_TEST_DIR} ) add_subdirectory ( ${TEST_DIR} ${PROJECT_BINARY_DIR}/test/hsa ) ## copying run script diff --git a/projects/roctracer/test/run.sh b/projects/roctracer/test/run.sh index ef38515ac7..da939d2fd5 100755 --- a/projects/roctracer/test/run.sh +++ b/projects/roctracer/test/run.sh @@ -69,6 +69,10 @@ export ROCP_THRS=1 eval_test "tool HSA test" "LD_PRELOAD='$HSA_TOOLS_LIB' ./test/hsa/ctrl" +echo "" > input.xml +export ROCP_INPUT=input.xml +eval_test "tool HSA test input" "LD_PRELOAD='$HSA_TOOLS_LIB' ./test/hsa/ctrl" + #valgrind --leak-check=full $tbin #valgrind --tool=massif $tbin #ms_print massif.out. diff --git a/projects/roctracer/test/tool/tracer_tool.cpp b/projects/roctracer/test/tool/tracer_tool.cpp index 38d896c477..55c76f9b3f 100644 --- a/projects/roctracer/test/tool/tracer_tool.cpp +++ b/projects/roctracer/test/tool/tracer_tool.cpp @@ -29,6 +29,7 @@ THE SOFTWARE. #include #include #include +#include #define PUBLIC_API __attribute__((visibility("default"))) #define CONSTRUCTOR_API __attribute__((constructor)) @@ -51,6 +52,14 @@ thread_local timestamp_t hip_begin_timestamp = 0; bool trace_hsa = false; bool trace_hip = false; +// Error handler +void fatal(const std::string msg) { + fflush(stdout); + fprintf(stderr, "%s\n\n", msg.c_str()); + fflush(stderr); + abort(); +} + // HSA API callback function void hsa_api_callback( uint32_t domain, @@ -150,22 +159,119 @@ void activity_callback(const char* begin, const char* end, void* arg) { } } +// Input parser +std::string normalize_token(const std::string& token, bool not_empty, const std::string& label) { + const std::string space_chars_set = " \t"; + const size_t first_pos = token.find_first_not_of(space_chars_set); + size_t norm_len = 0; + std::string error_str = "none"; + if (first_pos != std::string::npos) { + const size_t last_pos = token.find_last_not_of(space_chars_set); + if (last_pos == std::string::npos) error_str = "token string error: \"" + token + "\""; + else { + const size_t end_pos = last_pos + 1; + if (end_pos <= first_pos) error_str = "token string error: \"" + token + "\""; + else norm_len = end_pos - first_pos; + } + } + if (((first_pos != std::string::npos) && (norm_len == 0)) || + ((first_pos == std::string::npos) && not_empty)) { + fatal("normalize_token error, " + label + ": '" + token + "'," + error_str); + } + return (norm_len != 0) ? token.substr(first_pos, norm_len) : std::string(""); +} + +int get_xml_array(const xml::Xml::level_t* node, const std::string& field, const std::string& delim, std::vector* vec, const char* label = NULL) { + int parse_iter = 0; + const auto& opts = node->opts; + auto it = opts.find(field); + if (it != opts.end()) { + const std::string array_string = it->second; + if (label != NULL) printf("%s%s = %s\n", label, field.c_str(), array_string.c_str()); + size_t pos1 = 0; + const size_t string_len = array_string.length(); + while (pos1 < string_len) { + const size_t pos2 = array_string.find(delim, pos1); + const bool found = (pos2 != std::string::npos); + const size_t token_len = (pos2 != std::string::npos) ? pos2 - pos1 : string_len - pos1; + const std::string token = array_string.substr(pos1, token_len); + const std::string norm_str = normalize_token(token, found, "get_xml_array"); + if (norm_str.length() != 0) vec->push_back(norm_str); + if (!found) break; + pos1 = pos2 + 1; + ++parse_iter; + } + } + return parse_iter; +} + // HSA-runtime tool on-load method extern "C" PUBLIC_API bool OnLoad(HsaApiTable* table, uint64_t runtime_version, uint64_t failed_tool_count, const char* const* failed_tool_names) { timer = new hsa_rt_utils::Timer(table->core_->hsa_system_get_info_fn); + // API traces switches const char* trace_domain = getenv("ROCTRACER_DOMAIN"); trace_hsa = (trace_domain == NULL) || (strncmp(trace_domain, "hsa", 3) == 0); trace_hip = (trace_domain == NULL) || (strncmp(trace_domain, "hip", 3) == 0); + // API trace vector + std::vector hsa_api_vec; + + // XML input + const char* xml_name = getenv("ROCP_INPUT"); + if (xml_name != NULL) { + printf("ROCTracer: input from \"%s\"\n", xml_name); + xml::Xml* xml = xml::Xml::Create(xml_name); + if (xml == NULL) { + fprintf(stderr, "ROCTracer: Input file not found '%s'\n", xml_name); + abort(); + } + + for (const auto* entry : xml->GetNodes("top.trace")) { + auto it = entry->opts.find("name"); + if (it == entry->opts.end()) fatal("ROCTracer: trace name is missing"); + const std::string& name = it->second; + + std::vector api_vec; + for (const auto* node : entry->nodes) { + if (node->tag != "parameters") fatal("ROCProfiler: trace node is not supported '" + name + ":" + node->tag + "'"); + get_xml_array(node, "api", ",", &api_vec); + break; + } + + if (name == "HSA") { + trace_hsa |= true; + hsa_api_vec = api_vec; + } + if (name == "HIP") { + trace_hip |= true; + } + } + } + // Enable HSA API callbacks if (trace_hsa) { - ROCTRACER_CALL(roctracer_enable_domain_callback(ACTIVITY_DOMAIN_HSA_API, hsa_api_callback, NULL)); + printf(" HSA-trace"); + if (hsa_api_vec.size() != 0) { + printf("("); + for (unsigned i = 0; i < hsa_api_vec.size(); ++i) { + uint32_t cid = HSA_API_ID_NUMBER; + const char* api = hsa_api_vec[i].c_str(); + ROCTRACER_CALL(roctracer_op_code(ACTIVITY_DOMAIN_HSA_API, api, &cid)); + ROCTRACER_CALL(roctracer_enable_op_callback(ACTIVITY_DOMAIN_HSA_API, cid, hsa_api_callback, NULL)); + printf(" %s", api); + } + printf(" )"); + } else { + ROCTRACER_CALL(roctracer_enable_domain_callback(ACTIVITY_DOMAIN_HSA_API, hsa_api_callback, NULL)); + } + printf("\n"); } // Enable HIP API callbacks/activity if (trace_hip) { + printf(" HIP-trace\n"); // Allocating tracing pool roctracer_properties_t properties{}; properties.buffer_size = 12; @@ -181,8 +287,12 @@ extern "C" PUBLIC_API bool OnLoad(HsaApiTable* table, uint64_t runtime_version, // HSA-runtime tool on-unload method extern "C" PUBLIC_API void OnUnload() { - if (trace_hsa) ROCTRACER_CALL(roctracer_disable_domain_callback(ACTIVITY_DOMAIN_HSA_API)); - if (trace_hip) ROCTRACER_CALL(roctracer_disable_domain_callback(ACTIVITY_DOMAIN_HIP_API)); - if (trace_hip) ROCTRACER_CALL(roctracer_disable_domain_callback(ACTIVITY_DOMAIN_HCC_OPS)); - ROCTRACER_CALL(roctracer_close_pool()); + if (trace_hsa) { + ROCTRACER_CALL(roctracer_disable_domain_callback(ACTIVITY_DOMAIN_HSA_API)); + } + if (trace_hip) { + ROCTRACER_CALL(roctracer_disable_domain_callback(ACTIVITY_DOMAIN_HIP_API)); + ROCTRACER_CALL(roctracer_disable_domain_callback(ACTIVITY_DOMAIN_HCC_OPS)); + ROCTRACER_CALL(roctracer_close_pool()); + } }