From 79076c4ad5f59c03bac52523f18fc0ce97cdde4e Mon Sep 17 00:00:00 2001 From: Mark Meserve Date: Wed, 22 Oct 2025 16:16:49 -0500 Subject: [PATCH] attach: Cleanup docs from initial commmit (#1302) - Remove unimplemented older API functions - Remove mentions of reattach API - Remove details on implementing a process attachment library - This will return later as a theory of operation --- .../docs/api-reference/process_attachment.rst | 1065 ++--------------- .../experimental/registration.h | 2 +- .../lib/rocprofiler-sdk/registration.hpp | 9 +- 3 files changed, 93 insertions(+), 983 deletions(-) diff --git a/projects/rocprofiler-sdk/source/docs/api-reference/process_attachment.rst b/projects/rocprofiler-sdk/source/docs/api-reference/process_attachment.rst index c6c6f21738..e3dbb4de0b 100644 --- a/projects/rocprofiler-sdk/source/docs/api-reference/process_attachment.rst +++ b/projects/rocprofiler-sdk/source/docs/api-reference/process_attachment.rst @@ -1,6 +1,6 @@ .. meta:: :description: Technical guide for implementing ROCprofiler-SDK process attachment - :keywords: ROCprofiler-SDK, process attachment, ptrace, dynamic profiling, tool development + :keywords: ROCprofiler-SDK, rocattach, attach, detach, process attachment, ptrace, dynamic profiling, tool development .. _process_attachment_implementation: @@ -11,19 +11,42 @@ Implementing Process Attachment Tools Overview ======== -This document provides the technical details needed to implement a process attachment tool similar to ``rocprofv3 --attach``. Process attachment allows profiling tools to dynamically attach to running GPU applications without requiring application restart. +This document provides the technical details needed to implement a process attachment tool similar to ``rocprofv3 --attach``. Process attachment allows profiling tools to dynamically attach to running GPU applications without requiring application restart. The implementation can use either the provided python or exported C functions. -The implementation uses specific exported C functions and involves low-level process manipulation using ptrace, environment variable injection, library loading, and coordination with the ROCprofiler-SDK registration system. - -Exported C Functions for Attachment +Python Functions =================================== -The attachment functionality provides the following exported C functions that tools can use: +The python file ``rocprofv3-attach.py`` defines a main function that can be used for attachment: -ROCprofiler-Attach Functions ------------------------------ +.. code-block:: python -These functions are exported from the ``rocprofiler-attach`` binary: + def main( + pid=os.environ.get("ROCPROF_ATTACH_PID", None), + attach_library=os.environ.get( + "ROCPROF_ATTACH_TOOL_LIBRARY", ROCPROF_ATTACH_TOOL_LIBRARY + ), + duration=os.environ.get("ROCPROF_ATTACH_DURATION", None), + ) + +**Function Details** + +The main function performs the entire attachment process, including attaching and detaching, and provides the ability to use custom tools. It also has simple control flow intended for direct calling from python. For more complex control, it is recommended to instead use the explicit attach and detach functions provided by the ``librocprofv3-attach.so`` binary. + +**Parameters** + +- **pid**: Required - PID of process to attach to + - Defaults to environment variable ROCPROF_ATTACH_PID +- **attach_library**: Optional - Colon delimited list of tool libraries to use + - Defaults to environment variable ROCPROF_ATTACH_TOOL_LIBRARY + - If unspecified, defaults to the absolute path of librocprofv3-attach.so +- **duration**: Optional - Length of time in milliseconds to profile for + - Defaults to environment variable ROCPROF_ATTACH_DURATION + - If unspecified, attachment will run until Enter is pressed or SIGINT (Ctrl+C) is received + +C Functions +=================================== + +The C library ``librocprofv3-attach.so`` defines an attach and detach function that can be used for attachment: .. code-block:: cpp @@ -37,69 +60,13 @@ These functions are exported from the ``rocprofiler-attach`` binary: **Function Details:** -- **``attach(uint32_t pid)``**: Main entry point for starting attachment to a process - - Takes the target process ID as parameter - - Initiates ptrace-based attachment sequence - - Spawns background thread for ptrace operations +- **attach(uint32_t pid)**: Main entry point for starting attachment to a process + - Takes the target process ID as parameter + - Initiates ptrace-based attachment sequence + - Custom tool libraries can be specified in a colon delimited list with the environment variable ROCPROF_ATTACH_TOOL_LIBRARY -- **``detach()``**: Entry point for detaching from the target process - - Cleans up attachment resources and terminates profiling - - Joins ptrace thread and releases resources - -ROCprofiler-Register Functions ------------------------------- - -These functions are exported from the ``librocprofiler-register.so`` library and are called via ptrace: - -.. code-block:: cpp - - extern "C" { - // Activate profiling in target process (called via ptrace) - rocprofiler_register_error_code_t - rocprofiler_register_attach(const char* environment_buffer, const char* tool_lib_path) - ROCPROFILER_REGISTER_PUBLIC_API; - - // Deactivate profiling in target process (called via ptrace) - rocprofiler_register_error_code_t - rocprofiler_register_detach() - ROCPROFILER_REGISTER_PUBLIC_API; - - // Reattach to previously attached process (experimental) - rocprofiler_register_error_code_t - rocprofiler_register_invoke_reattach() - ROCPROFILER_REGISTER_PUBLIC_API; - - // Client callback functions for reattachment support - void rocprofiler_call_client_reattach(void) - ROCPROFILER_REGISTER_PUBLIC_API; - void rocprofiler_call_client_detach(void) - ROCPROFILER_REGISTER_PUBLIC_API; - } - -**Function Details:** - -- **``rocprofiler_register_attach(const char* environment_buffer, const char* tool_lib_path)``**: - - Called via ptrace from the attachment system - - Receives serialized environment variables for profiling configuration - - Receives the tool library path to load (defaults to "librocprofiler-sdk-tool.so" if NULL) - - Loads the specified tool library and activates profiling services - - Returns ``rocprofiler_register_error_code_t`` status - -- **``rocprofiler_register_detach()``**: - - Called via ptrace to stop profiling in the target process - - Calls the tool's detach function and cleans up resources - - Returns ``rocprofiler_register_error_code_t`` status - -- **``rocprofiler_register_invoke_reattach()``**: (EXPERIMENTAL) - - Called to reattach profiling to a previously attached process - - Invokes client reattach callbacks without full re-initialization - - Used for resuming profiling after temporary detachment - - Returns ``rocprofiler_register_error_code_t`` status - -- **``rocprofiler_call_client_reattach()`` and ``rocprofiler_call_client_detach()``**: - - C wrapper functions for client tool reattachment callbacks - - Automatically resolved and called by the registration system - - Enable tools to handle dynamic attach/detach cycles +- **detach()**: Entry point for detaching from the target process + - Cleans up attachment resources and terminates profiling Function Call Sequence ====================== @@ -107,71 +74,58 @@ Function Call Sequence Initial Attachment Sequence --------------------------- -The initial attachment process follows this sequence: +The initial attachment process roughly follows this sequence: -.. code-block:: text +1. attach(pid) ← Your tool calls this +2. ptrace calls rocprofiler_register_attach(env_buffer) +3. tool_library::rocprofiler_configure(...) +4. tool_library::rocprofiler_configure_attach(...) +5. tool_library::tool_init(...) +6. tool_library::tool_attach(...) +7. [Profiling and data collection...] +8. detach() ← Your tool calls this +9. ptrace calls rocprofiler_register_detach() +10. tool_library::tool_detach(...) +11. [Program ends] +12. tool_library::tool_fini(...) - Tool Implementation - | - v - attach(pid) ← Your tool calls this - | - v - Ptrace attachment & environment setup - | - v - rocprofiler_register_attach(env_buffer) ← Called via ptrace in target - | - v - Profiling active in target process - | - v - [Profiling data collection...] - | - v - rocprofiler_register_detach() ← Called via ptrace in target - | - v - detach() ← Your tool calls this - | - v - Cleanup complete - -Reattachment Sequence (Experimental) ------------------------------------- +Reattachment Sequence +--------------------- For reattachment to a previously attached process: +1. attach(pid) ← Your tool calls this again +2. ptrace calls rocprofiler_register_attach(env_buffer) +3. tool_library::tool_attach(...) +4. [Continued profiling and data collection...] +5. detach() ← Your tool calls this +6. ptrace calls rocprofiler_register_detach() +7. tool_library::tool_detach(...) + + +Environment Variable Configuration +================================== + +The target process must have ``ROCP_TOOL_ATTACH=1`` set, or be using a version of ``rocprofiler-register`` configured with the CMake flag ``ROCPROFILER_REGISTER_BUILD_DEFAULT_ATTACHMENT=ON`` + +Required Variables +------------------ + .. code-block:: text - Tool Implementation - | - v - attach(pid) ← Your tool calls this again - | - v - Ptrace attachment & environment setup - | - v - rocprofiler_register_attach(env_buffer) ← Detects previous attachment - | - v - rocprofiler_register_invoke_reattach() ← Calls client reattach callbacks - | - v - Profiling resumed in target process - | - v - [Continued profiling data collection...] - | - v - rocprofiler_register_detach() ← Called via ptrace in target - | - v - detach() ← Your tool calls this - | - v - Cleanup complete + export ROCP_TOOL_ATTACH=1 + OR + cmake /path/to/rocprofiler-register -DROCPROFILER_REGISTER_BUILD_DEFAULT_ATTACHMENT=ON + +Tool Library Configuration +-------------------------- + +The attachment system can use any tool library. ``librocprofiler-sdk-tool.so`` is used when the environment variable is not set. + +.. code-block:: cpp + + // Attachment libraries to be used + setenv("ROCPROF_ATTACH_TOOL_LIBRARY", "example-tool-1.so:example-tool-2.so", 1); Using the Attachment Functions ============================== @@ -179,7 +133,7 @@ Using the Attachment Functions Here's how to use these functions in your own attachment tool: Basic Attachment Tool Implementation ------------------------------------ +------------------------------------ .. code-block:: cpp @@ -197,9 +151,9 @@ Basic Attachment Tool Implementation public: bool initialize() { // Load the rocprofiler-attach library/binary - attach_lib_handle = dlopen("librocprofiler-attach.so", RTLD_NOW); + attach_lib_handle = dlopen("librocprofv3-attach.so", RTLD_NOW); if (!attach_lib_handle) { - std::cerr << "Failed to load rocprofiler-attach: " << dlerror() << std::endl; + std::cerr << "Failed to load librocprofv3-attach: " << dlerror() << std::endl; return false; } @@ -255,7 +209,7 @@ Basic Attachment Tool Implementation }; Complete Tool Example --------------------- +--------------------- .. code-block:: cpp @@ -275,13 +229,10 @@ Complete Tool Example pid_t target_pid = std::stoi(argv[1]); uint32_t duration = (argc > 2) ? std::stoi(argv[2]) : 0; - // Set up profiling environment variables before attachment - setenv("ROCP_TOOL_ATTACH", "1", 1); - - // Note: The attachment system now uses the hardcoded default tool library path - // "librocprofiler-sdk-tool.so" and no longer uses environment variables for tool selection - - setenv("ROCPROF_HIP_API_TRACE", "1", 1); + // For this example, the tool library "librocprofiler-sdk-tool.so" is used by + // default because ROCPROF_ATTACH_TOOL_LIBRARY is not set. These environment + // variables are used to communicate profiling options to rocprofiler-sdk-tool. + setenv("ROCPROF_HIP_RUNTIME_API_TRACE", "1", 1); setenv("ROCPROF_KERNEL_TRACE", "1", 1); setenv("ROCPROF_MEMORY_COPY_TRACE", "1", 1); setenv("ROCPROF_OUTPUT_PATH", "./attachment-output", 1); @@ -302,837 +253,3 @@ Complete Tool Example std::cout << "Attachment completed successfully" << std::endl; return 0; } - -Experimental Reattachment API -============================= - -ROCprofiler-SDK now provides experimental support for reattachment, allowing tools to handle dynamic attach/detach cycles more efficiently. - -Tool Configuration for Reattachment ------------------------------------ - -Tools that support reattachment should implement the experimental configuration structure: - -.. code-block:: cpp - - #include - - // Experimental reattachment callbacks - void tool_reattach(void* tool_data) { - // Reinitialize contexts and resume profiling - // This is called when reattaching to a previously profiled process - } - - void tool_detach(void* tool_data) { - // Suspend profiling operations temporarily - // This is called during detachment, but contexts may be preserved - } - - extern "C" rocprofiler_tool_configure_result_experimental_t* - rocprofiler_configure_experimental(uint32_t version, - const char* runtime_version, - uint32_t prio, - rocprofiler_client_id_t* client_id) - { - static auto cfg = rocprofiler_tool_configure_result_experimental_t { - .size = sizeof(rocprofiler_tool_configure_result_experimental_t), - .initialize = &tool_init, - .finalize = &tool_fini, - .tool_data = nullptr, - .tool_reattach = &tool_reattach, // Experimental reattachment support - .tool_detach = &tool_detach // Experimental detachment support - }; - - return &cfg; - } - -Client Callback Functions -------------------------- - -The registration system automatically provides C wrapper functions: - -.. code-block:: cpp - - // These are automatically generated and called by rocprofiler-register - extern "C" void rocprofiler_call_client_reattach(void) { - // Calls the tool's reattach callback with stored tool_data - } - - extern "C" void rocprofiler_call_client_detach(void) { - // Calls the tool's detach callback with stored tool_data - } - -Reattachment Environment Variables ---------------------------------- - -When using reattachment, set this additional environment variable: - -.. code-block:: cpp - - // Indicates that the tool was loaded via attachment (not LD_PRELOAD) - setenv("ROCPROFILER_REGISTER_TOOL_ATTACHED", "1", 1); - -This helps the registration system differentiate between initial attachment and reattachment cycles. - -Environment Variable Configuration -================================= - -Before calling the attachment functions, set up environment variables that will be injected into the target process: - -Required Variables ------------------ - -.. code-block:: cpp - - // Essential for attachment functionality - setenv("ROCP_TOOL_ATTACH", "1", 1); - -Tool Library Configuration --------------------------- - -The attachment system now uses a hardcoded default tool library path: - -.. code-block:: cpp - - // The attachment system automatically uses "librocprofiler-sdk-tool.so" - // No environment variable configuration is needed or supported - -Tracing Options --------------- - -.. code-block:: cpp - - // Enable different types of tracing - setenv("ROCPROF_HIP_API_TRACE", "1", 1); // HIP API calls - setenv("ROCPROF_HSA_API_TRACE", "1", 1); // HSA API calls - setenv("ROCPROF_KERNEL_TRACE", "1", 1); // Kernel dispatches - setenv("ROCPROF_MEMORY_COPY_TRACE", "1", 1); // Memory operations - setenv("ROCPROF_MEMORY_ALLOCATION_TRACE", "1", 1); // Memory allocations - setenv("ROCPROF_SCRATCH_MEMORY_TRACE", "1", 1); // Scratch memory - setenv("ROCPROF_MARKER_TRACE", "1", 1); // ROCTx markers - -Output Configuration -------------------- - -.. code-block:: cpp - - // Control output location and format - setenv("ROCPROF_OUTPUT_PATH", "/path/to/output", 1); - setenv("ROCPROF_OUTPUT_FILE_NAME", "profile_name", 1); - setenv("ROCPROF_OUTPUT_FORMAT", "csv", 1); // or "json", "pftrace", etc. - -Build Configuration -================== - -To build a tool using the attachment functions: - -CMakeLists.txt -------------- - -.. code-block:: cmake - - cmake_minimum_required(VERSION 3.16) - project(my_rocprofiler_attach_tool) - - set(CMAKE_CXX_STANDARD 17) - - # Find ROCprofiler SDK (for headers and linking) - find_package(rocprofiler-sdk REQUIRED) - - add_executable(my_attach_tool - main.cpp - attachment_tool.cpp - ) - - # Link with required libraries - target_link_libraries(my_attach_tool - rocprofiler-sdk::rocprofiler-sdk - dl # for dlopen/dlsym operations - ) - - # Set capabilities for ptrace operations - add_custom_command(TARGET my_attach_tool POST_BUILD - COMMAND sudo setcap cap_sys_ptrace+ep $ - COMMENT "Setting ptrace capability" - ) - -Error Handling -============= - -When using the attachment functions, handle these common error conditions: - -.. code-block:: cpp - - class AttachmentErrorHandler { - public: - static bool validate_target_process(pid_t pid) { - // Check if process exists - if (kill(pid, 0) != 0) { - std::cerr << "Process " << pid << " not found or not accessible" << std::endl; - return false; - } - - // Check if it's a GPU application - std::string maps_path = "/proc/" + std::to_string(pid) + "/maps"; - std::ifstream maps(maps_path); - std::string line; - - bool has_gpu_libs = false; - while (std::getline(maps, line)) { - if (line.find("libamdhip64.so") != std::string::npos || - line.find("libhsa-runtime64.so") != std::string::npos) { - has_gpu_libs = true; - break; - } - } - - if (!has_gpu_libs) { - std::cerr << "Process " << pid << " does not appear to use GPU APIs" << std::endl; - return false; - } - - return true; - } - - static void handle_attachment_errors() { - // Check for common permission issues - if (geteuid() != 0) { - std::cerr << "Warning: Not running as root. Ensure CAP_SYS_PTRACE capability is set." << std::endl; - } - - // Check if rocprofiler libraries are available - if (getenv("LD_LIBRARY_PATH") == nullptr || - std::string(getenv("LD_LIBRARY_PATH")).find("/opt/rocm/lib") == std::string::npos) { - std::cerr << "Warning: /opt/rocm/lib may not be in LD_LIBRARY_PATH" << std::endl; - } - } - }; - -Architecture Overview -===================== - -Process attachment consists of several cooperating components: - -.. code-block:: text - - Attachment Tool (your implementation) - | - v - 1. Process Discovery & Validation - | - v - 2. Ptrace Attachment & Control - | - v - 3. Environment Variable Injection - | - v - 4. Library Loading (rocprofiler-register) - | - v - 5. Profiling Service Activation - | - v - 6. Data Collection & Management - | - v - 7. Detachment & Cleanup - -Theoretical Implementation Details -================================= - -Core Implementation Components -============================= - -1. Process Discovery and Validation ------------------------------------ - -**Target Process Requirements:** - -.. code-block:: cpp - - #include - #include - #include - - bool validate_target_process(pid_t pid) { - // Check if process exists and is accessible - if (kill(pid, 0) != 0) { - return false; // Process doesn't exist or no permission - } - - // Verify it's a GPU application by checking loaded libraries - std::string maps_path = "/proc/" + std::to_string(pid) + "/maps"; - std::ifstream maps(maps_path); - std::string line; - - bool has_hip = false, has_hsa = false; - while (std::getline(maps, line)) { - if (line.find("libamdhip64.so") != std::string::npos) has_hip = true; - if (line.find("libhsa-runtime64.so") != std::string::npos) has_hsa = true; - } - - return has_hip || has_hsa; // Must use HIP or HSA - } - -2. Ptrace-Based Process Control ------------------------------- - -**Core Ptrace Operations:** - -.. code-block:: cpp - - #include - #include - #include - - class ProcessAttachment { - private: - pid_t target_pid; - bool attached = false; - - public: - bool attach(pid_t pid) { - target_pid = pid; - - // Attach to the target process - if (ptrace(PTRACE_ATTACH, target_pid, nullptr, nullptr) == -1) { - perror("ptrace PTRACE_ATTACH failed"); - return false; - } - - // Wait for the process to stop - int status; - if (waitpid(target_pid, &status, 0) == -1) { - perror("waitpid failed"); - detach(); - return false; - } - - if (!WIFSTOPPED(status)) { - fprintf(stderr, "Process did not stop after attach\n"); - detach(); - return false; - } - - attached = true; - return true; - } - - bool detach() { - if (!attached) return true; - - // Detach and allow process to continue - if (ptrace(PTRACE_DETACH, target_pid, nullptr, nullptr) == -1) { - perror("ptrace PTRACE_DETACH failed"); - return false; - } - - attached = false; - return true; - } - }; - -3. Environment Variable Injection ---------------------------------- - -**Environment Variable Management:** - -.. code-block:: cpp - - #include - #include - - class EnvironmentInjector { - public: - struct EnvironmentVar { - std::string name; - std::string value; - }; - - // Prepare environment variables for profiling - std::vector prepare_profiling_env( - const std::vector& trace_options, - const std::string& output_path, - const std::string& output_file) { - - std::vector env_vars; - - // Essential attachment variable - env_vars.push_back({"ROCP_TOOL_ATTACH", "1"}); - - // Configure tracing based on options - for (const auto& option : trace_options) { - if (option == "hip-trace") { - env_vars.push_back({"ROCPROF_HIP_API_TRACE", "1"}); - } - if (option == "kernel-trace") { - env_vars.push_back({"ROCPROF_KERNEL_TRACE", "1"}); - } - if (option == "hsa-trace") { - env_vars.push_back({"ROCPROF_HSA_API_TRACE", "1"}); - } - if (option == "memory-copy-trace") { - env_vars.push_back({"ROCPROF_MEMORY_COPY_TRACE", "1"}); - } - } - - // Output configuration - env_vars.push_back({"ROCPROF_OUTPUT_PATH", output_path}); - env_vars.push_back({"ROCPROF_OUTPUT_FILE_NAME", output_file}); - - return env_vars; - } - - // Serialize environment for injection - std::vector serialize_environment(const std::vector& vars) { - std::vector buffer(4); // Start with count - uint32_t count = vars.size(); - - // Store count in first 4 bytes - buffer[0] = count & 0xFF; - buffer[1] = (count >> 8) & 0xFF; - buffer[2] = (count >> 16) & 0xFF; - buffer[3] = (count >> 24) & 0xFF; - - // Add each variable as null-terminated name and value - for (const auto& var : vars) { - // Add variable name - for (char c : var.name) { - buffer.push_back(c); - } - buffer.push_back(0); // Null terminate name - - // Add variable value - for (char c : var.value) { - buffer.push_back(c); - } - buffer.push_back(0); // Null terminate value - } - - return buffer; - } - }; - -4. Memory Manipulation and Library Loading ------------------------------------------- - -**Remote Memory Operations:** - -.. code-block:: cpp - - #include - - class RemoteMemoryManager { - private: - pid_t target_pid; - - public: - RemoteMemoryManager(pid_t pid) : target_pid(pid) {} - - // Allocate memory in remote process - void* remote_mmap(size_t length, int prot, int flags) { - // Find a suitable location for injection - struct user_regs_struct regs; - if (ptrace(PTRACE_GETREGS, target_pid, nullptr, ®s) == -1) { - return nullptr; - } - - // Save original registers - struct user_regs_struct orig_regs = regs; - - // Set up mmap syscall - regs.rax = 9; // __NR_mmap - regs.rdi = 0; // addr (let kernel choose) - regs.rsi = length; - regs.rdx = prot; - regs.r10 = flags; - regs.r8 = -1; // fd - regs.r9 = 0; // offset - - if (ptrace(PTRACE_SETREGS, target_pid, nullptr, ®s) == -1) { - return nullptr; - } - - // Execute syscall - if (ptrace(PTRACE_SYSCALL, target_pid, nullptr, nullptr) == -1) { - return nullptr; - } - - // Wait for syscall completion - int status; - waitpid(target_pid, &status, 0); - - // Get result - if (ptrace(PTRACE_GETREGS, target_pid, nullptr, ®s) == -1) { - return nullptr; - } - - void* result = (void*)regs.rax; - - // Restore original registers - ptrace(PTRACE_SETREGS, target_pid, nullptr, &orig_regs); - - return (result == (void*)-1) ? nullptr : result; - } - - // Write data to remote process memory - bool write_memory(void* addr, const void* data, size_t size) { - const uint8_t* bytes = static_cast(data); - size_t written = 0; - - while (written < size) { - long word = 0; - size_t to_copy = std::min(sizeof(long), size - written); - - // For partial words, read existing content first - if (to_copy < sizeof(long)) { - errno = 0; - word = ptrace(PTRACE_PEEKDATA, target_pid, - (uint8_t*)addr + written, nullptr); - if (errno != 0) return false; - } - - // Copy new data into word - memcpy(&word, bytes + written, to_copy); - - // Write word to remote process - if (ptrace(PTRACE_POKEDATA, target_pid, - (uint8_t*)addr + written, word) == -1) { - return false; - } - - written += to_copy; - } - - return true; - } - }; - -5. Library Injection and Symbol Resolution ------------------------------------------- - -**Dynamic Library Loading:** - -.. code-block:: cpp - - #include - #include - - class LibraryInjector { - private: - pid_t target_pid; - RemoteMemoryManager memory_manager; - - public: - LibraryInjector(pid_t pid) : target_pid(pid), memory_manager(pid) {} - - // Inject rocprofiler-register library - bool inject_register_library() { - const char* lib_path = "/opt/rocm/lib/librocprofiler-register.so"; - - // Find dlopen in target process - void* dlopen_addr = find_function_address("dlopen"); - if (!dlopen_addr) { - fprintf(stderr, "Could not find dlopen in target process\n"); - return false; - } - - // Allocate memory for library path - void* path_addr = memory_manager.remote_mmap( - strlen(lib_path) + 1, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS); - - if (!path_addr) return false; - - // Write library path to remote memory - if (!memory_manager.write_memory(path_addr, lib_path, strlen(lib_path) + 1)) { - return false; - } - - // Call dlopen in target process - return call_remote_function(dlopen_addr, - {(uint64_t)path_addr, RTLD_NOW | RTLD_GLOBAL}); - } - - void* find_function_address(const char* function_name) { - // Parse /proc/PID/maps to find loaded libraries - std::string maps_path = "/proc/" + std::to_string(target_pid) + "/maps"; - std::ifstream maps(maps_path); - std::string line; - - while (std::getline(maps, line)) { - if (line.find("libc.so") != std::string::npos) { - // Extract base address of libc - size_t dash = line.find('-'); - std::string base_addr_str = line.substr(0, dash); - void* base_addr = (void*)std::stoull(base_addr_str, nullptr, 16); - - // Open libc and find function offset - void* handle = dlopen("libc.so.6", RTLD_LAZY); - if (handle) { - void* func_addr = dlsym(handle, function_name); - if (func_addr) { - // Calculate actual address in target process - return (uint8_t*)base_addr + ((uint8_t*)func_addr - (uint8_t*)dlsym(RTLD_DEFAULT, "main")); - } - dlclose(handle); - } - } - } - return nullptr; - } - }; - -6. ROCprofiler-Register Communication Protocol ----------------------------------------------- - -**Attachment Protocol Implementation:** - -.. code-block:: cpp - - extern "C" { - // Function signatures from rocprofiler-register - typedef void (*attach_func_t)(uint32_t pid); - typedef void (*detach_func_t)(); - } - - class ROCprofilerAttachment { - private: - pid_t target_pid; - void* register_handle = nullptr; - attach_func_t attach_func = nullptr; - detach_func_t detach_func = nullptr; - - public: - bool initialize() { - // Load rocprofiler-register library - register_handle = dlopen("/opt/rocm/lib/librocprofiler-register.so", RTLD_NOW); - if (!register_handle) { - fprintf(stderr, "Failed to load rocprofiler-register: %s\n", dlerror()); - return false; - } - - // Get attachment functions - attach_func = (attach_func_t)dlsym(register_handle, "attach"); - detach_func = (detach_func_t)dlsym(register_handle, "detach"); - - if (!attach_func || !detach_func) { - fprintf(stderr, "Failed to find attachment functions\n"); - return false; - } - - return true; - } - - bool attach_to_process(pid_t pid, const std::vector& env_buffer) { - target_pid = pid; - - // Set up environment for rocprofiler-register - // This involves injecting the environment buffer into the target process - - // Call the attach function - attach_func(pid); - - return true; - } - - void detach_from_process() { - if (detach_func) { - detach_func(); - } - } - }; - -Complete Attachment Tool Implementation -====================================== - -**Main Attachment Tool Structure:** - -.. code-block:: cpp - - #include - #include - #include - #include - #include - - class ROCprofilerAttachTool { - private: - ProcessAttachment process_control; - EnvironmentInjector env_injector; - LibraryInjector lib_injector; - ROCprofilerAttachment rocprof_attachment; - - public: - struct AttachmentConfig { - pid_t target_pid; - std::vector trace_options; - std::string output_path = "./rocprof-attachment-output"; - std::string output_filename = "attached_profile"; - uint32_t duration_msec = 0; // 0 = until process ends - }; - - bool attach_and_profile(const AttachmentConfig& config) { - // 1. Validate target process - if (!validate_target_process(config.target_pid)) { - std::cerr << "Invalid or inaccessible target process: " << config.target_pid << std::endl; - return false; - } - - // 2. Initialize rocprofiler attachment system - if (!rocprof_attachment.initialize()) { - std::cerr << "Failed to initialize rocprofiler attachment system" << std::endl; - return false; - } - - // 3. Attach to target process - if (!process_control.attach(config.target_pid)) { - std::cerr << "Failed to attach to process " << config.target_pid << std::endl; - return false; - } - - // 4. Prepare environment variables - auto env_vars = env_injector.prepare_profiling_env( - config.trace_options, - config.output_path, - config.output_filename); - auto env_buffer = env_injector.serialize_environment(env_vars); - - // 5. Inject rocprofiler-register library - LibraryInjector injector(config.target_pid); - if (!injector.inject_register_library()) { - std::cerr << "Failed to inject rocprofiler-register library" << std::endl; - process_control.detach(); - return false; - } - - // 6. Activate profiling - if (!rocprof_attachment.attach_to_process(config.target_pid, env_buffer)) { - std::cerr << "Failed to activate profiling" << std::endl; - process_control.detach(); - return false; - } - - // 7. Allow process to continue with profiling active - if (!process_control.detach()) { - std::cerr << "Warning: Failed to detach cleanly" << std::endl; - } - - // 8. Wait for specified duration or until process ends - if (config.duration_msec > 0) { - std::cout << "Profiling for " << config.duration_msec << " milliseconds..." << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(config.duration_msec)); - - // Re-attach to stop profiling - rocprof_attachment.detach_from_process(); - } else { - std::cout << "Profiling until process ends..." << std::endl; - // Monitor process and wait for it to end - while (kill(config.target_pid, 0) == 0) { - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - } - - std::cout << "Profiling completed. Output saved to: " - << config.output_path << "/" << config.output_filename << std::endl; - return true; - } - }; - - // Example usage - int main(int argc, char* argv[]) { - if (argc < 2) { - std::cerr << "Usage: " << argv[0] << " [options]" << std::endl; - return 1; - } - - ROCprofilerAttachTool::AttachmentConfig config; - config.target_pid = std::stoi(argv[1]); - config.trace_options = {"hip-trace", "kernel-trace", "memory-copy-trace"}; - config.duration_msec = 5000; // 5 seconds - - ROCprofilerAttachTool tool; - if (!tool.attach_and_profile(config)) { - std::cerr << "Attachment and profiling failed" << std::endl; - return 1; - } - - return 0; - } - -Required System Permissions and Setup -===================================== - -**Permission Requirements:** - -.. code-block:: bash - - # Your attachment tool will need: - - # 1. Ptrace permissions (may require root or capabilities) - sudo setcap cap_sys_ptrace+ep your_attachment_tool - - # 2. Access to /proc filesystem - # Usually available by default - - # 3. Ability to load shared libraries - # Ensure ROCm libraries are in LD_LIBRARY_PATH - export LD_LIBRARY_PATH=/opt/rocm/lib:$LD_LIBRARY_PATH - -**Build Requirements:** - -.. code-block:: cmake - - # CMakeLists.txt for your attachment tool - cmake_minimum_required(VERSION 3.16) - project(rocprofiler_attach_tool) - - set(CMAKE_CXX_STANDARD 17) - - find_package(rocprofiler-sdk REQUIRED) - - add_executable(rocprofiler_attach_tool - main.cpp - process_attachment.cpp - environment_injection.cpp - library_injection.cpp - ) - - target_link_libraries(rocprofiler_attach_tool - rocprofiler-sdk::rocprofiler-sdk - dl # for dlopen/dlsym - ) - -Error Handling and Debugging -============================ - -**Common Issues and Solutions:** - -1. **Ptrace Permissions**: Use ``strace`` to debug ptrace failures -2. **Library Loading**: Check ``/proc/PID/maps`` to verify library injection -3. **Environment Variables**: Validate environment buffer format -4. **Process State**: Monitor target process status during attachment - -**Debugging Techniques:** - -.. code-block:: cpp - - // Enable debug logging - setenv("ROCPROF_LOGGING_LEVEL", "trace", 1); - - // Monitor attachment progress - bool debug_attachment(pid_t pid) { - std::cout << "Target process memory maps:" << std::endl; - std::string cmd = "cat /proc/" + std::to_string(pid) + "/maps"; - system(cmd.c_str()); - - std::cout << "Target process environment:" << std::endl; - cmd = "cat /proc/" + std::to_string(pid) + "/environ | tr '\\0' '\\n'"; - system(cmd.c_str()); - - return true; - } - -This implementation guide provides the foundation needed to build a complete process attachment tool for ROCprofiler-SDK. The actual rocprofv3 implementation uses similar techniques with additional optimizations and error handling. diff --git a/projects/rocprofiler-sdk/source/include/rocprofiler-sdk/experimental/registration.h b/projects/rocprofiler-sdk/source/include/rocprofiler-sdk/experimental/registration.h index 3e8b4ab1bd..622a87f234 100644 --- a/projects/rocprofiler-sdk/source/include/rocprofiler-sdk/experimental/registration.h +++ b/projects/rocprofiler-sdk/source/include/rocprofiler-sdk/experimental/registration.h @@ -67,7 +67,7 @@ typedef void (*rocprofiler_tool_detach_t)(void* tool_data); * attach/detach, and data. * * This is an experimental extension of ::rocprofiler_tool_configure_result_t that adds support for - * runtime attachment and detachment of tools. The `tool_reattach` and `tool_detach` function + * runtime attachment and detachment of tools. The `tool_attach` and `tool_detach` function * pointers allow tools to handle dynamic attachment scenarios where they may need to suspend and * resume profiling operations. * diff --git a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/registration.hpp b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/registration.hpp index ecfb5450c5..0b0eb71bfd 100644 --- a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/registration.hpp +++ b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/registration.hpp @@ -39,13 +39,6 @@ rocprofiler_set_api_table(const char* name, uint64_t lib_instance, void** tables, uint64_t num_tables) ROCPROFILER_PUBLIC_API; - -// functions for dynamic attach/detach control -void -rocprofiler_call_client_reattach() ROCPROFILER_PUBLIC_API; - -void -rocprofiler_call_client_detach() ROCPROFILER_PUBLIC_API; } namespace rocprofiler @@ -83,7 +76,7 @@ set_fini_status(int); bool supports_attachment(); -// call tool_reattach function for all registered clients +// call tool_attach function for all registered clients rocprofiler_status_t attach();