////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// This program 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, either version 3 of the License, or
// (at your option) any later version.
//
// 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. If not, see .
////////////////////////////////////////////////////////////////////////
#ifdef __OTSERV_ALLOCATOR__
#ifndef __ALLOCATOR__
#define __ALLOCATOR__
#include "otsystem.h"
#include
#include
#include
#include
template
class dummyallocator
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
template struct rebind
{
typedef dummyallocator other;
};
template
dummyallocator(const dummyallocator&) throw() {}
dummyallocator(const dummyallocator&) throw() {}
dummyallocator() throw() {}
virtual ~dummyallocator() throw() {}
pointer address(reference x) const {return &x;}
const_pointer address(const_reference x) const {return &x;}
pointer allocate(size_type n, void* hint32_t = 0)
{
return static_cast(std::malloc(n * sizeof(T)));
}
void deallocate(pointer p, size_type n)
{
std::free(static_cast(p));
}
size_type max_size() const throw()
{
return std::numeric_limits::max() / sizeof(T);
}
void construct(pointer p, const T& val)
{
new(static_cast(p))T(val);
}
void destroy(pointer p)
{
p->~T();
}
};
void* operator new(size_t bytes, int32_t dummy);
void* operator new(size_t bytes);
void* operator new[](size_t bytes);
void operator delete(void* p);
void operator delete[](void* p);
#ifdef _MSC_VER
void operator delete(void* p, int32_t dummy);
void operator delete[](void* p, int32_t dummy);
#endif
#ifdef __OTSERV_ALLOCATOR_STATS__
void allocatorStatsThread(void* a);
#endif
struct poolTag
{
size_t poolbytes;
};
class PoolManager
{
public:
static PoolManager* getInstance()
{
static PoolManager instance;
return &instance;
}
void* allocate(size_t size)
{
Pools::iterator it;
poolLock.lock();
for(it = pools.begin(); it != pools.end(); ++it)
{
if(it->first >= size + sizeof(poolTag))
{
poolTag* tag = reinterpret_cast(it->second->malloc());
#ifdef __OTSERV_ALLOCATOR_STATS__
if(!tag)
dumpStats();
#endif
tag->poolbytes = it->first;
#ifdef __OTSERV_ALLOCATOR_STATS__
poolsStats[it->first]->allocations++;
poolsStats[it->first]->unused+= it->first - (size + sizeof(poolTag));
#endif
poolLock.unlock();
return tag + 1;
}
}
poolTag* tag = reinterpret_cast(std::malloc(size + sizeof(poolTag)));
#ifdef __OTSERV_ALLOCATOR_STATS__
poolsStats[0]->allocations++;
poolsStats[0]->unused += size;
#endif
tag->poolbytes = 0;
poolLock.unlock();
return tag + 1;
}
void deallocate(void* deletable)
{
if(!deletable)
return;
poolTag* const tag = reinterpret_cast(deletable) - 1U;
poolLock.lock();
if(tag->poolbytes)
{
Pools::iterator it;
it = pools.find(tag->poolbytes);
it->second->free(tag);
#ifdef __OTSERV_ALLOCATOR_STATS__
poolsStats[it->first]->deallocations++;
#endif
}
else
{
std::free(tag);
#ifdef __OTSERV_ALLOCATOR_STATS__
poolsStats[0]->deallocations++;
#endif
}
poolLock.unlock();
}
#ifdef __OTSERV_ALLOCATOR_STATS__
void dumpStats()
{
time_t rawtime;
time(&rawtime);
std::ofstream output("data/logs/memory_dump.log", std::ios_base::app);
output << "OTServ Allocator Stats: " << std::ctime(&rawtime) << std::endl;
for(PoolsStats::iterator it = poolsStats.begin(); it != poolsStats.end(); ++it)
{
output << (int32_t)(it->first) << " alloc: " << (int64_t)(it->second->allocations) << " dealloc: ";
output << (int64_t)(it->second->deallocations) << " unused: " << (int64_t)(it->second->unused);
if(it->second->allocations != 0 && it->first != 0)
{
output << " avg: " << (int64_t)((it->first) - (it->second->unused) / (it->second->allocations));
output << " %unused: " << (int64_t)((it->second->unused) * 100 / (it->second->allocations) / (it->first));
}
output << " N: " << ((int64_t)(it->second->allocations) - (int64_t)(it->second->deallocations)) << std::endl;
}
output << std::endl;
output.close();
}
#endif
virtual ~PoolManager()
{
Pools::iterator it = pools.begin();
while(it != pools.end())
{
std::free(it->second);
it = pools.erase(it);
}
#ifdef __OTSERV_ALLOCATOR_STATS__
for(PoolsStats::iterator sit = poolsStats.begin(); sit != poolsStats.end();)
{
std::free(sit->second);
sit = poolsStats.erase(sit);
}
#endif
}
private:
void addPool(size_t size, size_t nextSize)
{
pools[size] = new(0) boost::pool(size, nextSize);
#ifdef __OTSERV_ALLOCATOR_STATS__
t_PoolStats * tmp = new(0) t_PoolStats;
tmp->unused = tmp->allocations = tmp->deallocations = 0;
poolsStats[size] = tmp;
#endif
}
PoolManager()
{
addPool(4 + sizeof(poolTag), 32768);
addPool(20 + sizeof(poolTag), 32768);
addPool(32 + sizeof(poolTag), 32768);
addPool(48 + sizeof(poolTag), 32768);
addPool(96 + sizeof(poolTag), 16384);
addPool(128 + sizeof(poolTag), 1024);
addPool(384 + sizeof(poolTag), 2048);
addPool(512 + sizeof(poolTag), 128);
addPool(1024 + sizeof(poolTag), 128);
addPool(8192 + sizeof(poolTag), 128);
addPool(16384 + sizeof(poolTag), 128);
addPool(60 + sizeof(poolTag), 10000); //Tile class
addPool(36 + sizeof(poolTag), 10000); //Item class
#ifdef __OTSERV_ALLOCATOR_STATS__
t_PoolStats * tmp = new(0) t_PoolStats;
tmp->unused = tmp->allocations = tmp->deallocations = 0;
poolsStats[0] = tmp;
#endif
}
PoolManager(const PoolManager&);
const PoolManager& operator=(const PoolManager&);
typedef std::map*, std::less,
dummyallocator* > > > Pools;
Pools pools;
#ifdef __OTSERV_ALLOCATOR_STATS__
struct t_PoolStats
{
int64_t allocations, deallocations, unused;
};
typedef std::map, dummyallocator > > PoolsStats;
PoolsStats poolsStats;
#endif
boost::recursive_mutex poolLock;
};
#endif
#endif