timemory 3.3.0
Modular C++ Toolkit for Performance Analysis and Logging. Profiling API and Tools for C, C++, CUDA, Fortran, and Python. The C++ template API is essentially a framework to creating tools: it is designed to provide a unifying interface for recording various performance measurements alongside data logging and interfaces to other tools.
pthread.cpp
Go to the documentation of this file.
1// MIT License
2//
3// Copyright (c) 2020, The Regents of the University of California,
4// through Lawrence Berkeley National Laboratory (subject to receipt of any
5// required approvals from the U.S. Dept. of Energy). All rights reserved.
6//
7// Permission is hereby granted, free of charge, to any person obtaining a copy
8// of this software and associated documentation files (the "Software"), to deal
9// in the Software without restriction, including without limitation the rights
10// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11// copies of the Software, and to permit persons to whom the Software is
12// furnished to do so, subject to the following conditions:
13//
14// The above copyright notice and this permission notice shall be included in all
15// copies or substantial portions of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23// SOFTWARE.
24
25#if !defined(TIMEMORY_LIBRARY_SOURCE)
26# define TIMEMORY_LIBRARY_SOURCE 1
27#endif
28
29#include "timemory/backends/threading.hpp"
31#include "timemory/library.h"
32#include "timemory/manager.hpp"
35#include "timemory/timemory.hpp"
36#include "timemory/trace.hpp"
38
39#if !defined(TIMEMORY_WINDOWS)
40
41# include <array>
42# include <functional>
43# include <pthread.h>
44
45using namespace tim::component;
46
47//--------------------------------------------------------------------------------------//
48
49extern "C"
50{
53 TIMEMORY_VISIBILITY("default");
54
56 {
57 return tim::get_env("TIMEMORY_ENABLE_PTHREAD_GOTCHA_WRAPPER", false);
58 }
59}
60
61//--------------------------------------------------------------------------------------//
62
63struct pthread_gotcha : tim::component::base<pthread_gotcha, void>
64{
65 template <size_t... Idx>
67 {
68 // array of finalization functions
69 std::array<std::function<void()>, sizeof...(Idx)> _data{};
70 // generate a function for finalizing
71 TIMEMORY_FOLD_EXPRESSION(get_storage_impl<Idx>(_data));
72 // return the array of finalization functions
73 return _data;
74 }
75
76 struct wrapper
77 {
78 typedef void* (*routine_t)(void*);
79
80 TIMEMORY_DEFAULT_OBJECT(wrapper)
81
82 wrapper(routine_t _routine, void* _arg, bool _debug)
83 : m_routine(_routine)
84 , m_arg(_arg)
85 , m_debug(_debug)
86 {}
87
88 void* operator()() const { return m_routine(m_arg); }
89
90 bool debug() const { return m_debug; }
91 static void* wrap(void* _arg)
92 {
93 if(!_arg)
94 return nullptr;
95
96 // get the thread id
97 auto _tid = tim::threading::get_id();
98 // convert the argument
99 wrapper* _wrapper = static_cast<wrapper*>(_arg);
100 if(_wrapper->debug())
101 PRINT_HERE("[T%li] Creating timemory manager", (long int) _tid);
102 // create the manager and initialize the storage
103 auto _tlm = tim::manager::instance();
104# if defined(TIMEMORY_INTERNAL_TESTING)
105 if(_tlm == nullptr)
106 throw std::runtime_error("nullptr to manager instance");
107# else
108 (void) _tlm;
109# endif
110 // initialize the storage
111 auto _final =
113 if(_wrapper->debug())
114 PRINT_HERE("[T%li] Executing original function", (long int) _tid);
115 // execute the original function
116 auto* _ret = (*_wrapper)();
117 if(_wrapper->debug())
118 PRINT_HERE("[T%li] Executing finalizing callbacks", (long int) _tid);
119 // finalize
120 for(auto& itr : _final)
121 itr();
122 if(_wrapper->debug())
123 PRINT_HERE("[T%li] Returning from thread", (long int) _tid);
124 // return the data
125 return _ret;
126 }
127
128 private:
129 routine_t m_routine = nullptr;
130 void* m_arg = nullptr;
131 bool m_debug = false;
132 };
133
134 // pthread_create
135 int operator()(pthread_t* thread, const pthread_attr_t* attr,
136 void* (*start_routine)(void*), void* arg)
137 {
138 // get the thread id
139 auto _tid = tim::threading::get_id();
140 auto* _settings = tim::settings::instance<TIMEMORY_API>();
141 auto _debug = (_settings) ? _settings->get_debug() : true;
142 if(_debug)
143 PRINT_HERE("[T%li] Creating new thread", (long int) _tid);
144 auto* _obj = new wrapper(start_routine, arg, _debug);
145 return pthread_create(thread, attr, &wrapper::wrap, static_cast<void*>(_obj));
146 }
147
148private:
149 template <size_t Idx, size_t N>
150 static void get_storage_impl(std::array<std::function<void()>, N>& _data)
151 {
152 _data[Idx] = []() {
155 // auto _instance = tim::storage<type>::instance();
156 // tim::get_storage_singleton<tim::storage<type>>()->reset(_instance);
157 };
158 }
159};
160
161//--------------------------------------------------------------------------------------//
162
166
167//--------------------------------------------------------------------------------------//
168
169auto
171{
172# if defined(TIMEMORY_USE_GOTCHA)
174 {
176 TIMEMORY_C_GOTCHA(pthread_gotcha_t, 0, pthread_create);
177 };
178 }
179 return std::make_shared<pthread_bundle_t>();
180# else
181 return std::shared_ptr<pthread_bundle_t>{};
182# endif
183}
184
185//--------------------------------------------------------------------------------------//
186
187namespace
188{
189auto pthread_gotcha_handle = setup_pthread_gotcha();
190}
191
192#else
193namespace
194{
195auto pthread_gotcha_handle = false;
196}
197#endif
This is a variadic component wrapper where all components are allocated on the stack and cannot be di...
static pointer_t instance()
Get a shared pointer to the instance for the current thread.
#define TIMEMORY_WEAK_PREFIX
Definition: macros.h:230
#define TIMEMORY_WEAK_POSTFIX
Definition: macros.h:242
#define TIMEMORY_C_GOTCHA(...)
Definition: macros.hpp:323
typename enumerator< Idx >::type enumerator_t
Definition: properties.hpp:273
const hash_alias_ptr_t hash_value_t std::string *& _ret
Definition: definition.hpp:300
std::make_integer_sequence< size_t, Num > make_index_sequence
Alias template make_index_sequence.
Definition: types.hpp:182
Tp get_env(const std::string &env_id, Tp _default, bool _store)
char argparse::argument_parser tim::settings * _settings
Definition: config.cpp:255
std::integer_sequence< size_t, Idx... > index_sequence
Alias template index_sequence.
Definition: types.hpp:178
TIMEMORY_WEAK_PREFIX bool timemory_enable_pthread_gotcha_wrapper() TIMEMORY_WEAK_POSTFIX
Definition: pthread.cpp:55
auto setup_pthread_gotcha()
Definition: pthread.cpp:170
Definition for various functions for storage_initializer in operations.
static base_storage_type * get_storage()
The gotcha component rewrites the global offset table such that calling the wrapped function actually...
Definition: components.hpp:179
static get_initializer_t & get_initializer()
Definition: components.hpp:234
#define PRINT_HERE(...)
Definition: macros.hpp:152
#define TIMEMORY_FOLD_EXPRESSION(...)
Definition: types.hpp:56