CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
285 lines
7.8 KiB
C++
285 lines
7.8 KiB
C++
// Copyright (c) Advanced Micro Devices, Inc.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include "common/env_vars.hpp"
|
|
#include "common/path.hpp"
|
|
#include "logger/debug.hpp"
|
|
|
|
#include <spdlog/fmt/ranges.h>
|
|
|
|
#include <algorithm>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <exception>
|
|
#include <iostream>
|
|
#include <limits>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <rocprofiler-sdk-rocattach/rocattach.h>
|
|
|
|
namespace
|
|
{
|
|
struct attach_options
|
|
{
|
|
int pid = -1;
|
|
std::string output_path = {};
|
|
std::vector<std::string> profile_format = {};
|
|
};
|
|
|
|
void
|
|
print_usage(const char* prog_name)
|
|
{
|
|
std::cout << "Usage: " << prog_name << " -p <pid> [OPTIONS]\n"
|
|
<< "\n"
|
|
<< "Attach to a running process for profiling.\n"
|
|
<< "\n"
|
|
<< "Options:\n"
|
|
<< " -p <pid> Process ID to attach to (required)\n"
|
|
<< " -o, --output PATH Output path for profiling results\n"
|
|
<< " -F, --format FORMAT[,FORMAT,...]\n"
|
|
<< " Output format(s): perfetto, rocpd\n"
|
|
<< " -h, --help Show this help message\n"
|
|
<< "\n"
|
|
<< "Environment variables:\n"
|
|
<< " ROCPROFSYS_OUTPUT_PATH Output directory for profiling data\n"
|
|
<< " ROCPROFSYS_TRACE Enable perfetto trace output\n"
|
|
<< " ROCPROFSYS_USE_ROCPD Enable rocpd database output\n"
|
|
<< " ROCPROF_ATTACH_TOOL_LIBRARY Path to the tool library\n"
|
|
<< "\n"
|
|
<< "Once attached, press ENTER to detach from the process.\n";
|
|
}
|
|
|
|
void
|
|
setup_tool_library_env()
|
|
{
|
|
const auto* attach_tool_library_env_name = "ROCPROF_ATTACH_TOOL_LIBRARY";
|
|
const auto* rocp_tool_libraries_env_name = "ROCP_TOOL_LIBRARIES";
|
|
const auto* output_use_current_time_env_name =
|
|
rocprofsys::env_vars::OUTPUT_USE_CURRENT_TIME;
|
|
const auto* reattach_add_session_id_env_name =
|
|
rocprofsys::env_vars::REATTACH_ADD_SESSION_ID;
|
|
|
|
// enable the use of the current time for the output path
|
|
setenv(output_use_current_time_env_name, "true", 1);
|
|
|
|
// enable the re-attach to add a session ID to the output path
|
|
setenv(reattach_add_session_id_env_name, "true", 1);
|
|
|
|
const auto* existing = std::getenv(attach_tool_library_env_name);
|
|
if(existing != nullptr)
|
|
{
|
|
setenv(rocp_tool_libraries_env_name, existing, 0);
|
|
LOG_INFO("Using tool library: {}", existing);
|
|
return;
|
|
}
|
|
|
|
const auto path =
|
|
rocprofsys::common::path::get_internal_libpath("librocprof-sys-dl.so");
|
|
if(!path.empty())
|
|
{
|
|
setenv(attach_tool_library_env_name, path.c_str(), 0);
|
|
setenv(rocp_tool_libraries_env_name, path.c_str(), 0);
|
|
LOG_INFO("Using tool library: {}", path);
|
|
}
|
|
}
|
|
|
|
void
|
|
setup_output_env(const std::string& output_path)
|
|
{
|
|
const auto* existing_output_path = getenv(rocprofsys::env_vars::OUTPUT_PATH);
|
|
if(output_path.empty() && existing_output_path != nullptr)
|
|
{
|
|
LOG_INFO("Output path: {}", existing_output_path);
|
|
return;
|
|
}
|
|
|
|
const auto* const pwd = getenv("PWD");
|
|
const auto output =
|
|
output_path.empty() ? fmt::format("{}/rocprof-sys-output", pwd) : output_path;
|
|
|
|
setenv(rocprofsys::env_vars::OUTPUT_PATH, output.c_str(), 1);
|
|
LOG_INFO("Output path: {}", output);
|
|
}
|
|
|
|
void
|
|
setup_output_format_env(const std::vector<std::string>& formats)
|
|
{
|
|
if(formats.empty()) return;
|
|
|
|
auto has_format = [&formats](const std::string& fmt) {
|
|
return std::find(formats.begin(), formats.end(), fmt) != formats.end();
|
|
};
|
|
|
|
// setenv("ROCPROFSYS_PROFILE", "false", 1);
|
|
|
|
if(has_format("perfetto") || has_format("rocpd"))
|
|
{
|
|
setenv(rocprofsys::env_vars::TRACE, has_format("perfetto") ? "true" : "false", 1);
|
|
setenv(rocprofsys::env_vars::USE_ROCPD, has_format("rocpd") ? "true" : "false",
|
|
1);
|
|
}
|
|
|
|
LOG_INFO("Output format: {}", fmt::join(formats, " "));
|
|
}
|
|
|
|
bool
|
|
is_option(const char* arg, const char* short_opt, const char* long_opt)
|
|
{
|
|
return std::strcmp(arg, short_opt) == 0 || std::strcmp(arg, long_opt) == 0;
|
|
}
|
|
|
|
const char*
|
|
consume_arg(int& i, int argc, char* argv[], const char* opt_name)
|
|
{
|
|
if(i + 1 >= argc)
|
|
{
|
|
LOG_ERROR("{} requires an argument.", opt_name);
|
|
std::exit(EXIT_FAILURE);
|
|
}
|
|
return argv[++i];
|
|
}
|
|
|
|
void
|
|
parse_pid(attach_options& opts, const char* arg)
|
|
{
|
|
try
|
|
{
|
|
opts.pid = std::stoi(arg);
|
|
if(opts.pid <= 0)
|
|
{
|
|
LOG_ERROR("PID must be a positive integer.");
|
|
std::exit(EXIT_FAILURE);
|
|
}
|
|
} catch(const std::exception&)
|
|
{
|
|
LOG_ERROR("Invalid PID '{}'.", arg);
|
|
std::exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
void
|
|
parse_formats(attach_options& opts, const char* arg)
|
|
{
|
|
std::string token;
|
|
std::stringstream ss(arg);
|
|
while(std::getline(ss, token, ','))
|
|
{
|
|
if(token == "perfetto" || token == "rocpd")
|
|
{
|
|
opts.profile_format.push_back(token);
|
|
}
|
|
else
|
|
{
|
|
LOG_ERROR("Invalid format '{}'. Valid options: perfetto, rocpd", token);
|
|
std::exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
|
|
attach_options
|
|
parse_args(int argc, char* argv[])
|
|
{
|
|
attach_options opts;
|
|
|
|
for(int i = 1; i < argc; ++i)
|
|
{
|
|
const char* arg = argv[i];
|
|
|
|
if(is_option(arg, "-h", "--help"))
|
|
{
|
|
print_usage(argv[0]);
|
|
std::exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
if(is_option(arg, "-p", "--pid"))
|
|
{
|
|
parse_pid(opts, consume_arg(i, argc, argv, "-p"));
|
|
continue;
|
|
}
|
|
|
|
if(is_option(arg, "-o", "--output"))
|
|
{
|
|
opts.output_path = consume_arg(i, argc, argv, "-o/--output");
|
|
continue;
|
|
}
|
|
|
|
if(is_option(arg, "-F", "--format"))
|
|
{
|
|
parse_formats(opts, consume_arg(i, argc, argv, "-F/--format"));
|
|
continue;
|
|
}
|
|
|
|
LOG_ERROR("Unknown option '{}'.", arg);
|
|
print_usage(argv[0]);
|
|
std::exit(EXIT_FAILURE);
|
|
}
|
|
|
|
return opts;
|
|
}
|
|
|
|
void
|
|
print_banner()
|
|
{
|
|
std::cout << R"(
|
|
____ ___ ____ __ __ ______ ______ _____ _____ __ __ ____ _ _____ _____ _ ____ _ _
|
|
| _ \ / _ \ / ___| \/ | / ___\ \ / / ___|_ _| ____| \/ / ___| / \|_ _|_ _|/ \ / ___| | | |
|
|
| |_) | | | | | | |\/| | \___ \\ V /\___ \ | | | _| | |\/| \___ \ / _ \ | | | | / _ \| | | |_| |
|
|
| _ <| |_| | |___| | | | ___) || | ___) || | | |___| | | |___) | / ___ \| | | |/ ___ \ |___| _ |
|
|
|_| \_\\___/ \____|_| |_| |____/ |_| |____/ |_| |_____|_| |_|____/ /_/ \_\_| |_/_/ \_\____|_| |_|
|
|
|
|
)" << "\n";
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int
|
|
main(int argc, char* argv[])
|
|
{
|
|
print_banner();
|
|
if(argc < 2)
|
|
{
|
|
print_usage(argv[0]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
auto opts = parse_args(argc, argv);
|
|
|
|
if(opts.pid < 0)
|
|
{
|
|
LOG_ERROR("-p <pid> is required.");
|
|
print_usage(argv[0]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
setup_tool_library_env();
|
|
setup_output_env(opts.output_path);
|
|
setup_output_format_env(opts.profile_format);
|
|
|
|
const auto pid = opts.pid;
|
|
|
|
LOG_INFO("Trying to attach to process {}", pid);
|
|
|
|
auto result = rocattach_attach(pid);
|
|
if(result != ROCATTACH_STATUS_SUCCESS)
|
|
{
|
|
LOG_ERROR("Failed to attach to process {}", pid);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
LOG_INFO("Attached to process {}. Press ENTER to detach.", pid);
|
|
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
|
|
|
result = rocattach_detach(pid);
|
|
if(result != ROCATTACH_STATUS_SUCCESS)
|
|
{
|
|
LOG_ERROR("Failed to detach from process {}", pid);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
LOG_INFO("Detached from process {}", pid);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|