1 // ========================================================================== 2 // $Source: /var/lib/cvs/Givaro/src/kernel/memory/givaromm.h,v $ 3 // Copyright(c)'1994-2009 by The Givaro group 4 // This file is part of Givaro. 5 // Givaro is governed by the CeCILL-B license under French law 6 // and abiding by the rules of distribution of free software. 7 // see the COPYRIGHT file for more details. 8 // Author: T. Gautier 9 // $Id: givaromm.h,v 1.7 2011-02-02 16:23:56 briceboyer Exp $ 10 // ========================================================================== 11 12 /** @file givaromm.h 13 * @ingroup memory 14 * @brief Memory management in Givaro 15 * two memory managers: 16 * - the first one handle a set on free-list of blocs ; 17 * - the second one implement a reference mecanism on the bloc. 18 * . 19 * The latter used method of the former. 20 */ 21 #ifndef __GIVARO_mm_H 22 #define __GIVARO_mm_H 23 24 #include <cstring> // gcc 4.3 25 #include <stddef.h> // size_t definition 26 #include <iostream> // ostream definition 27 #include <new> 28 #include "givaro/givmodule.h" 29 #include "givaro/givbasictype.h" 30 #ifdef GIVARO_DEBUG 31 #include "givaro/giverror.h" 32 #endif 33 34 #include <givaro/givconfig.h> 35 namespace Givaro { 36 37 // ==================================================================== // 38 39 //! Static informations of memory allocation 40 class GivMMInfo { 41 public: 42 GivMMInfo(); 43 ~GivMMInfo(); 44 size_t physalloc; // size in bytes of physical allocated bloc 45 size_t logalloc; // size in bytes of "logical" allocated bloc 46 size_t sizetab; // length of next arrays 47 size_t* tabbloc; // size of all the blocs 48 size_t* tablog; // number of each logical allocated bloc 49 size_t* tabphy; // number of each physical allocated bloc 50 std::ostream& print( std::ostream& so ) const; 51 }; 52 53 //! IO 54 inline std::ostream& operator<<( std::ostream& o, const GivMMInfo& T) 55 { return T.print(o); } 56 57 // -------------------------------------------------------- 58 //! Data structure of a bloc. 59 //! Each bloc in TabFree[id] has a data field of size TabSize[id] 60 class BlocFreeList { 61 union header { 62 int index ; // - index in free list 63 BlocFreeList* nextfree; // - pointer to the next free bloc (of the same size) 64 double dummy; // - here to force alignment on data on 8bytes boundary 65 } u; 66 int64_t data[1]; 67 68 // -- Array of list of free bloc 69 static BlocFreeList* TabFree[]; 70 static const size_t TabSize[] ; 71 static const int lenTables; 72 static int search_binary( size_t sz ) ; 73 74 friend class GivMMInfo; 75 friend class GivMMFreeList; 76 friend class GivMMRefCount; 77 }; 78 79 80 // -------------------------------------------------------- 81 //! Implementation of a memory manager with free-lists. 82 //! All members are static methods. 83 class GivMMFreeList { 84 public: 85 86 // -- Free all internal data structures 87 static void Destroy(); 88 89 // -- Allocation of a new bloc. 90 // These two next functions returns a pointer or 0. 91 // The frequently required bloc is treated in a special version 92 // in order to speed-up the allocation. 93 static BlocFreeList* _allocate (const size_t sz); allocate(const size_t sz)94 inline static void* allocate (const size_t sz) 95 { 96 #ifdef GIVARO_DEBUG 97 if (sz ==0) return 0 ; 98 #endif 99 size_t index; 100 BlocFreeList* tmp; 101 if ((sz <= 32) && ((tmp=BlocFreeList::TabFree[index =sz-1]) !=0)) { 102 BlocFreeList::TabFree[index] = tmp->u.nextfree; 103 tmp->u.index = (int)index; 104 #ifdef GIVARO_STATMEM 105 tablog[index] ++; logalloc += BlocFreeList::TabSize[index]; 106 #endif 107 return (void*) tmp->data; 108 } 109 tmp = _allocate(sz); 110 return tmp->data ; 111 } 112 113 // -- Reallocation of a bloc. 114 // The function returns a pointer to the possibly new 115 // bloc. If the bloc must be moved then only oldsize are 116 // recopied. 117 static void* resize (void* p, const size_t oldsize, const size_t newsize); 118 119 // -- Free the bloc pointed by p and allocated by the manager GivMMFreeList. 120 inline static void desallocate(void* p, const size_t = 0) 121 { 122 if (p==0) return ; 123 BlocFreeList* tmp = reinterpret_cast<BlocFreeList*>(((char*)p) - 124 (sizeof(BlocFreeList)-sizeof(int64_t))); 125 int index = tmp->u.index; 126 #ifdef GIVARO_DEBUG 127 if ((index <0) || (index >= BlocFreeList::lenTables)) 128 throw GivError("[GivMMFreeList::desallocate]: bad pointer."); 129 #endif 130 tmp->u.nextfree = BlocFreeList::TabFree[index]; 131 BlocFreeList::TabFree[index] = tmp; 132 } 133 134 // -- Recopy size bytes pointed by src into bytes pointer by dest 135 static void memcpy( void* dest, const void* src, const size_t size ); 136 137 // -- Returns some memory usage informations 138 static const GivMMInfo& Usage(); 139 140 //private: 141 // -- bug (on CW10): must comment the private part to initialize next field 142 static GivMMInfo info; 143 144 #ifdef GIVARO_STATMEM 145 friend class GivMMInfo; 146 friend class GivMMRefCount; 147 static size_t& physalloc; // total amount of physical allocated bloc 148 static size_t& logalloc; // total amoun of "logical" allocated bloc 149 static size_t*& tablog; // number of each logical allocated bloc 150 static size_t*& tabphy; // number of each physical allocated bloc 151 #endif 152 153 // -- Initialization module 154 public: 155 static GivModule Module; 156 private: 157 static void Init(int* argc, char***argv); 158 static void End(); 159 friend class GivModule; 160 }; 161 162 163 //! Memory management with reference counter on allocated data. 164 //! The memory manager uses the BlocFreeList data structure 165 //! and stores the refcounter in the field data[0] 166 class GivMMRefCount { 167 public: 168 // -- Allocation of a new bloc of size at least s allocate(const size_t s)169 inline static void* allocate (const size_t s) 170 { 171 172 #ifdef GIVARO_DEBUG 173 if (s ==0) return 0 ; 174 #endif 175 int index; 176 BlocFreeList* tmp; 177 size_t sz = s + sizeof(int64_t); 178 if ((sz <= 32) && ((tmp=BlocFreeList::TabFree[index =int(sz-1)]) !=0)) { 179 BlocFreeList::TabFree[index] = tmp->u.nextfree; 180 tmp->u.index = index; 181 #ifdef GIVARO_STATMEM 182 GivMMFreeList::tablog[index] ++; GivMMFreeList::logalloc += BlocFreeList::TabSize[index]; 183 #endif 184 tmp->data[0] = 1 ; 185 return (void*) &(tmp->data[1]); 186 } 187 tmp = GivMMFreeList::_allocate(sz); 188 tmp->data[0] = 1 ; 189 190 191 return (void*) &(tmp->data[1]); 192 } 193 194 // -- Reallocation of a bloc. See description in GivMMFreeList's class. 195 // Here, if ref count on p is >1 then a new bloc is allocated. 196 static void* resize (void* p, const size_t oldsize, const size_t newsize); 197 198 // -- Free the bloc allocated by the manager GivMMRefCount. 199 inline static void desallocate(void* p, const size_t = 0) 200 { 201 if (p==0) return ; 202 BlocFreeList* tmp = reinterpret_cast<BlocFreeList*>((char *) p - sizeof(BlocFreeList) ) ; 203 if ( --(tmp->data[0]) ==0) { 204 int index = tmp->u.index; 205 #ifdef GIVARO_DEBUG 206 if ((index <0) || (index >= BlocFreeList::lenTables)) 207 GivError::throw_error(GivError("[GivMMRefCount::desallocate]: bad pointer.")); 208 #endif 209 #ifdef GIVARO_JGD 210 if ((index <0) || (index >= BlocFreeList::lenTables)) 211 cerr << "[GivMMRefCount::desallocate]: bad pointer with index " << index << ", doing nothing ..." << endl; 212 else { 213 #endif 214 tmp->u.nextfree = BlocFreeList::TabFree[index]; 215 BlocFreeList::TabFree[index] = tmp; 216 #ifdef GIVARO_JGD 217 } 218 #endif 219 } 220 } 221 222 // -- Assignement of pointer: assign(void ** dest,void * src)223 inline static void* assign (void** dest, void*src) 224 { 225 if (src == *dest) return *dest ; 226 if (*dest !=0) GivMMRefCount::desallocate( *dest ); 227 if (src ==0) return *dest=src; 228 BlocFreeList* s = reinterpret_cast<BlocFreeList*>(((char*)src) - sizeof(BlocFreeList)); 229 #ifdef GIVARO_DEBUG 230 if ((s->u.index <0) || (s->u.index >= BlocFreeList::lenTables)) 231 GivError::throw_error(GivError("[GivMMRefCount::assign]: bad pointer 'src'.")); 232 #endif 233 ++(s->data[0]); 234 return *dest = src ; 235 } 236 237 // -- Increment, decrement and getvalue of the refcount. 238 // Returns the value after increment/decrment. incrc(void * p)239 inline static int incrc(void* p) 240 { 241 if (p ==0) return 0; 242 BlocFreeList* bp = reinterpret_cast<BlocFreeList*>(((char*)p) - sizeof(BlocFreeList)); 243 #ifdef GIVARO_DEBUG 244 if ((bp->u.index <0) || (bp->u.index >= BlocFreeList::lenTables)) 245 throw GivError("[GivMMRefCount::incrc]: bad pointer."); 246 #endif 247 return int(++(bp->data[0])); 248 } decrc(void * p)249 inline static int decrc(void* p) 250 { 251 if (p ==0) return 0; 252 BlocFreeList* bp = reinterpret_cast<BlocFreeList*>(((char*)p) - sizeof(BlocFreeList)); 253 #ifdef GIVARO_DEBUG 254 if ((bp->u.index <0) || (bp->u.index >= BlocFreeList::lenTables)) 255 throw GivError("[GivMMRefCount::incrc]: bad pointer."); 256 #endif 257 return int(--(bp->data[0])); 258 } getrc(void * p)259 inline static int getrc(void* p) 260 { 261 if (p ==0) return 0; 262 BlocFreeList* bp = reinterpret_cast<BlocFreeList*>(((char*)p) - sizeof(BlocFreeList)); 263 #ifdef GIVARO_DEBUG 264 if ((bp->u.index <0) || (bp->u.index >= BlocFreeList::lenTables)) 265 throw GivError("[GivMMRefCount::incrc]: bad pointer."); 266 #endif 267 return int(bp->data[0]); 268 } 269 }; 270 271 272 //! Memory manager that allocates array of object of type T for 273 template<class T> 274 class GivaroMM { 275 public: 276 typedef T* ptT; 277 // -- Allocation of a new bloc contains s unintialized elements 278 static T* allocate (const size_t s); 279 // -- Desallocation of bloc 280 static void desallocate ( T* bloc, const size_t sz =0 ); 281 // -- Initialize each element pointed by bloc with value V 282 static void initone( T*p, const T& V = T()); 283 static void initialize(T* bloc, const size_t s, const T& V =T()); 284 // -- Call destructor on each elements pointed by bloc 285 static void destroy(T* bloc, const size_t s); 286 }; 287 288 289 //! @bug implem does not belong here 290 //@{ 291 template<class T> allocate(const size_t s)292 inline T* GivaroMM<T>::allocate (const size_t s) 293 { return (T*)GivMMFreeList::allocate(s*sizeof(T)); } 294 template<class T> desallocate(T * bloc,const size_t sz)295 inline void GivaroMM<T>::desallocate(T* bloc, const size_t sz) 296 { GivMMFreeList::desallocate((void*)bloc,sz); } 297 template<class T> initone(T * p,const T & V)298 inline void GivaroMM<T>::initone( T* p, const T& V) 299 { new (p) T(V); } 300 template<class T> initialize(T * bloc,const size_t s,const T & V)301 inline void GivaroMM<T>::initialize(T* bloc, const size_t s, const T& V) 302 { for (size_t i=0; i<s; i++) GivaroMM<T>::initone(&(bloc[i]), V); } 303 template<class T> destroy(T * bloc,const size_t s)304 inline void GivaroMM<T>::destroy(T* bloc, const size_t s) 305 { for (size_t i=0; i<s; i++) bloc[i].~T(); } 306 //@} 307 308 // -- specialized version: for basic C++ type and pointer on this type 309 #define GIVARO_MM_SPECIALIZED(TYPE) \ 310 template<> class GivaroMM<TYPE> {\ 311 public: \ 312 typedef TYPE* ptType;\ 313 typedef TYPE Type;\ 314 static ptType allocate (const size_t s);\ 315 static void desallocate ( ptType bloc, const size_t sz =0 );\ 316 static void initone( ptType p, const Type V = 0);\ 317 static void initialize(ptType bloc, const size_t s, const Type V =0);\ 318 static void destroy(GivaroMM<TYPE>::ptType bloc, const size_t s);\ 319 };\ 320 inline GivaroMM<TYPE>::ptType GivaroMM<TYPE>::allocate (const size_t s)\ 321 { return (GivaroMM<TYPE>::ptType)GivMMFreeList::allocate(s*sizeof(GivaroMM<TYPE>::Type)); }\ 322 inline void GivaroMM<TYPE>::desallocate(GivaroMM<TYPE>::ptType bloc, const size_t sz)\ 323 { GivMMFreeList::desallocate((void*)bloc,sz); }\ 324 inline void GivaroMM<TYPE>::initone( GivaroMM<TYPE>::ptType p, const GivaroMM<TYPE>::Type v) \ 325 { *p = v; }\ 326 inline void GivaroMM<TYPE>::initialize(GivaroMM<TYPE>::ptType bloc, const size_t s, const GivaroMM<TYPE>::Type V)\ 327 { for (size_t i=0; i<s; i++) bloc[i] = V; }\ 328 inline void GivaroMM<TYPE>::destroy(GivaroMM<TYPE>::ptType bloc, const size_t s){} 329 330 #if 0 331 GIVARO_MM_SPECIALIZED(char) 332 GIVARO_MM_SPECIALIZED(short) 333 GIVARO_MM_SPECIALIZED(int) 334 GIVARO_MM_SPECIALIZED(long) 335 GIVARO_MM_SPECIALIZED(float) 336 GIVARO_MM_SPECIALIZED(double) 337 338 GIVARO_MM_SPECIALIZED(unsigned char) 339 GIVARO_MM_SPECIALIZED(unsigned short) 340 GIVARO_MM_SPECIALIZED(unsigned int) 341 GIVARO_MM_SPECIALIZED(unsigned long) 342 343 GIVARO_MM_SPECIALIZED(char*) 344 GIVARO_MM_SPECIALIZED(short*) 345 GIVARO_MM_SPECIALIZED(int*) 346 GIVARO_MM_SPECIALIZED(long*) 347 GIVARO_MM_SPECIALIZED(float*) 348 GIVARO_MM_SPECIALIZED(double*) 349 350 GIVARO_MM_SPECIALIZED(unsigned char*) 351 GIVARO_MM_SPECIALIZED(unsigned short*) 352 GIVARO_MM_SPECIALIZED(unsigned int*) 353 GIVARO_MM_SPECIALIZED(unsigned long*) 354 #endif 355 356 } // namespace Givaro 357 358 #endif // __GIVARO_mm_H 359 360 /* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 361 // vim:sts=4:sw=4:ts=4:et:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s 362