6 * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $
7 ***************************************************************/
10 * \brief Implementation of memory manager for more efficiently
11 * allocating small pieces of memory
13 * \author Carsten Gutwenger
16 * This file is part of the Open Graph Drawing Framework (OGDF).
20 * See README.txt in the root directory of the OGDF installation for details.
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * Version 2 or 3 as published by the Free Software Foundation;
26 * see the file LICENSE.txt included in the packaging of this file
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
36 * You should have received a copy of the GNU General Public
37 * License along with this program; if not, write to the Free
38 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
39 * Boston, MA 02110-1301, USA.
41 * \see http://www.gnu.org/copyleft/gpl.html
42 ***************************************************************/
45 #include <ogdf/basic/basic.h>
51 struct PoolMemoryAllocator::PoolVector
53 MemElemPtr m_pool
[ePoolVectorLength
];
57 struct PoolMemoryAllocator::PoolElement
59 PoolVector
*m_currentVector
;
60 MemElemPtr m_restHead
;
61 MemElemPtr m_restTail
;
66 struct PoolMemoryAllocator::BlockChain
68 char m_fill
[eBlockSize
-sizeof(void*)];
73 PoolMemoryAllocator::PoolElement
PoolMemoryAllocator::s_pool
[eTableSize
];
74 PoolMemoryAllocator::MemElemPtr
PoolMemoryAllocator::s_freeVectors
;
75 PoolMemoryAllocator::BlockChainPtr
PoolMemoryAllocator::s_blocks
;
77 #ifdef OGDF_MEMORY_POOL_NTS
78 PoolMemoryAllocator::MemElemPtr
PoolMemoryAllocator::s_tp
[eTableSize
];
79 #elif defined(OGDF_NO_COMPILER_TLS)
80 CriticalSection
*PoolMemoryAllocator::s_criticalSection
;
81 pthread_key_t
PoolMemoryAllocator::s_tpKey
;
83 CriticalSection
*PoolMemoryAllocator::s_criticalSection
;
84 OGDF_DECL_THREAD
PoolMemoryAllocator::MemElemPtr
PoolMemoryAllocator::s_tp
[eTableSize
];
88 void PoolMemoryAllocator::init()
90 #ifndef OGDF_MEMORY_POOL_NTS
91 #ifdef OGDF_NO_COMPILER_TLS
92 pthread_key_create(&s_tpKey
,NULL
);
94 s_criticalSection
= new CriticalSection(500);
100 void PoolMemoryAllocator::initThread() {
101 #if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS)
102 pthread_setspecific(s_tpKey
,calloc(eTableSize
,sizeof(MemElemPtr
)));
107 void PoolMemoryAllocator::cleanup()
109 BlockChainPtr p
= s_blocks
;
111 BlockChainPtr pNext
= p
->m_next
;
116 #ifndef OGDF_MEMORY_POOL_NTS
117 #ifdef OGDF_NO_COMPILER_TLS
118 pthread_key_delete(s_tpKey
);
120 delete s_criticalSection
;
125 bool PoolMemoryAllocator::checkSize(size_t nBytes
) {
126 return nBytes
< eTableSize
;
130 void *PoolMemoryAllocator::allocate(size_t nBytes
) {
131 #if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS)
132 MemElemPtr
*pFreeBytes
= ((MemElemPtr
*)pthread_getspecific(s_tpKey
))+nBytes
;
134 MemElemPtr
*pFreeBytes
= s_tp
+nBytes
;
136 if (OGDF_LIKELY(*pFreeBytes
!= 0)) {
137 MemElemPtr p
= *pFreeBytes
;
138 *pFreeBytes
= p
->m_next
;
141 return fillPool(*pFreeBytes
,__uint16(nBytes
));
146 void PoolMemoryAllocator::deallocate(size_t nBytes
, void *p
) {
147 #if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS)
148 MemElemPtr
*pFreeBytes
= ((MemElemPtr
*)pthread_getspecific(s_tpKey
))+nBytes
;
150 MemElemPtr
*pFreeBytes
= s_tp
+nBytes
;
152 MemElemPtr(p
)->m_next
= *pFreeBytes
;
153 *pFreeBytes
= MemElemPtr(p
);
157 void PoolMemoryAllocator::deallocateList(size_t nBytes
, void *pHead
, void *pTail
) {
158 #if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS)
159 MemElemPtr
*pFreeBytes
= ((MemElemPtr
*)pthread_getspecific(s_tpKey
))+nBytes
;
161 MemElemPtr
*pFreeBytes
= s_tp
+nBytes
;
163 MemElemPtr(pTail
)->m_next
= *pFreeBytes
;
164 *pFreeBytes
= MemElemPtr(pHead
);
168 PoolMemoryAllocator::MemElemExPtr
169 PoolMemoryAllocator::collectGroups(
171 MemElemPtr
&pRestHead
,
172 MemElemPtr
&pRestTail
,
175 int n
= slicesPerBlock(nBytes
);
178 #if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS)
179 MemElemPtr p
= ((MemElemPtr
*)pthread_getspecific(s_tpKey
))[nBytes
];
181 MemElemPtr p
= s_tp
[nBytes
];
183 MemElemExPtr pStart
= 0, pLast
= 0;
187 MemElemPtr pHead
= p
, pTail
;
191 } while(++i
< n
&& p
!= 0);
196 pStart
= MemElemExPtr(pHead
);
198 pLast
->m_down
= MemElemExPtr(pHead
);
199 pLast
= MemElemExPtr(pHead
);
214 void PoolMemoryAllocator::flushPoolSmall(__uint16 nBytes
)
216 int n
= slicesPerBlock(nBytes
< eMinBytes
? eMinBytes
: nBytes
);
217 PoolElement
&pe
= s_pool
[nBytes
];
219 #if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS)
220 MemElemPtr p
= ((MemElemPtr
*)pthread_getspecific(s_tpKey
))[nBytes
];
222 MemElemPtr p
= s_tp
[nBytes
];
224 if(pe
.m_restHead
!= 0) {
225 pe
.m_restTail
->m_next
= p
;
233 MemElemPtr pHead
= p
, pTail
;
237 } while(++i
< n
&& p
!= 0);
241 pe
.m_currentVector
->m_pool
[pe
.m_index
] = pHead
;
244 pe
.m_restHead
= pHead
;
245 pe
.m_restTail
= pTail
;
252 void PoolMemoryAllocator::incVectorSlot(PoolElement
&pe
)
254 if(pe
.m_currentVector
== 0 || ++pe
.m_index
== ePoolVectorLength
) {
255 if(s_freeVectors
== 0)
256 s_freeVectors
= allocateBlock(sizeof(PoolVector
));
258 PoolVector
*pv
= (PoolVector
*)s_freeVectors
;
259 s_freeVectors
= MemElemPtr(pv
)->m_next
;
260 pe
.m_currentVector
= pv
;
266 void PoolMemoryAllocator::flushPool(__uint16 nBytes
)
268 #ifndef OGDF_MEMORY_POOL_NTS
269 if(nBytes
>= sizeof(MemElemEx
)) {
270 MemElemPtr pRestHead
, pRestTail
;
272 MemElemExPtr pStart
= collectGroups(nBytes
, pRestHead
, pRestTail
, nRest
);
274 s_criticalSection
->enter();
275 PoolElement
&pe
= s_pool
[nBytes
];
279 pe
.m_currentVector
->m_pool
[pe
.m_index
] = MemElemPtr(pStart
);
280 pStart
= pStart
->m_down
;
283 int n
= slicesPerBlock(nBytes
);
284 pRestTail
->m_next
= pe
.m_restTail
;
285 int nTotal
= nRest
+ pe
.m_restCount
;
287 MemElemPtr p
= pe
.m_restHead
;
291 pe
.m_restHead
= p
->m_next
;
292 pe
.m_restCount
= nTotal
-n
;
294 pe
.m_currentVector
->m_pool
[pe
.m_index
] = pRestHead
;
296 pe
.m_restHead
= pRestHead
;
297 pe
.m_restCount
= nTotal
;
300 s_criticalSection
->leave();
303 s_criticalSection
->enter();
304 flushPoolSmall(nBytes
);
305 s_criticalSection
->leave();
311 void PoolMemoryAllocator::flushPool()
313 #ifndef OGDF_MEMORY_POOL_NTS
314 for(__uint16 nBytes
= 1; nBytes
< eTableSize
; ++nBytes
) {
315 #ifdef OGDF_NO_COMPILER_TLS
316 MemElemPtr p
= ((MemElemPtr
*)pthread_getspecific(s_tpKey
))[nBytes
];
318 MemElemPtr p
= s_tp
[nBytes
];
327 void *PoolMemoryAllocator::fillPool(MemElemPtr
&pFreeBytes
, __uint16 nBytes
)
329 #ifdef OGDF_MEMORY_POOL_NTS
330 pFreeBytes
= allocateBlock(nBytes
);
333 s_criticalSection
->enter();
335 PoolElement
&pe
= s_pool
[nBytes
];
336 if(pe
.m_currentVector
!= 0) {
337 pFreeBytes
= pe
.m_currentVector
->m_pool
[pe
.m_index
];
338 if(--pe
.m_index
< 0) {
339 PoolVector
*pV
= pe
.m_currentVector
;
340 pe
.m_currentVector
= pV
->m_prev
;
341 pe
.m_index
= ePoolVectorLength
-1;
342 MemElemPtr(pV
)->m_next
= s_freeVectors
;
343 s_freeVectors
= MemElemPtr(pV
);
345 s_criticalSection
->leave();
348 s_criticalSection
->leave();
349 pFreeBytes
= allocateBlock(nBytes
);
353 MemElemPtr p
= pFreeBytes
;
354 pFreeBytes
= p
->m_next
;
359 // __asm __volatile ("":::"memory") GLIBC
362 PoolMemoryAllocator::MemElemPtr
363 PoolMemoryAllocator::allocateBlock(__uint16 nBytes
)
365 if(nBytes
< eMinBytes
)
368 MemElemPtr pBlock
= (MemElemPtr
) malloc(eBlockSize
);
370 // we altogether create nSlices slices
372 int nSlices
= slicesPerBlock(nBytes
,nWords
);
374 MemElemPtr pHead
= MemElemPtr(pBlock
);
375 BlockChainPtr(pBlock
)->m_next
= s_blocks
;
376 s_blocks
= BlockChainPtr(pBlock
);
379 pBlock
= pBlock
->m_next
= pBlock
+nWords
;
380 } while(--nSlices
> 1);
381 MemElemPtr(pBlock
)->m_next
= 0;
387 size_t PoolMemoryAllocator::memoryAllocatedInBlocks()
389 #ifndef OGDF_MEMORY_POOL_NTS
390 s_criticalSection
->enter();
394 for (BlockChainPtr p
= s_blocks
; p
!= 0; p
= p
->m_next
)
397 #ifndef OGDF_MEMORY_POOL_NTS
398 s_criticalSection
->leave();
401 return nBlocks
* eBlockSize
;
405 size_t PoolMemoryAllocator::memoryInGlobalFreeList()
407 #ifndef OGDF_MEMORY_POOL_NTS
408 s_criticalSection
->enter();
411 size_t bytesFree
= 0;
412 for (int sz
= 1; sz
< eTableSize
; ++sz
)
414 const PoolElement
&pe
= s_pool
[sz
];
415 PoolVector
*pv
= pe
.m_currentVector
;
416 for(; pv
!= 0; pv
= pv
->m_prev
)
417 bytesFree
+= ePoolVectorLength
*sz
;
418 if(pe
.m_restHead
!= 0)
419 bytesFree
+= pe
.m_restCount
;
422 #ifndef OGDF_MEMORY_POOL_NTS
423 s_criticalSection
->leave();
430 size_t PoolMemoryAllocator::memoryInThreadFreeList()
432 size_t bytesFree
= 0;
433 for (int sz
= 1; sz
< eTableSize
; ++sz
)
435 #if !defined(OGDF_MEMORY_POOL_NTS) && defined(OGDF_NO_COMPILER_TLS)
436 MemElemPtr p
= ((MemElemPtr
*)pthread_getspecific(s_tpKey
))[sz
];
438 MemElemPtr p
= s_tp
[sz
];
440 for(; p
!= 0; p
= p
->m_next
)