diff options
Diffstat (limited to 'kcachegrind/kcachegrind/pool.cpp')
-rw-r--r-- | kcachegrind/kcachegrind/pool.cpp | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/kcachegrind/kcachegrind/pool.cpp b/kcachegrind/kcachegrind/pool.cpp new file mode 100644 index 00000000..ec8d4074 --- /dev/null +++ b/kcachegrind/kcachegrind/pool.cpp @@ -0,0 +1,258 @@ +/* This file is part of KCachegrind. + Copyright (C) 2002-2004 Josef Weidendorfer <Josef.Weidendorfer@gmx.de> + + KCachegrind is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation, version 2. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <string.h> +#include <stdlib.h> +#include <qglobal.h> +#include "pool.h" + +// FixPool + +#define CHUNK_SIZE 100000 + +struct SpaceChunk +{ + struct SpaceChunk* next; + unsigned int used; + char space[1]; +}; + +FixPool::FixPool() +{ + _first = _last = 0; + _reservation = 0; + _count = 0; + _size = 0; +} + +FixPool::~FixPool() +{ + struct SpaceChunk* chunk = _first, *next; + + while(chunk) { + next = chunk->next; + free(chunk); + chunk = next; + } + + if (0) qDebug("~FixPool: Had %d objects with total size %d\n", + _count, _size); +} + +void* FixPool::allocate(unsigned int size) +{ + if (!ensureSpace(size)) return 0; + + _reservation = 0; + void* result = _last->space + _last->used; + _last->used += size; + + _count++; + _size += size; + + return result; +} + +void* FixPool::reserve(unsigned int size) +{ + if (!ensureSpace(size)) return 0; + _reservation = size; + + return _last->space + _last->used; +} + + +bool FixPool::allocateReserved(unsigned int size) +{ + if (_reservation < size) return false; + + _reservation = 0; + _last->used += size; + + _count++; + _size += size; + + return true; +} + +bool FixPool::ensureSpace(unsigned int size) +{ + if (_last && _last->used + size <= CHUNK_SIZE) return true; + + struct SpaceChunk* newChunk; + + // we don't allow allocation sizes > CHUNK_SIZE + if (size > CHUNK_SIZE) return false; + + newChunk = (struct SpaceChunk*) malloc(sizeof(struct SpaceChunk) + + CHUNK_SIZE); + newChunk->next = 0; + newChunk->used = 0; + + if (!_last) { + _last = _first = newChunk; + } + else { + _last->next = newChunk; + _last = newChunk; + } + return true; +} + + +// DynPool + +DynPool::DynPool() +{ + _data = (char*) malloc(CHUNK_SIZE); + _used = 0; + _size = CHUNK_SIZE; + + // end marker + *(int*)_data = 0; +} + +DynPool::~DynPool() +{ + // we could check for correctness by iteration over all objects + + ::free(_data); +} + +bool DynPool::allocate(char** ptr, unsigned int size) +{ + // round up to multiple of 4 + size = (size+3) & ~3; + + /* need 12 bytes more: + * - 4 bytes for forward chain + * - 4 bytes for pointer to ptr + * - 4 bytes as end marker (not used for new object) + */ + if (!ensureSpace(size + 12)) return false; + + char** obj = (char**) (_data+_used); + obj[0] = (char*)(_data + _used + size + 8); + obj[1] = (char*)ptr; + *(int*)(_data+_used+size+8) = 0; + *ptr = _data+_used+8; + + _used += size + 8; + + return true; +} + +void DynPool::free(char** ptr) +{ + if (!ptr || + !*ptr || + (*(char**)(*ptr - 4)) != (char*)ptr ) + qFatal("Chaining error in DynPool::free"); + + (*(char**)(*ptr - 4)) = 0; + *ptr = 0; +} + +bool DynPool::ensureSpace(unsigned int size) +{ + if (_used + size <= _size) return true; + + unsigned int newsize = _size *3/2 + CHUNK_SIZE; + char* newdata = (char*) malloc(newsize); + + unsigned int freed = 0, len; + char **p, **pnext, **pnew; + + qDebug("DynPool::ensureSpace size: %d => %d, used %d. %p => %p", + _size, newsize, _used, _data, newdata); + + pnew = (char**) newdata; + p = (char**) _data; + while(*p) { + pnext = (char**) *p; + len = (char*)pnext - (char*)p; + + if (0) qDebug(" [%8p] Len %d (ptr %p), freed %d (=> %p)", + p, len, p[1], freed, pnew); + + /* skip freed space ? */ + if (p[1] == 0) { + freed += len; + p = pnext; + continue; + } + + // new and old still at same address ? + if (pnew == p) { + pnew = p = pnext; + continue; + } + + // copy object + pnew[0] = (char*)pnew + len; + pnew[1] = p[1]; + memcpy((char*)pnew + 8, (char*)p + 8, len-8); + + // update pointer to object + char** ptr = (char**) p[1]; + if (*ptr != ((char*)p)+8) + qFatal("Chaining error in DynPool::ensureSpace"); + *ptr = ((char*)pnew)+8; + + pnew = (char**) pnew[0]; + p = pnext; + } + pnew[0] = 0; + + unsigned int newused = (char*)pnew - (char*)newdata; + qDebug("DynPool::ensureSpace size: %d => %d, used %d => %d (%d freed)", + _size, newsize, _used, newused, freed); + + ::free(_data); + _data = newdata; + _size = newsize; + _used = newused; + + return true; +} + +/* Testing the DynPool +int main() +{ + char* bufs[CHUNK_SIZE]; + int i; + + DynPool p; + + for(i=0;i<CHUNK_SIZE;i++) { + p.allocate(bufs+i, 10+i%10); + if (((i%3)==0) && (i>20)) + p.free(bufs+i-20); + } + + for(i=0;i<CHUNK_SIZE;i++) { + if ((bufs[i]==0) || ((i%7)==0)) continue; + p.free(bufs+i); + } + + for(i=0;i<CHUNK_SIZE;i++) { + if (bufs[i]) continue; + p.allocate(bufs+i, 10+i%10); + } +} +*/ |