// MIT License // // Copyright (c) 2023-2025 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 "tmp_file_buffer.hpp" #include "lib/common/container/ring_buffer.hpp" #include "lib/common/demangle.hpp" #include "lib/common/logging.hpp" #include #include #include #include #include #include namespace rocprofiler { namespace tool { /// converts a container of ring buffers of element Tp into a single container of elements template class ContainerT, typename... ParamsT> ContainerT get_buffer_elements(ContainerT, ParamsT...>&& data) { auto ret = ContainerT{}; for(auto& buf : data) { Tp* record = nullptr; do { record = buf.retrieve(); if(record) ret.emplace_back(*record); } while(record != nullptr); } return ret; } template std::vector get_buffer_elements(common::container::ring_buffer&& buf) { auto ret = std::vector{}; Tp* record = nullptr; ret.reserve(buf.count()); do { record = buf.retrieve(); if(record) ret.emplace_back(*record); } while(record != nullptr); return ret; } template struct buffered_output; struct defer_size {}; template struct generator { generator() = delete; virtual ~generator() = default; generator(const generator&) = delete; generator(generator&&) noexcept = delete; generator& operator=(const generator&) = delete; generator& operator=(generator&&) noexcept = delete; auto begin() { return m_pos.begin(); } auto begin() const { return m_pos.begin(); } auto cbegin() const { return m_pos.cbegin(); } auto end() { return m_pos.end(); } auto end() const { return m_pos.end(); } auto cend() const { return m_pos.cend(); } auto size() const { return m_pos.size(); } auto empty() const { return m_pos.empty(); } virtual std::vector get(size_t) const = 0; protected: explicit generator(defer_size); explicit generator(size_t sz); void resize(size_t sz); std::vector m_pos = {}; }; template generator::generator(defer_size) {} template generator::generator(size_t sz) { resize(sz); } template void generator::resize(size_t sz) { m_pos.resize(sz, 0); std::iota(m_pos.begin(), m_pos.end(), 0); } template struct file_generator : public generator { template friend struct buffered_output; file_generator() = delete; ~file_generator() override = default; file_generator(const file_generator&) = delete; file_generator(file_generator&&) noexcept = delete; file_generator& operator=(const file_generator&) = delete; file_generator& operator=(file_generator&&) noexcept = delete; std::vector get(size_t itr) const override; private: explicit file_generator(file_buffer* fbuf); file_buffer* filebuf = nullptr; std::lock_guard lk_guard; std::set file_pos = {}; }; template file_generator::file_generator(file_buffer* fbuf) : generator{fbuf->file.file_pos.size()} , filebuf{fbuf} , lk_guard{filebuf->file.file_mutex} , file_pos{filebuf->file.file_pos} {} template std::vector file_generator::get(size_t idx) const { auto _data = std::vector{}; auto& _fs = filebuf->file.stream; if(idx >= file_pos.size()) { ROCP_ERROR << fmt::format("file_generator has no file position at index {}", idx); return _data; } auto itr = file_pos.begin(); std::advance(itr, idx); if(itr == file_pos.end()) { ROCP_ERROR << fmt::format("file_generator at index {} == end of file_pos set", idx); return _data; } ROCP_TRACE << fmt::format("file_generator file position at index={} :: ", idx) << *itr; _fs.seekg(*itr); // set to the absolute position if(!_fs.eof()) { auto _buffer = ring_buffer_t{}; _buffer.load(_fs); _data = get_buffer_elements(std::move(_buffer)); } return _data; } } // namespace tool } // namespace rocprofiler namespace cereal { namespace tool = ::rocprofiler::tool; template void save(ArchiveT& ar, const tool::file_generator& data) { ar.makeArray(); for(auto itr : data) { auto dat = data.get(itr); for(const auto& ditr : dat) ar(ditr); } } template void save(ArchiveT& ar, const tool::generator& data) { if(const auto* fdata = dynamic_cast*>(&data); fdata != nullptr) { save(ar, *fdata); } else { ROCP_CI_LOG(WARNING) << fmt::format( "dynamic_cast failed for {}", rocprofiler::common::cxx_demangle(typeid(tool::generator).name())); } } } // namespace cereal