hydrogen 1.2.6
Object.cpp
Go to the documentation of this file.
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 * Copyright(c) 2008-2025 The hydrogen development team [hydrogen-devel@lists.sourceforge.net]
5 *
6 * http://www.hydrogen-music.org
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY, without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see https://www.gnu.org/licenses
20 *
21 */
22
23#include "core/Object.h"
24
25#include <cassert>
26#include <sstream>
27#include <iomanip>
28#include <cstdlib>
29#include <typeinfo>
30
31#ifdef WIN32
32# include "core/Timehelper.h"
33#else
34# include <unistd.h>
35# include <sys/time.h>
36#endif
37
38#ifdef HAVE_EXECINFO_H
39#include <execinfo.h>
40#endif
41
54
55namespace H2Core {
56
57Logger* Base::__logger = nullptr;
58bool Base::bLogColors = true;
59bool Base::__count = false;
60std::atomic<int> Base::__objects_count(0);
61pthread_mutex_t Base::__mutex;
63QString Base::sPrintIndention = " ";
64timeval Base::__last_clock = { 0, 0 };
65
66int Base::bootstrap( Logger* pLogger, bool count ) {
67 if ( __logger == nullptr && pLogger != nullptr ) {
68 __logger = pLogger;
69 __count = count;
70
71 Base::bLogColors = pLogger->getLogColors();
72
73 pthread_mutex_init( &__mutex, nullptr );
74 return 0;
75 }
76 return 1;
77}
78
79void Base::set_count( bool flag ) {
80#ifdef H2CORE_HAVE_DEBUG
81 __count = flag;
82#else
83 if( __logger!=0 && __logger->should_log( Logger::Error ) ) {
84 __logger->log( Logger::Error, "set_count", "Object", "not compiled with H2CORE_HAVE_DEBUG flag set" );
85 }
86#endif
87}
88
89void Base::write_objects_map_to( std::ostream& out, object_map_t* map ) {
90#ifdef H2CORE_HAVE_DEBUG
91 if ( !__count ) {
92 if ( ! Base::bLogColors ) {
93 out << "level must be Debug or higher" << std::endl;
94 } else {
95 out << "\033[35mlog level must be \033[31mDebug\033[35m or higher\033[0m"<< std::endl;
96 }
97
98 return;
99 }
100 object_map_t snapshot;
101 if ( map == nullptr ) {
102 snapshot = getObjectMap();
103 map = &snapshot;
104 }
105
106 std::ostringstream o;
107 pthread_mutex_lock( &__mutex );
108 object_map_t::iterator it = map->begin();
109 while ( it != map->end() ) {
110 if ( it->second.constructed || it->second.destructed ) {
111 o << "\t[ " << std::setw( 30 ) << ( *it ).first << " ]\t" << std::setw( 6 ) << ( *it ).second.constructed << "\t" << std::setw( 6 ) << ( *it ).second.destructed
112 << "\t" << std::setw( 6 ) << ( *it ).second.constructed - ( *it ).second.destructed << std::endl;
113 }
114 it++;
115 }
116 pthread_mutex_unlock( &__mutex );
117
118 out << std::endl;
119 if ( Base::bLogColors ) {
120 out << "\033[35m";
121 }
122
123 out << "Objects map :" << std::setw( 30 ) << "class\t" << "constr destr alive" << std::endl << o.str() << "Total : " << std::setw( 6 ) << __objects_count << " objects.";
124
125 if ( Base::bLogColors ) {
126 out << "\033[0m";
127 }
128 out << std::endl << std::endl;
129#else
130
131 if ( ! Base::bLogColors ) {
132 out << "Base::write_objects_map_to :: not compiled with H2CORE_HAVE_DEBUG flag set" << std::endl;
133 } else {
134 out << "\033[35mBase::write_objects_map_to :: \033[31mnot compiled with H2CORE_HAVE_DEBUG flag set\033[0m" << std::endl;
135 }
136#endif
137}
138
140#ifdef H2CORE_HAVE_DEBUG
141 int nCount = 0;
142 for (auto const& ii : __objects_map ) {
143 if (!strcmp(ii.first, "Object")) {
144 return ii.second->constructed - ii.second->destructed;
145 }
146 }
147 return nCount;
148#else
149 ERRORLOG( "This function is only supported in debug builds of Hydrogen." );
150 return 0;
151#endif
152}
153
155 object_map_t mapCopy;
156 obj_cpt_t copy;
157
158 for ( auto const& ii : __objects_map ) {
159 copy.constructed = ii.second->constructed;
160 copy.destructed = ii.second->destructed;
161 mapCopy.insert( std::pair<const char*, obj_cpt_t>( ii.first, copy ) );
162 }
163
164 return mapCopy;
165}
166
168 object_map_t mapDiff;
169 obj_cpt_t diff;
170
171 // Since key value pairs are only inserted but not erased while
172 // Hydrogen is running it is save to assume for mapSnapshot to be
173 // a subset of the current object map.
174 for ( auto const& ii : __objects_map ) {
175 auto it = mapSnapshot.find( ii.first );
176 if ( it != mapSnapshot.end() ) {
177 diff.constructed = ii.second->constructed - it->second.constructed;
178 diff.destructed = ii.second->destructed - it->second.destructed;
179 mapDiff.insert( std::pair<const char*, obj_cpt_t>( ii.first, diff ) );
180 }
181 }
182
183 write_objects_map_to( std::cout, &mapDiff );
184}
185
186QString Base::toQString( const QString& sPrefix, bool bShort ) const {
187 return QString( "[%1] instances alive: %2" )
188 .arg( class_name() ).arg( count_active() );
189}
190
191void Base::Print( bool bShort ) const {
192 DEBUGLOG( toQString( "", bShort ) );
193}
194
195void Base::logBacktrace() const {
196#ifdef HAVE_EXECINFO_H
197 const int nMaxFrames = 128;
198 void *frames[ nMaxFrames ];
199 int nFrames = backtrace( frames, nMaxFrames );
200 char **symbols = backtrace_symbols( frames, nFrames );
201 for ( int i = 0; i < nFrames; i++ ) {
202 DEBUGLOG( QString("%1").arg( symbols[i] ) );
203 }
204#else
205 DEBUGLOG( "Compiled without backtrace support" );
206#endif
207}
208
209QString Base::base_clock_in( const QString& sMsg )
210{
211 struct timeval now;
212 gettimeofday( &now, nullptr );
213 __last_clock = now;
214
215 QString sResult( "Start clocking" );
216 if ( ! sMsg.isEmpty() ) {
217 sResult = QString( "%1: %2" ).arg( sMsg ).arg( sResult );
218 }
219
220 return std::move( sResult );
221}
222
223QString Base::base_clock( const QString& sMsg )
224{
225 struct timeval now;
226 gettimeofday( &now, nullptr );
227
228 QString sResult;
229 if ( __last_clock.tv_sec == 0 && __last_clock.tv_usec == 0 ) {
230 // Clock is invoked for the first time.
231 sResult = "Start clocking";
232 } else {
233 sResult = QString( "elapsed [%1]ms" )
234 .arg( ( now.tv_sec - __last_clock.tv_sec ) * 1000.0 +
235 ( now.tv_usec - __last_clock.tv_usec ) / 1000.0 );
236 }
237
238 __last_clock = now;
239
240 if ( ! sMsg.isEmpty() ) {
241 sResult = QString( "%1: %2" ).arg( sMsg ).arg( sResult );
242 }
243
244 return std::move( sResult );
245}
246
247std::ostream& operator<<( std::ostream& os, const Base& object ) {
248 return os << object.toQString( "", true ).toLocal8Bit().data() << std::endl;
249}
250
251std::ostream& operator<<( std::ostream& os, const Base* object ) {
252 return os << object->toQString( "", true ).toLocal8Bit().data() << std::endl;
253}
254
255void Base::registerClass(const char *name, const atomic_obj_cpt_t *counters)
256{
257 if ( ! counters ) {
258 qWarning() << "Base::registerClass: " << name << " null counters!";
259 }
260 if ( counters->constructed ) {
261 // already registered by another thread
262 return;
263 }
264 if ( ! __objects_map[name] ) {
265 __objects_map[name] = counters;
266 } else {
267 qWarning() << "Base::registerClass: " << name << " already registered";
268 }
269}
270
271}; // namespace H2Core
272
273/* vim: set softtabstop=4 noexpandtab: */
#define ERRORLOG(x)
Definition Object.h:242
#define DEBUGLOG(x)
Definition Object.h:239
int gettimeofday(struct timeval *tv, struct timezone *tz)
Base class.
Definition Object.h:62
static std::atomic< int > __objects_count
total objects count
Definition Object.h:162
static void registerClass(const char *name, const atomic_obj_cpt_t *counters)
Definition Object.cpp:255
virtual QString toQString(const QString &sPrefix="", bool bShort=true) const
Formatted string version for debugging purposes.
Definition Object.cpp:186
static QString base_clock_in(const QString &sMsg)
Definition Object.cpp:209
static object_map_t getObjectMap()
Definition Object.cpp:154
static pthread_mutex_t __mutex
yeah this has to be thread safe
Definition Object.h:164
static bool count_active()
Definition Object.h:85
static QString base_clock(const QString &sMsg)
Measures the current time and stores it in __last_clock.
Definition Object.cpp:223
static int getAliveObjectCount()
Definition Object.cpp:139
void Print(bool bShort=true) const
Prints content of toQString() via DEBUGLOG.
Definition Object.cpp:191
void logBacktrace() const
Print the current stack at point into the debug log.
Definition Object.cpp:195
static bool __count
should we count class instances
Definition Object.h:155
static bool bLogColors
Definition Object.h:157
static void set_count(bool flag)
enable/disable class instances counting
Definition Object.cpp:79
static int bootstrap(Logger *logger, bool count=false)
must be called before any Object instantiation !
Definition Object.cpp:66
static timeval __last_clock
Definition Object.h:159
static object_internal_map_t __objects_map
objects classes and instances count structure
Definition Object.h:163
static QString sPrintIndention
String used to format the debugging string output of some core classes.
Definition Object.h:127
static void write_objects_map_to(std::ostream &out, object_map_t *map=nullptr)
output the full objects map to a given ostream
Definition Object.cpp:89
virtual const char * class_name() const
Definition Object.h:79
static Logger * __logger
Definition Object.h:156
static void printObjectMapDiff(object_map_t map)
Creates the difference between a snapshot of the object map and its current state and prints it to st...
Definition Object.cpp:167
Class for writing logs to the console.
Definition Logger.h:41
bool getLogColors() const
Definition Logger.h:201
std::map< const char *, const atomic_obj_cpt_t * > object_internal_map_t
Definition Object.h:56
std::ostream & operator<<(std::ostream &os, const Base &object)
Definition Object.cpp:247
std::map< const char *, obj_cpt_t > object_map_t
the objects class map types
Definition Object.h:55
atomic_obj_cpt_t Object< T >::counters
Definition Object.h:223
an objects class map item type
Definition Object.h:43