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
242 lines
7.4 KiB
C++
242 lines
7.4 KiB
C++
// MIT License
|
|
//
|
|
// Copyright (c) 2026 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 "lib/common/container/pool_object.hpp"
|
|
#include "lib/common/container/stable_vector.hpp"
|
|
#include "lib/common/defines.hpp"
|
|
#include "lib/common/demangle.hpp"
|
|
#include "lib/common/logging.hpp"
|
|
#include "lib/common/mpl.hpp"
|
|
|
|
#include <fmt/format.h>
|
|
#include <fmt/ranges.h>
|
|
|
|
#include <atomic>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <queue>
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
|
|
namespace rocprofiler
|
|
{
|
|
namespace common
|
|
{
|
|
namespace container
|
|
{
|
|
template <typename Tp>
|
|
struct pool
|
|
{
|
|
using size_type = size_t;
|
|
using pool_array_type = stable_vector<pool_object<Tp>, 32>;
|
|
|
|
template <typename FuncT, typename... Args>
|
|
explicit pool(std::piecewise_construct_t, size_type count, FuncT&& ctor, Args&&... args);
|
|
|
|
~pool() = default;
|
|
pool(const pool&) = delete;
|
|
pool(pool&&) noexcept = delete;
|
|
pool& operator=(const pool&) = delete;
|
|
pool& operator=(pool&&) noexcept = delete;
|
|
|
|
// get an object from the pool. if all objects are in use, a new one will be created and added
|
|
// to the pool
|
|
pool_object<Tp>& acquire();
|
|
void release(size_type idx);
|
|
|
|
template <typename FuncT, typename... Args>
|
|
pool_object<Tp>& acquire(FuncT&& ctor, Args&&... args);
|
|
|
|
template <typename FuncT = void (*)(pool_object<Tp>&)>
|
|
void clear(FuncT&& func = [](pool_object<Tp>&) {});
|
|
|
|
std::string get_usage_report() const;
|
|
|
|
private:
|
|
size_type m_count = 256;
|
|
std::function<void()> m_function = nullptr;
|
|
mutable std::mutex m_pool_mtx = {};
|
|
pool_array_type m_pool = {};
|
|
mutable std::mutex m_available_mtx = {};
|
|
std::queue<size_type> m_available = {};
|
|
std::atomic<size_type> m_released = 0;
|
|
std::atomic<size_type> m_reused = 0;
|
|
std::atomic<size_type> m_new_batch = 0;
|
|
};
|
|
|
|
template <typename Tp>
|
|
template <typename FuncT, typename... Args>
|
|
pool<Tp>::pool(std::piecewise_construct_t, size_type count, FuncT&& ctor, Args&&... args)
|
|
: m_count{count}
|
|
, m_function{[this,
|
|
_ctor = std::forward<FuncT>(ctor),
|
|
_args_tuple = std::make_tuple(std::forward<Args>(args)...)]() {
|
|
for(size_type i = 0; i < m_count; ++i)
|
|
{
|
|
auto idx = m_pool.size();
|
|
m_pool.emplace_back(idx, false, this);
|
|
std::apply(
|
|
[&](auto&&... unpacked_args) {
|
|
_ctor(m_pool[idx].get(), std::forward<decltype(unpacked_args)>(unpacked_args)...);
|
|
},
|
|
_args_tuple);
|
|
m_available.push(idx);
|
|
}
|
|
}}
|
|
{
|
|
m_function();
|
|
}
|
|
|
|
template <typename Tp>
|
|
pool_object<Tp>&
|
|
pool<Tp>::acquire()
|
|
{
|
|
auto _idx = std::optional<size_type>{};
|
|
{
|
|
auto _avail_lk = std::unique_lock<std::mutex>{m_available_mtx};
|
|
if(!m_available.empty())
|
|
{
|
|
_idx = m_available.front();
|
|
m_available.pop();
|
|
if(m_released > 0)
|
|
{
|
|
m_reused++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(_idx.has_value())
|
|
{
|
|
auto _read_lk = std::unique_lock<std::mutex>{m_pool_mtx};
|
|
auto& _obj = m_pool.at(_idx.value());
|
|
ROCP_FATAL_IF(!_obj.acquire()) << fmt::format(
|
|
"Pool object at index {} was expected to be available but was not", _idx.value());
|
|
return _obj;
|
|
}
|
|
|
|
// add a new batch
|
|
{
|
|
auto _write_pool_lk = std::unique_lock<std::mutex>{m_pool_mtx};
|
|
auto _write_avail_lk = std::unique_lock<std::mutex>{m_available_mtx};
|
|
if(m_available.empty())
|
|
{
|
|
ROCP_INFO << fmt::format(
|
|
"Pool of type {} exhausted. Creating new batch of {} objects. New pool size: {}",
|
|
cxx_demangle(typeid(Tp).name()),
|
|
m_count,
|
|
m_pool.size() + m_count);
|
|
m_new_batch++;
|
|
m_function();
|
|
}
|
|
}
|
|
|
|
return acquire();
|
|
}
|
|
|
|
template <typename Tp>
|
|
void
|
|
pool<Tp>::release(size_type idx)
|
|
{
|
|
if(idx < m_pool.size())
|
|
{
|
|
auto _write_lk = std::unique_lock<std::mutex>{m_available_mtx};
|
|
ROCP_FATAL_IF(m_pool.at(idx).in_use())
|
|
<< fmt::format("Pool object at index {} was expected to be not in use", idx);
|
|
m_available.push(idx);
|
|
m_released++;
|
|
}
|
|
}
|
|
|
|
// get an object from the pool. if all objects are in use, a new one will be created and added to
|
|
// the pool
|
|
template <typename Tp>
|
|
template <typename FuncT, typename... Args>
|
|
pool_object<Tp>&
|
|
pool<Tp>::acquire(FuncT&& ctor, Args&&... args)
|
|
{
|
|
auto& _ref = acquire();
|
|
ctor(_ref.get(), std::forward<Args>(args)...);
|
|
return _ref;
|
|
}
|
|
|
|
template <typename Tp>
|
|
template <typename FuncT>
|
|
void
|
|
pool<Tp>::clear(FuncT&& func)
|
|
{
|
|
auto _write_pool_lk = std::unique_lock<std::mutex>{m_pool_mtx};
|
|
|
|
for(auto& itr : m_pool)
|
|
{
|
|
ROCP_WARNING_IF(itr.in_use()) << fmt::format(
|
|
"Pool object at index {} is still in use during pool clear", itr.index());
|
|
itr.release();
|
|
// run cleanup lambda
|
|
if constexpr(std::is_invocable_v<FuncT, pool_object<Tp>&>)
|
|
{
|
|
func(itr);
|
|
}
|
|
else if constexpr(std::is_invocable_v<FuncT, Tp&>)
|
|
{
|
|
func(itr.get());
|
|
}
|
|
else
|
|
{
|
|
static_assert(mpl::assert_false<FuncT>::value,
|
|
"Invalid function type for pool<Tp>::clear");
|
|
}
|
|
}
|
|
|
|
auto _write_avail_lk = std::unique_lock<std::mutex>{m_available_mtx};
|
|
|
|
while(!m_available.empty())
|
|
m_available.pop();
|
|
m_pool = pool_array_type{};
|
|
m_released.store(0);
|
|
m_reused.store(0);
|
|
m_new_batch.store(0);
|
|
}
|
|
|
|
template <typename Tp>
|
|
std::string
|
|
pool<Tp>::get_usage_report() const
|
|
{
|
|
auto _pool_lk = std::unique_lock<std::mutex>{m_pool_mtx};
|
|
auto _avail_lk = std::unique_lock<std::mutex>{m_available_mtx};
|
|
return fmt::format("Usage report for pool (type='{}') :: size={}, available={}, reused={}, "
|
|
"released={}, batches={}",
|
|
cxx_demangle(typeid(Tp).name()),
|
|
m_pool.size(),
|
|
m_available.size(),
|
|
m_reused.load(),
|
|
m_released.load(),
|
|
m_new_batch.load());
|
|
}
|
|
} // namespace container
|
|
} // namespace common
|
|
} // namespace rocprofiler
|