Misc updates for distribution (#233)

* Adding tools support

* cmake formatting (cmake-format) (#227)

Co-authored-by: SrirakshaNag <SrirakshaNag@users.noreply.github.com>

* Checking to do rebase

* Adding rocprofv2 script

* cmake formatting (cmake-format) (#229)

Co-authored-by: bgopesh <bgopesh@users.noreply.github.com>

* Fixing build for the tool

* Removing the requirement for rocm_version

* Update rocprofiler_utilities.cmake

* C++ filesystem fixes

- added source/lib/common/filesystem.hpp
  - support older compilers which have <experimental/filesystem> and do not have <filesystem>
- added samples/common/filesystem.hpp
  - samples now depend on "common" library which provides the correct filesystem header
- renamed rocprofiler-stdcxxfs interface target to rocprofiler-cxx-filesystem
  - support old LLVM in addition to GNU
- fix bin/rocprof/rocprof.cpp
  - was using VLA

* Fix rocprofiler-drm include directories

- OpenSUSE only has include/libdrm/drm.h (no include/drm/drm.h)

* Tools fixes

* Fix for the tools

* Fix rocprofv2 script

* Fixing Filesystem Issues

* source formatting (clang-format v11) (#234)

Co-authored-by: ammarwa <ammarwa@users.noreply.github.com>

* Vlaindic/pc sampling api update (#235)

* pcs: updating PC sampling API

* source formatting (clang-format v11) (#232)

Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

---------

Co-authored-by: vlaindic <vladimir.indic@amd.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* Vlaindic/pc sampling api update for ammar branch (#244)

*Updating the documentation inside pc_sampling.h

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>

* pcs: use @p in front of params

* pcs: documenting struct fields updated

* Fixing PC Sampling Documentation issues

* Fixing PC Sampling Documentation

* Relocated tools directory to source/lib/rocprofiler-tool

* Fixes/updates to rocprofiler-tool

- updated CMake
- Fixed miscellaneous issues in the code (VLAs, etc.)
- Updated rocprofv2 to reflect some minor env variables changes in rocprofiler-tool
- Fixed clang-tidy warnings

* Update lib/rocprofiler-tool/CMakeLists.txt

- link to atomic library

* Add $ORIGIN/.. RUNPATH to rocprofiler-tool

* Adding readme file for tools

* Renaming the tools readme file

* Update ReadMe.md

* Update ReadMe.md

* Documentation updates

- overview and explanation of design and concepts

* Fix lib/rocprofiler-tool/README.md

- delete ReadMe.md

* Hacks for build

* Update Filesystem

* cmake formatting (cmake-format) (#248)

Co-authored-by: ammarwa <ammarwa@users.noreply.github.com>

* source formatting (clang-format v11) (#249)

Co-authored-by: ammarwa <ammarwa@users.noreply.github.com>

* source formatting (clang-format v11) (#250)

Co-authored-by: ammarwa <ammarwa@users.noreply.github.com>

* Addressing review comments on the tool readme file

* Revert "Hacks for build"

This reverts commit d6688cb3d1226c46fc97e37ced889a5b0d180940.

* Fixes for GCC 7.5 compiler in OpenSUSE 15.4

* Update lib/rocprofiler-tool/CMakeLists.txt

- link to AQL profile library

* Fix lib/rocprofiler-tool/README.md

- fix markdown

* Fix lib/rocprofiler-tool

- fix usage of hsa_ven_amd_loader_query_host_address

* Fix unused variable warnings

- byproduct of variables only used in assert statements

* Update docs

- update about.md
  - more "Important Changes" section here
- update tool_library_overview.md
  - extend "Tool Library Design" section
  - write "Tool Initialization" section
  - write "Tool Finalization" section

* Add ghc::filesystem submodule

* Implement usage of ghc::filesystem

* Add ROCPROFILER_BUILD_GHC_FS option

- option to use external/filesystem (ghc)

* Update samples/counter-collection

- compile flags
- common library
- fixes for warnings

* Update tests/kernel-tracing/CMakeLists.txt

- change install location of kernel-tracing-test-tool and install rpath

* Update samples/common/CMakeLists.txt

- compile features requiring C++17

* Update lib/rocprofiler-tool/tool.cpp

- remove include <filesystem>
- comment out unused variable
- remove unused functions
- move some functions into anonymous namespace

---------

Co-authored-by: Sriraksha Nagaraj <Sriraksha.Nagaraj@amd.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: SrirakshaNag <SrirakshaNag@users.noreply.github.com>
Co-authored-by: gobhardw <gopesh.bhardwaj@amd.com>
Co-authored-by: bgopesh <bgopesh@users.noreply.github.com>
Co-authored-by: Jonathan R. Madsen <jonathanrmadsen@gmail.com>
Co-authored-by: ammarwa <ammarwa@users.noreply.github.com>
Co-authored-by: vlaindic <vladimir.indic@amd.com>
Co-authored-by: vlaindic <vlaindic@users.noreply.github.com>
Co-authored-by: Vladimir Indic <139573562+vlaindic@users.noreply.github.com>
Co-authored-by: Benjamin Welton <bewelton@amd.com>
Co-authored-by: Jonathan R. Madsen <jrmadsen@users.noreply.github.com>
Tá an tiomantas seo le fáil i:
77 comhad athraithe
+2501 -943

Níor tháinig aon chomhaid le do chuardach

-34
Féach ar an gComhad
@@ -1,34 +0,0 @@
#
#
#
cmake_minimum_required(VERSION 3.21.0 FATAL_ERROR)
project(rocprofiler-samples-pc-sampling LANGUAGES C CXX)
if(NOT TARGET rocprofiler::rocprofiler)
find_package(rocprofiler REQUIRED)
endif()
add_executable(pc_sampling_single-user-host-trap)
target_sources(pc_sampling_single-user-host-trap PRIVATE common.h
single-user-host-trap.cpp)
target_link_libraries(
pc_sampling_single-user-host-trap
PRIVATE rocprofiler::rocprofiler
$<TARGET_NAME_IF_EXISTS:rocprofiler::samples-build-flags>)
add_executable(pc_sampling_single-user-host-trap-retry)
target_sources(pc_sampling_single-user-host-trap-retry
PRIVATE common.h single-user-host-trap-retries-service-instantiation.cpp)
target_link_libraries(
pc_sampling_single-user-host-trap-retry
PRIVATE rocprofiler::rocprofiler
$<TARGET_NAME_IF_EXISTS:rocprofiler::samples-build-flags>)
add_executable(pc_sampling_single-user-multiple-agents)
target_sources(pc_sampling_single-user-multiple-agents
PRIVATE common.h single-user-multiple-agents.cpp)
target_link_libraries(
pc_sampling_single-user-multiple-agents
PRIVATE rocprofiler::rocprofiler
$<TARGET_NAME_IF_EXISTS:rocprofiler::samples-build-flags>)
-147
Féach ar an gComhad
@@ -1,147 +0,0 @@
// MIT License
//
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <rocprofiler/rocprofiler.h>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <optional>
#include <string>
#include <string_view>
constexpr size_t BUFFER_SIZE_BYTES = 4096;
constexpr size_t WATERMARK = (BUFFER_SIZE_BYTES / 2);
const std::string_view MI200_NAME = "gfx90a";
#define ROCPROFILER_CALL(result, msg) \
{ \
rocprofiler_status_t CHECKSTATUS = result; \
if(CHECKSTATUS != ROCPROFILER_STATUS_SUCCESS) \
{ \
puts(#result " failed"); \
} \
}
// We might want to test the calls that fails
// e.g. calling `rocprofiler_configure_pc_sampling_service `
// after previous initialization.
#define ROCPROFILER_CALL_FAILS(result, msg) \
{ \
rocprofiler_status_t CHECKSTATUS = result; \
if(CHECKSTATUS == ROCPROFILER_STATUS_SUCCESS) \
{ \
puts(#result " succeeded"); \
} \
}
static rocprofiler_status_t
find_first_gpu_agent_impl(const rocprofiler_agent_t** agents, size_t num_agents, void* data)
{
// data is required
if(!data) return ROCPROFILER_STATUS_ERROR;
auto* _out_agent = static_cast<rocprofiler_agent_t*>(data);
// find the first GPU agent
for(size_t i = 0; i < num_agents; i++)
{
if(agents[i]->type == ROCPROFILER_AGENT_TYPE_GPU)
{
*_out_agent = *agents[i];
printf("[%s] %s :: id=%u, type=%i, num pc sample configs=%zu\n",
__FUNCTION__,
_out_agent->name,
_out_agent->node_id,
_out_agent->type,
_out_agent->num_pc_sampling_configs);
return ROCPROFILER_STATUS_SUCCESS;
}
else
{
printf("[%s] %s :: id=%u, type=%i, num pc sample configs=%zu\n",
__FUNCTION__,
agents[i]->name,
agents[i]->node_id,
agents[i]->type,
agents[i]->num_pc_sampling_configs);
}
}
return ROCPROFILER_STATUS_ERROR;
}
static std::optional<rocprofiler_agent_t>
find_first_gpu_agent()
{
// This function returns the first gpu agent it encounters.
// TODO: write the better function querying information about the agent,
// and return if the agent is MI200.
rocprofiler_agent_t gpu_agent;
auto status = rocprofiler_query_available_agents(
&find_first_gpu_agent_impl, sizeof(rocprofiler_agent_t), static_cast<void*>(&gpu_agent));
if(status != ROCPROFILER_STATUS_SUCCESS) return std::nullopt;
return gpu_agent;
}
static void
rocprofiler_pc_sampling_callback(rocprofiler_context_id_t /*context_id*/,
rocprofiler_buffer_id_t /*buffer_id*/,
rocprofiler_record_header_t** headers,
size_t num_headers,
void* /*data*/,
uint64_t drop_count)
{
// Vladimir: I am not sure if this is the right way of iterating over PC sampling records.
printf(
"The number of delivered samples is: %zu, while the number of dropped samples is: %lu.\n",
num_headers,
drop_count);
for(size_t i = 0; i < num_headers; i++)
{
auto* cur_header = headers[i];
if(cur_header->category == ROCPROFILER_BUFFER_CATEGORY_PC_SAMPLING)
{
auto* pc_sample = static_cast<rocprofiler_pc_sampling_record_t*>(cur_header->payload);
printf("--- pc: %lx, dispatch_id: %lx, timestamp: %lu, hardware_id: %lu\n",
pc_sample->pc,
pc_sample->dispatch_id,
pc_sample->timestamp,
pc_sample->hardware_id);
// Vladimir: How to parse the remaining part of the `rocprofiler_pc_sampling_record_t`
// struct?
}
}
// Vladimr: We might want to add somewhere in the documentation that headars actually contain PC
// samples.
}
static void
run_HIP_app()
{
// TODO: provide the simple HIP app
}
@@ -1,190 +0,0 @@
// MIT License
//
// Copyright (c) 2023 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.
// Vladimir: The example of using Host-trap PC sampling on a system with single MI200/300 by two
// users. The first user initiates Host-Trap sampling with the configuration A. The second user
// tries initiaiting stochastic sampling with configuration B and fails. Then it queries available
// configurations and observes only the configuration A. It accepts it and starts PC sampling.
// Vladimir: Currently, this example is written as a single-threaded program.
// Decide whether to move the second user to a separate thread or process
#include <rocprofiler/rocprofiler.h>
#include "common.h"
#include <cassert>
#include <cstdlib>
#include <stdexcept>
#include <vector>
#define HOST_TRAP_INTERVAL 1000
rocprofiler_pc_sampling_method_t host_trap_sampling_method;
rocprofiler_pc_sampling_unit_t host_trap_sampling_unit_time;
uint64_t host_trap_interval;
void
second_user()
{
// creating a context
rocprofiler_context_id_t context_id2;
ROCPROFILER_CALL(rocprofiler_create_context(&context_id2),
"Cannot create context for the second user\n");
auto gpu_agent = find_first_gpu_agent();
if(!gpu_agent) throw std::runtime_error{"no gpu agents were found"};
// creating a buffer that will hold pc sampling information
rocprofiler_buffer_policy_t lossless_buffer_action = ROCPROFILER_BUFFER_POLICY_LOSSLESS;
rocprofiler_buffer_id_t buffer_id2;
ROCPROFILER_CALL(rocprofiler_create_buffer(context_id2,
BUFFER_SIZE_BYTES,
WATERMARK,
lossless_buffer_action,
rocprofiler_pc_sampling_callback,
nullptr,
&buffer_id2),
"Cannot create pc sampling buffer for the second user");
// The second user tries to create another pc sampling service with different configuration,
// but the rocprofiler rejects it.
rocprofiler_pc_sampling_method_t sampling_method2 = ROCPROFILER_PC_SAMPLING_METHOD_STOCHASTIC;
rocprofiler_pc_sampling_unit_t sampling_unit2 = ROCPROFILER_PC_SAMPLING_UNIT_CYCLES;
uint64_t interval2 = 2048; // I assumed micro secs, so this should be 1ms
// The following function returns an error code indicating the PC sampling has already been
// configured.
ROCPROFILER_CALL_FAILS(
rocprofiler_configure_pc_sampling_service(
context_id2, *gpu_agent, sampling_method2, sampling_unit2, interval2, buffer_id2),
"Instantiation of the PC sampling service should fail");
// After failure, the second user queries available configuration and observes the one chosen by
// the first user.
auto config_count = gpu_agent->num_pc_sampling_configs;
auto configs = std::vector<rocprofiler_pc_sampling_configuration_t>{};
configs.reserve(config_count);
for(size_t i = 0; i < config_count; ++i)
configs.emplace_back(gpu_agent->pc_sampling_configs[i]);
// Only one configuration should be listed, and its parameters should match the parameters set
// by the first user. Vladimir: Is it ok to use assertions? In the release mode, they might be
// ignored.
assert(config_count == 1);
rocprofiler_pc_sampling_configuration_t first_user_config = configs[0];
assert(first_user_config.method == host_trap_sampling_method);
assert(first_user_config.unit == host_trap_sampling_unit_time);
// Vladimir: Should the min_interval and max_interval have the same value at this point (the PC
// sampling is alredy configured)??
assert(first_user_config.min_interval == host_trap_interval &&
first_user_config.min_interval == first_user_config.max_interval);
// Reuse the same configuration set by the first user.
// The second user is satisfied with the configuration chosen by the first user, so it
// starts PC sampling.
ROCPROFILER_CALL(rocprofiler_configure_pc_sampling_service(context_id2,
*gpu_agent,
first_user_config.method,
first_user_config.unit,
first_user_config.min_interval,
buffer_id2),
"The second user cannot share already created PC sampling configuration");
// Starting the context that should trigger PC sampling?
ROCPROFILER_CALL(rocprofiler_start_context(context_id2),
"Cannot start PC sampling context for the second user");
// Running the applicaiton
run_HIP_app();
// Stop the context that should stop PC sampling?
ROCPROFILER_CALL(rocprofiler_stop_context(context_id2),
"Cannot start PC sampling context for the second user");
// Explicit buffer flush, before destroying it
ROCPROFILER_CALL(rocprofiler_flush_buffer(buffer_id2),
"Cannot destroy the second user's buffer");
// Destroying the buffer
ROCPROFILER_CALL(rocprofiler_destroy_buffer(buffer_id2), "Cannot destroy the second user's");
}
int
main(int /*argc*/, char** /*argv*/)
{
// creating a context
rocprofiler_context_id_t context_id;
ROCPROFILER_CALL(rocprofiler_create_context(&context_id), "Cannot create context\n");
auto gpu_agent = find_first_gpu_agent();
if(!gpu_agent)
{
fprintf(stderr, "no gpu agents were found\n");
return EXIT_FAILURE;
}
// creating a buffer that will hold pc sampling information
rocprofiler_buffer_policy_t drop_buffer_action = ROCPROFILER_BUFFER_POLICY_DISCARD;
rocprofiler_buffer_id_t buffer_id;
ROCPROFILER_CALL(rocprofiler_create_buffer(context_id,
BUFFER_SIZE_BYTES,
WATERMARK,
drop_buffer_action,
rocprofiler_pc_sampling_callback,
nullptr,
&buffer_id),
"Cannot create pc sampling buffer");
// PC sampling service configuration
host_trap_sampling_method = ROCPROFILER_PC_SAMPLING_METHOD_HOST_TRAP;
host_trap_sampling_unit_time = ROCPROFILER_PC_SAMPLING_UNIT_TIME;
// Vladimir: What units are we using for time? ms, micro secs, ns?
host_trap_interval = HOST_TRAP_INTERVAL;
// Instantiating the first PC sampling service succeeds.
ROCPROFILER_CALL(rocprofiler_configure_pc_sampling_service(context_id,
*gpu_agent,
host_trap_sampling_method,
host_trap_sampling_unit_time,
host_trap_interval,
buffer_id),
"Cannot create PC sampling service");
// Trigger the second user code.
// Vladimir: Discuss whether this should be put in a separate thread/process.
second_user();
// Starting the context that should trigger PC sampling?
ROCPROFILER_CALL(rocprofiler_start_context(context_id), "Cannot start PC sampling context");
// Running the applicaiton
run_HIP_app();
// Stop the context that should stop PC sampling?
ROCPROFILER_CALL(rocprofiler_stop_context(context_id), "Cannot start PC sampling context");
// Explicit buffer flush, before destroying it
ROCPROFILER_CALL(rocprofiler_flush_buffer(buffer_id), "Cannot destroy buffer");
// Destroying the buffer
ROCPROFILER_CALL(rocprofiler_destroy_buffer(buffer_id), "Cannot destroy buffer");
// Vladimir: Do we need to destroy context or a service?
return 0;
}
-87
Féach ar an gComhad
@@ -1,87 +0,0 @@
// MIT License
//
// Copyright (c) 2023 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.
// Vladimir: The example of using Host-trap PC sampling exclusively on the system with single MI200.
// If any of the rocprofiler calls returns status fail, we simply stop the application.
#include <rocprofiler/rocprofiler.h>
#include <cstdlib>
#include "common.h"
int
main(int /*argc*/, char** /*argv*/)
{
// creating a context
rocprofiler_context_id_t context_id;
ROCPROFILER_CALL(rocprofiler_create_context(&context_id), "Cannot create context\n");
auto gpu_agent = find_first_gpu_agent();
if(!gpu_agent)
{
fprintf(stderr, "no gpu agents were found\n");
return EXIT_FAILURE;
}
// creating a buffer that will hold pc sampling information
rocprofiler_buffer_policy_t drop_buffer_action = ROCPROFILER_BUFFER_POLICY_DISCARD;
rocprofiler_buffer_id_t buffer_id;
ROCPROFILER_CALL(rocprofiler_create_buffer(context_id,
BUFFER_SIZE_BYTES,
WATERMARK,
drop_buffer_action,
rocprofiler_pc_sampling_callback,
nullptr,
&buffer_id),
"Cannot create pc sampling buffer");
// PC sampling service configuration
rocprofiler_pc_sampling_method_t sampling_method = ROCPROFILER_PC_SAMPLING_METHOD_HOST_TRAP;
rocprofiler_pc_sampling_unit_t sampling_unit = ROCPROFILER_PC_SAMPLING_UNIT_TIME;
// What units are we using for time? ms, micro secs, ns?
uint64_t interval = 1000; // I assumed micro secs, so this should be 1ms
// Instantiating the PC sampling service
ROCPROFILER_CALL(
rocprofiler_configure_pc_sampling_service(
context_id, *gpu_agent, sampling_method, sampling_unit, interval, buffer_id),
"Cannot create PC sampling service");
// Vladimir: Is this the place of retrying if someone already created the
// configuration and the previous call fails?
// Starting the context that should trigger PC sampling?
ROCPROFILER_CALL(rocprofiler_start_context(context_id), "Cannot start PC sampling context");
// Running the applicaiton
run_HIP_app();
// Stop the context that should stop PC sampling?
ROCPROFILER_CALL(rocprofiler_stop_context(context_id), "Cannot start PC sampling context");
// Explicit buffer flush, before destroying it
ROCPROFILER_CALL(rocprofiler_flush_buffer(buffer_id), "Cannot destroy buffer");
// Destroying the buffer
ROCPROFILER_CALL(rocprofiler_destroy_buffer(buffer_id), "Cannot destroy buffer");
// Vladimir: Do we need to destroy context or a service?
return 0;
}
@@ -1,225 +0,0 @@
// MIT License
//
// Copyright (c) 2023 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.
// Vladimir: The example that shows how a single user can use PC sampling
// on multiple GPU agents.
#include <rocprofiler/rocprofiler.h>
#include <string.h>
#include <cassert>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include "common.h"
namespace
{
// GPU agents supporting some kind of PC sampling
std::vector<rocprofiler_agent_t> gpu_agents;
std::vector<rocprofiler_context_id_t> contexts;
std::vector<rocprofiler_buffer_id_t> buffer_ids;
rocprofiler_status_t
find_all_gpu_agents_supporting_pc_sampling_impl(const rocprofiler_agent_t** agents,
size_t num_agents,
void* data)
{
// data is required
if(!data) return ROCPROFILER_STATUS_ERROR;
auto* _out_agents = static_cast<std::vector<rocprofiler_agent_t>*>(data);
// find the first GPU agent
for(size_t i = 0; i < num_agents; i++)
{
if(agents[i]->type == ROCPROFILER_AGENT_TYPE_GPU)
{
// Skip GPU agents not supporting PC sampling
// Vladimir: The assumption is that if a GPU agent does not support PC sampling,
// the size is 0.
if(agents[i]->num_pc_sampling_configs == 0) continue;
_out_agents->push_back(*agents[i]);
printf("[%s] %s :: id=%u, type=%i, num pc sample configs=%zu\n",
__FUNCTION__,
agents[i]->name,
agents[i]->node_id,
agents[i]->type,
agents[i]->num_pc_sampling_configs);
return ROCPROFILER_STATUS_SUCCESS;
}
else
{
printf("[%s] %s :: id=%u, type=%i, num pc sample configs=%zu\n",
__FUNCTION__,
agents[i]->name,
agents[i]->node_id,
agents[i]->type,
agents[i]->num_pc_sampling_configs);
}
}
return !_out_agents->empty() ? ROCPROFILER_STATUS_SUCCESS : ROCPROFILER_STATUS_ERROR;
}
void
find_all_gpu_agents_supporting_pc_sampling()
{
// This function returns the all gpu agents supporting some kind of PC sampling
ROCPROFILER_CALL(
rocprofiler_query_available_agents(&find_all_gpu_agents_supporting_pc_sampling_impl,
sizeof(rocprofiler_agent_t),
static_cast<void*>(&gpu_agents)),
"Failed to find GPU agents");
}
} // namespace
void
configure_host_trap_sampling(rocprofiler_context_id_t context_id,
rocprofiler_buffer_id_t buffer_id,
rocprofiler_agent_t gpu_agent)
{
// Vladimir: Does MI200 have only one configuration?
assert(gpu_agent.num_pc_sampling_configs == 1);
// Extract the configuration
auto host_trap_config = gpu_agent.pc_sampling_configs[0];
// The mean of min_interval and max_interval
auto interval = (host_trap_config.min_interval + host_trap_config.max_interval) / 2;
ROCPROFILER_CALL(rocprofiler_configure_pc_sampling_service(context_id,
gpu_agent,
host_trap_config.method,
host_trap_config.unit,
interval,
buffer_id),
"Cannot create host-trap PC sampling service");
}
rocprofiler_pc_sampling_configuration_t
extract_stochastic_config(const rocprofiler_pc_sampling_configuration_t* configs,
size_t num_configs)
{
// Iterate over an array of configurations and return the first one
// with stochasting method.
for(size_t i = 0; i < num_configs; i++)
{
if(configs[i].method == ROCPROFILER_PC_SAMPLING_METHOD_STOCHASTIC)
{
return configs[i];
}
}
printf("Improper use of the `extract_stochastic_config` function.");
exit(-1);
}
void
configure_stochastic_sampling(rocprofiler_context_id_t context_id,
rocprofiler_buffer_id_t buffer_id,
rocprofiler_agent_t gpu_agent)
{
// Find the configuration matching stochastic sampling in cycles
rocprofiler_pc_sampling_configuration_t stochastic_config =
extract_stochastic_config(gpu_agent.pc_sampling_configs, gpu_agent.num_pc_sampling_configs);
// The mean of min_interval and max_interval
auto interval = (stochastic_config.min_interval + stochastic_config.max_interval) / 2;
ROCPROFILER_CALL(rocprofiler_configure_pc_sampling_service(context_id,
gpu_agent,
stochastic_config.method,
stochastic_config.unit,
interval,
buffer_id),
"Cannot create stochastic PC sampling service");
}
int
main(int /*argc*/, char** /*argv*/)
{
if(!find_first_gpu_agent())
{
fprintf(stderr, "no gpu agents were found\n");
return EXIT_FAILURE;
}
find_all_gpu_agents_supporting_pc_sampling();
if(gpu_agents.empty())
{
printf("No availabe gpu agents\n");
exit(-1);
}
// Vladimir: The relations I assumed:
// - a context per gpu agent
// - a buffer per context
// - a pc sampling service per buffer
// How about the following: Single context with mulitple buffers and PC sampling services?
// When starting the context, does it start all PC sampling services at once?
for(auto gpu_agent : gpu_agents)
{
// creating a context
rocprofiler_context_id_t context_id;
ROCPROFILER_CALL(rocprofiler_create_context(&context_id), "Cannot create context\n");
contexts.push_back(context_id);
// creating a buffer that will hold pc sampling information
rocprofiler_buffer_policy_t drop_buffer_action = ROCPROFILER_BUFFER_POLICY_DISCARD;
rocprofiler_buffer_id_t buffer_id;
ROCPROFILER_CALL(rocprofiler_create_buffer(context_id,
BUFFER_SIZE_BYTES,
WATERMARK,
drop_buffer_action,
rocprofiler_pc_sampling_callback,
nullptr,
&buffer_id),
"Cannot create pc sampling buffer");
buffer_ids.push_back(buffer_id);
if(gpu_agent.name == MI200_NAME)
configure_host_trap_sampling(context_id, buffer_id, gpu_agent);
else
configure_stochastic_sampling(context_id, buffer_id, gpu_agent);
// Starting the context that should trigger PC sampling
ROCPROFILER_CALL(rocprofiler_start_context(context_id), "Cannot start PC sampling context");
}
// Running the applicaiton
run_HIP_app();
for(size_t i = 0; i < gpu_agents.size(); i++)
{
// Stop the context that should stop PC sampling?
ROCPROFILER_CALL(rocprofiler_stop_context(contexts[i]), "Cannot start PC sampling context");
// Explicit buffer flush, before destroying it
ROCPROFILER_CALL(rocprofiler_flush_buffer(buffer_ids[i]), "Cannot destroy buffer");
// Destroying the buffer
ROCPROFILER_CALL(rocprofiler_destroy_buffer(buffer_ids[i]), "Cannot destroy buffer");
}
return 0;
}