hydrogen 1.2.3
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-2024 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
51namespace H2Core {
52
53Logger* Base::__logger = nullptr;
54bool Base::__count = false;
55std::atomic<int> Base::__objects_count(0);
56pthread_mutex_t Base::__mutex;
58QString Base::sPrintIndention = " ";
59timeval Base::__last_clock = { 0, 0 };
60
61int Base::bootstrap( Logger* logger, bool count ) {
62 if( __logger==nullptr && logger!=nullptr ) {
64 __count = count;
65 pthread_mutex_init( &__mutex, nullptr );
66 return 0;
67 }
68 return 1;
69}
70
71void Base::set_count( bool flag ) {
72#ifdef H2CORE_HAVE_DEBUG
73 __count = flag;
74#else
76 __logger->log( Logger::Error, "set_count", "Object", "not compiled with H2CORE_HAVE_DEBUG flag set" );
77 }
78#endif
79}
80
81void Base::write_objects_map_to( std::ostream& out, object_map_t* map ) {
82#ifdef H2CORE_HAVE_DEBUG
83 if( !__count ) {
84#ifdef WIN32
85 out << "level must be Debug or higher"<< std::endl;
86#else
87 out << "\033[35mlog level must be \033[31mDebug\033[35m or higher\033[0m"<< std::endl;
88#endif
89 return;
90 }
91 object_map_t snapshot;
92 if ( map == nullptr ) {
93 snapshot = getObjectMap();
94 map = &snapshot;
95 }
96
97 std::ostringstream o;
98 pthread_mutex_lock( &__mutex );
99 object_map_t::iterator it = map->begin();
100 while ( it != map->end() ) {
101 if ( it->second.constructed || it->second.destructed ) {
102 o << "\t[ " << std::setw( 30 ) << ( *it ).first << " ]\t" << std::setw( 6 ) << ( *it ).second.constructed << "\t" << std::setw( 6 ) << ( *it ).second.destructed
103 << "\t" << std::setw( 6 ) << ( *it ).second.constructed - ( *it ).second.destructed << std::endl;
104 }
105 it++;
106 }
107 pthread_mutex_unlock( &__mutex );
108#ifndef WIN32
109 out << std::endl << "\033[35m";
110#endif
111 out << "Objects map :" << std::setw( 30 ) << "class\t" << "constr destr alive" << std::endl << o.str() << "Total : " << std::setw( 6 ) << __objects_count << " objects.";
112#ifndef WIN32
113 out << "\033[0m";
114#endif
115 out << std::endl << std::endl;
116#else
117#ifdef WIN32
118 out << "Base::write_objects_map_to :: not compiled with H2CORE_HAVE_DEBUG flag set" << std::endl;
119#else
120 out << "\033[35mBase::write_objects_map_to :: \033[31mnot compiled with H2CORE_HAVE_DEBUG flag set\033[0m" << std::endl;
121#endif
122#endif
123}
124
126#ifdef H2CORE_HAVE_DEBUG
127 int nCount = 0;
128 for (auto const& ii : __objects_map ) {
129 if (!strcmp(ii.first, "Object")) {
130 return ii.second->constructed - ii.second->destructed;
131 }
132 }
133 return nCount;
134#else
135 ERRORLOG( "This function is only supported in debug builds of Hydrogen." );
136 return 0;
137#endif
138}
139
141 object_map_t mapCopy;
142 obj_cpt_t copy;
143
144 for ( auto const& ii : __objects_map ) {
145 copy.constructed = ii.second->constructed;
146 copy.destructed = ii.second->destructed;
147 mapCopy.insert( std::pair<const char*, obj_cpt_t>( ii.first, copy ) );
148 }
149
150 return mapCopy;
151}
152
154 object_map_t mapDiff;
155 obj_cpt_t diff;
156
157 // Since key value pairs are only inserted but not erased while
158 // Hydrogen is running it is save to assume for mapSnapshot to be
159 // a subset of the current object map.
160 for ( auto const& ii : __objects_map ) {
161 auto it = mapSnapshot.find( ii.first );
162 if ( it != mapSnapshot.end() ) {
163 diff.constructed = ii.second->constructed - it->second.constructed;
164 diff.destructed = ii.second->destructed - it->second.destructed;
165 mapDiff.insert( std::pair<const char*, obj_cpt_t>( ii.first, diff ) );
166 }
167 }
168
169 write_objects_map_to( std::cout, &mapDiff );
170}
171
172QString Base::toQString( const QString& sPrefix, bool bShort ) const {
173 return QString( "[%1] instances alive: %2" )
174 .arg( class_name() ).arg( count_active() );
175}
176
177void Base::Print( bool bShort ) const {
178 DEBUGLOG( toQString( "", bShort ) );
179}
180
181QString Base::base_clock_in( const QString& sMsg )
182{
183 struct timeval now;
184 gettimeofday( &now, nullptr );
185 __last_clock = now;
186
187 QString sResult( "Start clocking" );
188 if ( ! sMsg.isEmpty() ) {
189 sResult = QString( "%1: %2" ).arg( sMsg ).arg( sResult );
190 }
191
192 return std::move( sResult );
193}
194
195QString Base::base_clock( const QString& sMsg )
196{
197 struct timeval now;
198 gettimeofday( &now, nullptr );
199
200 QString sResult;
201 if ( __last_clock.tv_sec == 0 && __last_clock.tv_usec == 0 ) {
202 // Clock is invoked for the first time.
203 sResult = "Start clocking";
204 } else {
205 sResult = QString( "elapsed [%1]ms" )
206 .arg( ( now.tv_sec - __last_clock.tv_sec ) * 1000.0 +
207 ( now.tv_usec - __last_clock.tv_usec ) / 1000.0 );
208 }
209
210 __last_clock = now;
211
212 if ( ! sMsg.isEmpty() ) {
213 sResult = QString( "%1: %2" ).arg( sMsg ).arg( sResult );
214 }
215
216 return std::move( sResult );
217}
218
219std::ostream& operator<<( std::ostream& os, const Base& object ) {
220 return os << object.toQString( "", true ).toLocal8Bit().data() << std::endl;
221}
222
223std::ostream& operator<<( std::ostream& os, const Base* object ) {
224 return os << object->toQString( "", true ).toLocal8Bit().data() << std::endl;
225}
226
227void Base::registerClass(const char *name, const atomic_obj_cpt_t *counters)
228{
229 if ( ! counters ) {
230 qWarning() << "Base::registerClass: " << name << " null counters!";
231 }
232 if ( counters->constructed ) {
233 // already registered by another thread
234 return;
235 }
236 if ( ! __objects_map[name] ) {
237 __objects_map[name] = counters;
238 } else {
239 qWarning() << "Base::registerClass: " << name << " already registered";
240 }
241}
242
243}; // namespace H2Core
244
245/* vim: set softtabstop=4 noexpandtab: */
#define ERRORLOG(x)
Definition Object.h:239
#define DEBUGLOG(x)
Definition Object.h:236
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:159
static void registerClass(const char *name, const atomic_obj_cpt_t *counters)
Definition Object.cpp:227
static Logger * logger()
return the logger instance
Definition Object.h:103
virtual QString toQString(const QString &sPrefix="", bool bShort=true) const
Formatted string version for debugging purposes.
Definition Object.cpp:172
static QString base_clock_in(const QString &sMsg)
Definition Object.cpp:181
static object_map_t getObjectMap()
Definition Object.cpp:140
static pthread_mutex_t __mutex
yeah this has to be thread safe
Definition Object.h:161
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:195
static int getAliveObjectCount()
Definition Object.cpp:125
void Print(bool bShort=true) const
Prints content of toQString() via DEBUGLOG.
Definition Object.cpp:177
static bool __count
should we count class instances
Definition Object.h:153
static void set_count(bool flag)
enable/disable class instances counting
Definition Object.cpp:71
static int bootstrap(Logger *logger, bool count=false)
must be called before any Object instantiation !
Definition Object.cpp:61
static timeval __last_clock
Definition Object.h:156
static object_internal_map_t __objects_map
objects classes and instances count structure
Definition Object.h:160
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:81
virtual const char * class_name() const
Definition Object.h:79
static Logger * __logger
Definition Object.h:154
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:153
Class for writing logs to the console.
Definition Logger.h:42
void log(unsigned level, const QString &class_name, const char *func_name, const QString &msg)
the log function
Definition Logger.cpp:144
bool should_log(unsigned lvl) const
return true if the level is set in the bitmask
Definition Logger.h:83
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:219
std::map< const char *, obj_cpt_t > object_map_t
the objects class map types
Definition Object.h:55
an objects class map item type
Definition Object.h:43
std::atomic< int > constructed
Definition Object.h:44