Files
TheRock/rocm-systems/projects/rocprofiler-systems/external/timemory/source/library.cpp
T
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

667 lines
21 KiB
C++

// MIT License
//
// Copyright (c) 2020, The Regents of the University of California,
// through Lawrence Berkeley National Laboratory (subject to receipt of any
// required approvals from the U.S. Dept. of Energy). 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.
#if !defined(TIMEMORY_LIBRARY_SOURCE)
# define TIMEMORY_LIBRARY_SOURCE 1
#endif
#include "timemory/compat/library.h"
#include "timemory/config.hpp"
#include "timemory/library.h"
#include "timemory/runtime/configure.hpp"
#include "timemory/timemory.hpp"
#include "timemory/trace.hpp"
#include <cstdarg>
#include <deque>
#include <iostream>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace tim::component;
//======================================================================================//
extern "C"
{
timemory_create_func_t timemory_create_function = nullptr;
timemory_delete_func_t timemory_delete_function = nullptr;
}
//======================================================================================//
using string_t = std::string;
using library_toolset_t = TIMEMORY_LIBRARY_TYPE;
using toolset_t = typename library_toolset_t::component_type;
using region_map_t = std::unordered_map<std::string, std::stack<uint64_t>>;
using record_map_t = std::unordered_map<uint64_t, toolset_t>;
using component_enum_t = std::vector<TIMEMORY_COMPONENT>;
using components_stack_t = std::deque<component_enum_t>;
static std::string spacer =
"#-------------------------------------------------------------------------#";
//--------------------------------------------------------------------------------------//
static record_map_t&
get_record_map()
{
static thread_local record_map_t _instance;
return _instance;
}
//--------------------------------------------------------------------------------------//
static region_map_t&
get_region_map()
{
static thread_local region_map_t _instance;
return _instance;
}
//--------------------------------------------------------------------------------------//
static components_stack_t&
get_components_stack()
{
static auto _leader_tid = std::this_thread::get_id();
static components_stack_t _leader_instance;
static thread_local components_stack_t _worker_instance = _leader_instance;
return (std::this_thread::get_id() == _leader_tid) ? _leader_instance
: _worker_instance;
}
//--------------------------------------------------------------------------------------//
// default components to record
//
inline std::string&
get_default_components()
{
static std::string _instance =
tim::get_env<std::string>("TIMEMORY_GLOBAL_COMPONENTS", "wall_clock");
return _instance;
}
//--------------------------------------------------------------------------------------//
// current set of components being recorded
//
inline component_enum_t&
get_current_components()
{
auto& _stack = get_components_stack();
if(_stack.empty())
{
_stack.push_back(
tim::enumerate_components(get_default_components(), "TIMEMORY_COMPONENTS"));
}
return _stack.back();
}
//--------------------------------------------------------------------------------------//
std::array<bool, 2>&
get_library_state()
{
static auto _instance = std::array<bool, 2>({ { false, false } });
return _instance;
}
//--------------------------------------------------------------------------------------//
//
// timemory symbols
//
//--------------------------------------------------------------------------------------//
extern "C"
{
//----------------------------------------------------------------------------------//
// get a unique id
//
uint64_t timemory_get_unique_id(void)
{
// the maps are thread-local so no concerns for data-race here since
// two threads updating at once and subsequently losing once of the updates
// still results in a unique id for that thread
static uint64_t uniqID = 0;
return uniqID++;
}
//----------------------------------------------------------------------------------//
// create a toolset of measurements
//
void timemory_create_record(const char* name, uint64_t* id, int n, int* ctypes)
{
if(timemory_create_function)
{
(*timemory_create_function)(name, id, n, ctypes);
return;
}
// else: provide default behavior
static thread_local auto& _record_map = get_record_map();
*id = timemory_get_unique_id();
_record_map.insert({ *id, toolset_t(name, true) });
tim::initialize(_record_map[*id], n, ctypes);
_record_map[*id].start();
if(_record_map.bucket_count() > _record_map.size())
_record_map.rehash(_record_map.size() + 10);
}
//----------------------------------------------------------------------------------//
// destroy a toolset of measurements
//
void timemory_delete_record(uint64_t id)
{
if(timemory_delete_function)
{
(*timemory_delete_function)(id);
}
else if(get_record_map().find(id) != get_record_map().end())
{
static thread_local auto& _record_map = get_record_map();
// stop recording, destroy objects, and erase key from map
_record_map[id].stop();
_record_map.erase(id);
}
}
//----------------------------------------------------------------------------------//
//
//
bool timemory_library_is_initialized(void) { return get_library_state()[0]; }
//----------------------------------------------------------------------------------//
//
//
void timemory_named_init_library(char* name)
{
if(name)
{
char* _name[1] = { name };
timemory_init_library(1, _name);
}
}
//----------------------------------------------------------------------------------//
// initialize the library
//
void timemory_init_library(int argc, char** argv)
{
tim::trace::lock<tim::trace::library> lk{};
if(get_library_state()[0])
return;
get_library_state()[0] = true;
if(argc < 1 && argv)
argc = 1;
if(argv == nullptr)
{
argc = 0;
}
else
{
int i = 0;
for(; i < argc; ++i)
{
if(argv[i] == nullptr)
{
argc = i;
break;
}
}
}
if(tim::settings::verbose() > 0)
{
printf("%s\n", spacer.c_str());
printf("\tInitialization of timemory library...\n");
printf("%s\n\n", spacer.c_str());
}
if(argc > 0 && argv)
tim::timemory_init(argc, argv);
tim::manager::instance()->update_metadata_prefix();
// tim::settings::parse();
}
//----------------------------------------------------------------------------------//
// finalize the library
void timemory_finalize_library(void)
{
tim::trace::lock<tim::trace::library> lk{};
get_library_state()[1] = true;
auto _manager = tim::manager::master_instance();
auto* _settings = tim::settings::instance();
if(!_manager || !_settings)
return;
if(_settings->get_enabled() == false && get_record_map().empty())
return;
auto& _record_map = get_record_map();
if(_settings->get_verbose() > 0)
{
printf("\n%s\n", spacer.c_str());
printf("\tFinalization of timemory library...\n");
printf("%s\n\n", spacer.c_str());
}
// put keys into a set so that a potential LD_PRELOAD for timemory_delete_record
// is called and there is not a concern for the map iterator
std::unordered_set<uint64_t> keys;
for(auto& itr : _record_map)
keys.insert(itr.first);
// delete all the records
for(const auto& itr : keys)
timemory_delete_record(itr);
// clear the map
_record_map.clear();
// have the manager finalize
if(tim::manager::instance())
tim::manager::instance()->finalize();
// do the finalization
tim::timemory_finalize();
// just in case
_settings->get_enabled() = false;
// set the finalization state to true
tim::dmp::set_finalized(true);
// reset manager
tim::manager::instance().reset();
// PGI and Intel compilers don't respect destruction order
#if defined(__PGI) || defined(__INTEL_COMPILER)
_settings->get_output() = false;
#endif
}
//----------------------------------------------------------------------------------//
// pause the collection
//
void timemory_pause(void) { tim::settings::enabled() = false; }
//----------------------------------------------------------------------------------//
// resume the collection
//
void timemory_resume(void) { tim::settings::enabled() = true; }
//----------------------------------------------------------------------------------//
void timemory_set_default(const char* _component_string)
{
tim::trace::lock<tim::trace::library> lk{};
get_default_components() =
tim::get_env<std::string>("TIMEMORY_GLOBAL_COMPONENTS", _component_string);
// tim::set_env("TIMEMORY_COMPONENTS", _component_string, 0);
static thread_local auto& _stack = get_components_stack();
if(_stack.empty())
_stack.push_back(tim::enumerate_components(get_default_components()));
}
//----------------------------------------------------------------------------------//
void timemory_set_environ(const char* evar, const char* eval, int over, int parse)
{
tim::trace::lock<tim::trace::library> lk{};
if(evar && eval)
{
tim::set_env(evar, eval, over);
if(parse > 0)
tim::settings::parse();
}
}
//----------------------------------------------------------------------------------//
void timemory_add_components(const char* _component_string)
{
tim::trace::lock<tim::trace::library> lk{};
auto& _stack = get_current_components();
for(auto itr : tim::enumerate_components(_component_string))
_stack.push_back(itr);
}
//----------------------------------------------------------------------------------//
void timemory_remove_components(const char* _component_string)
{
tim::trace::lock<tim::trace::library> lk{};
auto& _stack = get_current_components();
for(auto itr : tim::enumerate_components(_component_string))
_stack.erase(std::remove(_stack.begin(), _stack.end(), itr), _stack.end());
}
//----------------------------------------------------------------------------------//
void timemory_push_components(const char* _component_string)
{
tim::trace::lock<tim::trace::library> lk{};
static thread_local auto& _stack = get_components_stack();
_stack.push_back(tim::enumerate_components(_component_string));
}
//----------------------------------------------------------------------------------//
void timemory_push_components_enum(int types, ...)
{
tim::trace::lock<tim::trace::library> lk{};
static thread_local auto& _stack = get_components_stack();
component_enum_t comp({ types });
va_list args;
va_start(args, types);
for(int i = 0; i < TIMEMORY_COMPONENTS_END; ++i)
{
auto enum_arg = va_arg(args, int);
if(enum_arg >= TIMEMORY_COMPONENTS_END)
break;
comp.push_back(enum_arg);
}
va_end(args);
_stack.push_back(comp);
}
//----------------------------------------------------------------------------------//
void timemory_pop_components(void)
{
tim::trace::lock<tim::trace::library> lk{};
static thread_local auto& _stack = get_components_stack();
if(_stack.size() > 1)
_stack.pop_back();
}
//----------------------------------------------------------------------------------//
void timemory_begin_record(const char* name, uint64_t* id)
{
tim::trace::lock<tim::trace::library> lk{};
if(!lk || tim::settings::enabled() == false)
{
*id = std::numeric_limits<uint64_t>::max();
return;
}
auto& comp = get_current_components();
timemory_create_record(name, id, comp.size(), (int*) (comp.data()));
#if defined(DEBUG)
if(tim::settings::verbose() > 2)
printf("beginning record for '%s' (id = %lli)...\n", name,
(long long int) *id);
#endif
}
//----------------------------------------------------------------------------------//
void timemory_begin_record_types(const char* name, uint64_t* id, const char* ctypes)
{
tim::trace::lock<tim::trace::library> lk{};
if(!lk || tim::settings::enabled() == false)
{
*id = std::numeric_limits<uint64_t>::max();
return;
}
auto comp = tim::enumerate_components(std::string(ctypes));
timemory_create_record(name, id, comp.size(), (int*) (comp.data()));
#if defined(DEBUG)
if(tim::settings::verbose() > 2)
printf("beginning record for '%s' (id = %lli)...\n", name,
(long long int) *id);
#endif
}
//----------------------------------------------------------------------------------//
void timemory_begin_record_enum(const char* name, uint64_t* id, ...)
{
tim::trace::lock<tim::trace::library> lk{};
if(!lk || tim::settings::enabled() == false)
{
*id = std::numeric_limits<uint64_t>::max();
return;
}
component_enum_t comp;
va_list args;
va_start(args, id);
for(int i = 0; i < TIMEMORY_COMPONENTS_END; ++i)
{
auto enum_arg = va_arg(args, int);
if(enum_arg >= TIMEMORY_COMPONENTS_END)
break;
comp.push_back(enum_arg);
}
va_end(args);
timemory_create_record(name, id, comp.size(), (int*) (comp.data()));
#if defined(DEBUG)
if(tim::settings::verbose() > 2)
printf("beginning record for '%s' (id = %lli)...\n", name,
(long long int) *id);
#endif
}
//----------------------------------------------------------------------------------//
uint64_t timemory_get_begin_record(const char* name)
{
tim::trace::lock<tim::trace::library> lk{};
if(!lk || tim::settings::enabled() == false)
return std::numeric_limits<uint64_t>::max();
uint64_t id = 0;
auto& comp = get_current_components();
timemory_create_record(name, &id, comp.size(), (int*) (comp.data()));
#if defined(DEBUG)
if(tim::settings::verbose() > 2)
printf("beginning record for '%s' (id = %lli)...\n", name,
(long long int) id);
#endif
return id;
}
//----------------------------------------------------------------------------------//
uint64_t timemory_get_begin_record_types(const char* name, const char* ctypes)
{
tim::trace::lock<tim::trace::library> lk{};
if(!lk || tim::settings::enabled() == false)
return std::numeric_limits<uint64_t>::max();
uint64_t id = 0;
auto comp = tim::enumerate_components(std::string(ctypes));
timemory_create_record(name, &id, comp.size(), (int*) (comp.data()));
#if defined(DEBUG)
if(tim::settings::verbose() > 2)
printf("beginning record for '%s' (id = %lli)...\n", name,
(long long int) id);
#endif
return id;
}
//----------------------------------------------------------------------------------//
uint64_t timemory_get_begin_record_enum(const char* name, ...)
{
tim::trace::lock<tim::trace::library> lk{};
if(!lk || tim::settings::enabled() == false)
return std::numeric_limits<uint64_t>::max();
uint64_t id = 0;
component_enum_t comp;
va_list args;
va_start(args, name);
for(int i = 0; i < TIMEMORY_COMPONENTS_END; ++i)
{
auto enum_arg = va_arg(args, int);
if(enum_arg >= TIMEMORY_COMPONENTS_END)
break;
comp.push_back(enum_arg);
}
va_end(args);
timemory_create_record(name, &id, comp.size(), (int*) (comp.data()));
#if defined(DEBUG)
if(tim::settings::verbose() > 2)
printf("beginning record for '%s' (id = %lli)...\n", name,
(long long int) id);
#endif
return id;
}
//----------------------------------------------------------------------------------//
void timemory_end_record(uint64_t id)
{
tim::trace::lock<tim::trace::library> lk{};
if(!lk || id == std::numeric_limits<uint64_t>::max())
return;
timemory_delete_record(id);
#if defined(DEBUG)
if(tim::settings::verbose() > 2)
printf("ending record for %lli...\n", (long long int) id);
#endif
}
//----------------------------------------------------------------------------------//
void timemory_push_region(const char* name)
{
tim::trace::lock<tim::trace::library> lk{};
if(!lk)
return;
auto& region_map = get_region_map();
lk.release();
auto idx = timemory_get_begin_record(name);
lk = tim::trace::lock<tim::trace::library>{};
region_map[name].push(idx);
}
//----------------------------------------------------------------------------------//
void timemory_pop_region(const char* name)
{
tim::trace::lock<tim::trace::library> lk{};
if(!lk)
return;
auto& region_map = get_region_map();
auto itr = region_map.find(name);
if(itr == region_map.end() || (itr != region_map.end() && itr->second.empty()))
fprintf(stderr, "Warning! region '%s' does not exist!\n", name);
else
{
uint64_t idx = itr->second.top();
lk.release();
timemory_end_record(idx);
lk = tim::trace::lock<tim::trace::library>{};
itr->second.pop();
}
}
//==================================================================================//
//
// Symbols for Fortran
//
//==================================================================================//
void timemory_create_record_(const char* name, uint64_t* id, int n, int* ct)
{
timemory_create_record(name, id, n, ct);
}
void timemory_delete_record_(uint64_t id) { timemory_delete_record(id); }
void timemory_init_library_(int argc, char** argv)
{
timemory_init_library(argc, argv);
}
void timemory_finalize_library_(void) { timemory_finalize_library(); }
void timemory_set_default_(const char* components)
{
timemory_set_default(components);
}
void timemory_push_components_(const char* components)
{
timemory_push_components(components);
}
void timemory_pop_components_(void) { timemory_pop_components(); }
void timemory_begin_record_(const char* name, uint64_t* id)
{
timemory_begin_record(name, id);
}
void timemory_begin_record_types_(const char* name, uint64_t* id, const char* ctypes)
{
timemory_begin_record_types(name, id, ctypes);
}
uint64_t timemory_get_begin_record_(const char* name)
{
return timemory_get_begin_record(name);
}
uint64_t timemory_get_begin_record_types_(const char* name, const char* ctypes)
{
return timemory_get_begin_record_types(name, ctypes);
}
void timemory_end_record_(uint64_t id) { return timemory_end_record(id); }
void timemory_push_region_(const char* name) { return timemory_push_region(name); }
void timemory_pop_region_(const char* name) { return timemory_pop_region(name); }
//======================================================================================//
} // extern "C"