TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
G3D::BufferPool Class Reference

Classes

class  MemBlock
 

Public Types

enum  { tinyBufferSize = 128, smallBufferSize = 1024, medBufferSize = 4096 }
 
enum  { maxTinyBuffers = 250000, maxSmallBuffers = 40000, maxMedBuffers = 5000 }
 

Public Member Functions

 BufferPool ()
 
 ~BufferPool ()
 
UserPtr realloc (UserPtr ptr, size_t bytes)
 
UserPtr malloc (size_t bytes)
 
void free (UserPtr ptr)
 
std::string performance () const
 
std::string status () const
 

Public Attributes

int totalMallocs
 
int mallocsFromTinyPool
 
int mallocsFromSmallPool
 
int mallocsFromMedPool
 
volatile size_t bytesAllocated
 

Private Types

typedef void * UserPtr
 
typedef void * RealPtr
 

Private Member Functions

void lock ()
 
void unlock ()
 
UserPtr tinyMalloc (size_t bytes)
 
bool inTinyHeap (UserPtr ptr)
 
void tinyFree (UserPtr ptr)
 
void flushPool (MemBlock *pool, int &poolSize)
 
UserPtr malloc (MemBlock *pool, int &poolSize, size_t bytes)
 

Private Attributes

MemBlock smallPool [maxSmallBuffers]
 
int smallPoolSize
 
MemBlock medPool [maxMedBuffers]
 
int medPoolSize
 
void * tinyPool [maxTinyBuffers]
 
int tinyPoolSize
 
void * tinyHeap
 
Spinlock m_lock
 

Member Typedef Documentation

typedef void* G3D::BufferPool::RealPtr
private

Actual block allocated on the heap

typedef void* G3D::BufferPool::UserPtr
private

Pointer given to the program. Unless in the tiny heap, the user size of the block is stored right in front of the pointer as a uint32.

Member Enumeration Documentation

anonymous enum

Only store buffers up to these sizes (in bytes) in each pool-> Different pools have different management strategies.

A large block is preallocated for tiny buffers; they are used with tremendous frequency. Other buffers are allocated as demanded. Tiny buffers are 128 bytes long because that seems to align well with cache sizes on many machines.

Enumerator
tinyBufferSize 
smallBufferSize 
medBufferSize 
979 {tinyBufferSize = 128, smallBufferSize = 1024, medBufferSize = 4096};
Definition: System.cpp:979
Definition: System.cpp:979
Definition: System.cpp:979
anonymous enum

Most buffers we're allowed to store. 250000 * { 128 | 256} = {32 | 64} MB (preallocated) 40000 * {1024 | 2048} = {40 | 80} MB (allocated on demand) 5000 * {4096 | 8192} = {20 | 40} MB (allocated on demand)

Enumerator
maxTinyBuffers 
maxSmallBuffers 
maxMedBuffers 
988 {maxTinyBuffers = 250000, maxSmallBuffers = 40000, maxMedBuffers = 5000};
Definition: System.cpp:988
Definition: System.cpp:988
Definition: System.cpp:988

Constructor & Destructor Documentation

G3D::BufferPool::BufferPool ( )
inline

----------------------------—— old mutex

-------------------------------— old mutex

1148  {
1149  totalMallocs = 0;
1150 
1151  mallocsFromTinyPool = 0;
1153  mallocsFromMedPool = 0;
1154 
1155  bytesAllocated = 0;
1156 
1157  tinyPoolSize = 0;
1158  tinyHeap = NULL;
1159 
1160  smallPoolSize = 0;
1161 
1162  medPoolSize = 0;
1163 
1164 
1165  // Initialize the tiny heap as a bunch of pointers into one
1166  // pre-allocated buffer.
1168  for (int i = 0; i < maxTinyBuffers; ++i) {
1169  tinyPool[i] = (uint8*)tinyHeap + (tinyBufferSize * i);
1170  }
1172 
1173 #if 0
1174 # ifdef G3D_WINDOWS
1175  InitializeCriticalSection(&mutex);
1176 # else
1177  pthread_mutex_init(&mutex, NULL);
1178 # endif
1179 #endif
1180  }
void * tinyHeap
Definition: System.cpp:1021
Definition: System.cpp:979
void * tinyPool[maxTinyBuffers]
Definition: System.cpp:1017
int tinyPoolSize
Definition: System.cpp:1018
arena_t NULL
Definition: jemalloc_internal.h:624
int medPoolSize
Definition: System.cpp:1011
int mallocsFromTinyPool
Definition: System.cpp:1136
volatile size_t bytesAllocated
Definition: System.cpp:1146
int mallocsFromMedPool
Definition: System.cpp:1138
UserPtr malloc(MemBlock *pool, int &poolSize, size_t bytes)
Definition: System.cpp:1107
uint8_t uint8
Definition: Define.h:152
int smallPoolSize
Definition: System.cpp:1008
int mallocsFromSmallPool
Definition: System.cpp:1137
int totalMallocs
Definition: System.cpp:1135
Definition: System.cpp:988

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

G3D::BufferPool::~BufferPool ( )
inline
1183  {
1184  ::free(tinyHeap);
1187 #if 0 //-------------------------------- old mutex
1188 # ifdef G3D_WINDOWS
1189  DeleteCriticalSection(&mutex);
1190 # else
1191  // No destruction on pthreads
1192 # endif
1193 #endif //--------------------------------old mutex
1194  }
void * tinyHeap
Definition: System.cpp:1021
int medPoolSize
Definition: System.cpp:1011
void free(UserPtr ptr)
Definition: System.cpp:1327
MemBlock medPool[maxMedBuffers]
Definition: System.cpp:1010
void flushPool(MemBlock *pool, int &poolSize)
Definition: System.cpp:1094
MemBlock smallPool[maxSmallBuffers]
Definition: System.cpp:1007
int smallPoolSize
Definition: System.cpp:1008

+ Here is the call graph for this function:

Member Function Documentation

void G3D::BufferPool::flushPool ( MemBlock pool,
int &  poolSize 
)
inlineprivate
1094  {
1095  for (int i = 0; i < poolSize; ++i) {
1096  bytesAllocated -= USERSIZE_TO_REALSIZE(pool[i].bytes);
1097  ::free(USERPTR_TO_REALPTR(pool[i].ptr));
1098  pool[i].ptr = NULL;
1099  pool[i].bytes = 0;
1100  }
1101  poolSize = 0;
1102  }
arena_t NULL
Definition: jemalloc_internal.h:624
void free(UserPtr ptr)
Definition: System.cpp:1327
#define USERPTR_TO_REALPTR(x)
Definition: System.cpp:959
volatile size_t bytesAllocated
Definition: System.cpp:1146
#define USERSIZE_TO_REALSIZE(x)
Definition: System.cpp:960

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void G3D::BufferPool::free ( UserPtr  ptr)
inline
1327  {
1328  if (ptr == NULL) {
1329  // Free does nothing on null pointers
1330  return;
1331  }
1332 
1333  assert(isValidPointer(ptr));
1334 
1335  if (inTinyHeap(ptr)) {
1336  lock();
1337  tinyFree(ptr);
1338  unlock();
1339  return;
1340  }
1341 
1342  size_t bytes = USERSIZE_FROM_USERPTR(ptr);
1343 
1344  lock();
1345  if (bytes <= smallBufferSize) {
1347  smallPool[smallPoolSize] = MemBlock(ptr, bytes);
1348  ++smallPoolSize;
1349  unlock();
1350  return;
1351  }
1352  } else if (bytes <= medBufferSize) {
1353  if (medPoolSize < maxMedBuffers) {
1354  medPool[medPoolSize] = MemBlock(ptr, bytes);
1355  ++medPoolSize;
1356  unlock();
1357  return;
1358  }
1359  }
1361  unlock();
1362 
1363  // Free; the buffer pools are full or this is too big to store.
1364  ::free(USERPTR_TO_REALPTR(ptr));
1365  }
Definition: System.cpp:988
Definition: System.cpp:979
arena_t NULL
Definition: jemalloc_internal.h:624
void tinyFree(UserPtr ptr)
Definition: System.cpp:1072
bool isValidPointer(const void *x)
Definition: debug.h:54
void free(UserPtr ptr)
Definition: System.cpp:1327
int medPoolSize
Definition: System.cpp:1011
#define USERPTR_TO_REALPTR(x)
Definition: System.cpp:959
MemBlock medPool[maxMedBuffers]
Definition: System.cpp:1010
volatile size_t bytesAllocated
Definition: System.cpp:1146
Definition: System.cpp:988
#define USERSIZE_FROM_USERPTR(u)
Definition: System.cpp:962
MemBlock smallPool[maxSmallBuffers]
Definition: System.cpp:1007
#define USERSIZE_TO_REALSIZE(x)
Definition: System.cpp:960
int smallPoolSize
Definition: System.cpp:1008
bool inTinyHeap(UserPtr ptr)
Definition: System.cpp:1066
Definition: System.cpp:979
void lock()
Definition: System.cpp:1025
void unlock()
Definition: System.cpp:1029

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool G3D::BufferPool::inTinyHeap ( UserPtr  ptr)
inlineprivate

Returns true if this is a pointer into the tiny heap.

1066  {
1067  return
1068  (ptr >= tinyHeap) &&
1070  }
void * tinyHeap
Definition: System.cpp:1021
Definition: System.cpp:979
uint8_t uint8
Definition: Define.h:152
Definition: System.cpp:988

+ Here is the caller graph for this function:

void G3D::BufferPool::lock ( )
inlineprivate
1025  {
1026  m_lock.lock();
1027  }
bool lock()
Definition: GMutex.h:52
Spinlock m_lock
Definition: System.cpp:1023

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

UserPtr G3D::BufferPool::malloc ( MemBlock pool,
int &  poolSize,
size_t  bytes 
)
inlineprivate

Allocate out of a specific pool. Return NULL if no suitable memory was found.

1107  {
1108 
1109  // OPT: find the smallest block that satisfies the request.
1110 
1111  // See if there's something we can use in the buffer pool.
1112  // Search backwards since usually we'll re-use the last one.
1113  for (int i = (int)poolSize - 1; i >= 0; --i) {
1114  if (pool[i].bytes >= bytes) {
1115  // We found a suitable entry in the pool.
1116 
1117  // No need to offset the pointer; it is already offset
1118  UserPtr ptr = pool[i].ptr;
1119 
1120  // Remove this element from the pool, replacing it with
1121  // the one from the end (same as Array::fastRemove)
1122  --poolSize;
1123  pool[i] = pool[poolSize];
1124 
1125  return ptr;
1126  }
1127  }
1128 
1129  return NULL;
1130  }
void * UserPtr
Definition: System.cpp:993
arena_t NULL
Definition: jemalloc_internal.h:624

+ Here is the caller graph for this function:

UserPtr G3D::BufferPool::malloc ( size_t  bytes)
inline
1234  {
1235  lock();
1236  ++totalMallocs;
1237 
1238  if (bytes <= tinyBufferSize) {
1239 
1240  UserPtr ptr = tinyMalloc(bytes);
1241 
1242  if (ptr) {
1244  unlock();
1245  return ptr;
1246  }
1247 
1248  }
1249 
1250  // Failure to allocate a tiny buffer is allowed to flow
1251  // through to a small buffer
1252  if (bytes <= smallBufferSize) {
1253 
1254  UserPtr ptr = malloc(smallPool, smallPoolSize, bytes);
1255 
1256  if (ptr) {
1258  unlock();
1259  return ptr;
1260  }
1261 
1262  } else if (bytes <= medBufferSize) {
1263  // Note that a small allocation failure does *not* fall
1264  // through into a medium allocation because that would
1265  // waste the medium buffer's resources.
1266 
1267  UserPtr ptr = malloc(medPool, medPoolSize, bytes);
1268 
1269  if (ptr) {
1271  unlock();
1272  debugAssertM(ptr != NULL, "BufferPool::malloc returned NULL");
1273  return ptr;
1274  }
1275  }
1276 
1278  unlock();
1279 
1280  // Heap allocate
1281 
1282  // Allocate 4 extra bytes for our size header (unfortunate,
1283  // since malloc already added its own header).
1284  RealPtr ptr = ::malloc(USERSIZE_TO_REALSIZE(bytes));
1285 
1286  if (ptr == NULL) {
1287 # ifdef G3D_WINDOWS
1288  // Check for memory corruption
1289  alwaysAssertM(_CrtCheckMemory() == TRUE, "Heap corruption detected.");
1290 # endif
1291 
1292  // Flush memory pools to try and recover space
1295  ptr = ::malloc(USERSIZE_TO_REALSIZE(bytes));
1296  }
1297 
1298  if (ptr == NULL) {
1299  if ((System::outOfMemoryCallback() != NULL) &&
1300  (System::outOfMemoryCallback()(USERSIZE_TO_REALSIZE(bytes), true) == true)) {
1301  // Re-attempt the malloc
1302  ptr = ::malloc(USERSIZE_TO_REALSIZE(bytes));
1303  }
1304  }
1305 
1306  if (ptr == NULL) {
1307  if (System::outOfMemoryCallback() != NULL) {
1308  // Notify the application
1310  }
1311 # ifdef G3D_DEBUG
1312  debugPrintf("::malloc(%d) returned NULL\n", (int)USERSIZE_TO_REALSIZE(bytes));
1313 # endif
1314  debugAssertM(ptr != NULL,
1315  "::malloc returned NULL. Either the "
1316  "operating system is out of memory or the "
1317  "heap is corrupt.");
1318  return NULL;
1319  }
1320 
1321  ((size_t*)ptr)[0] = bytes;
1322 
1323  return REALPTR_TO_USERPTR(ptr);
1324  }
std::string __cdecl debugPrintf(const char *fmt...) G3D_CHECK_PRINTF_ARGS
Definition: debugAssert.cpp:355
Definition: System.cpp:979
UserPtr tinyMalloc(size_t bytes)
Definition: System.cpp:1036
#define REALPTR_TO_USERPTR(x)
Definition: System.cpp:958
Definition: System.cpp:979
void * UserPtr
Definition: System.cpp:993
arena_t NULL
Definition: jemalloc_internal.h:624
#define debugAssertM(exp, message)
Definition: debugAssert.h:161
void * RealPtr
Definition: System.cpp:996
int medPoolSize
Definition: System.cpp:1011
int mallocsFromTinyPool
Definition: System.cpp:1136
MemBlock medPool[maxMedBuffers]
Definition: System.cpp:1010
volatile size_t bytesAllocated
Definition: System.cpp:1146
void flushPool(MemBlock *pool, int &poolSize)
Definition: System.cpp:1094
MemBlock smallPool[maxSmallBuffers]
Definition: System.cpp:1007
int mallocsFromMedPool
Definition: System.cpp:1138
UserPtr malloc(MemBlock *pool, int &poolSize, size_t bytes)
Definition: System.cpp:1107
static OutOfMemoryCallback outOfMemoryCallback()
Definition: System.h:398
#define USERSIZE_TO_REALSIZE(x)
Definition: System.cpp:960
int smallPoolSize
Definition: System.cpp:1008
int mallocsFromSmallPool
Definition: System.cpp:1137
int totalMallocs
Definition: System.cpp:1135
Definition: System.cpp:979
#define alwaysAssertM(exp, message)
Definition: debugAssert.h:165
void lock()
Definition: System.cpp:1025
void unlock()
Definition: System.cpp:1029

+ Here is the call graph for this function:

std::string G3D::BufferPool::performance ( ) const
inline
1367  {
1368  if (totalMallocs > 0) {
1369  int pooled = mallocsFromTinyPool +
1372 
1373  int total = totalMallocs;
1374 
1375  return format("malloc performance: %5.1f%% <= %db, %5.1f%% <= %db, "
1376  "%5.1f%% <= %db, %5.1f%% > %db",
1377  100.0 * mallocsFromTinyPool / total,
1379  100.0 * mallocsFromSmallPool / total,
1381  100.0 * mallocsFromMedPool / total,
1383  100.0 * (1.0 - (double)pooled / total),
1385  } else {
1386  return "No System::malloc calls made yet.";
1387  }
1388  }
Definition: System.cpp:979
Definition: System.cpp:979
int mallocsFromTinyPool
Definition: System.cpp:1136
std::string __cdecl format(const char *fmt...) G3D_CHECK_PRINTF_ARGS
int mallocsFromMedPool
Definition: System.cpp:1138
int mallocsFromSmallPool
Definition: System.cpp:1137
int totalMallocs
Definition: System.cpp:1135
Definition: System.cpp:979

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

UserPtr G3D::BufferPool::realloc ( UserPtr  ptr,
size_t  bytes 
)
inline
1197  {
1198  if (ptr == NULL) {
1199  return malloc(bytes);
1200  }
1201 
1202  if (inTinyHeap(ptr)) {
1203  if (bytes <= tinyBufferSize) {
1204  // The old pointer actually had enough space.
1205  return ptr;
1206  } else {
1207  // Free the old pointer and malloc
1208 
1209  UserPtr newPtr = malloc(bytes);
1210  System::memcpy(newPtr, ptr, tinyBufferSize);
1211  tinyFree(ptr);
1212  return newPtr;
1213 
1214  }
1215  } else {
1216  // In one of our heaps.
1217 
1218  // See how big the block really was
1219  size_t userSize = USERSIZE_FROM_USERPTR(ptr);
1220  if (bytes <= userSize) {
1221  // The old block was big enough.
1222  return ptr;
1223  }
1224 
1225  // Need to reallocate and move
1226  UserPtr newPtr = malloc(bytes);
1227  System::memcpy(newPtr, ptr, userSize);
1228  free(ptr);
1229  return newPtr;
1230  }
1231  }
Definition: System.cpp:979
static void memcpy(void *dst, const void *src, size_t numBytes)
Definition: System.cpp:643
void * UserPtr
Definition: System.cpp:993
arena_t NULL
Definition: jemalloc_internal.h:624
void tinyFree(UserPtr ptr)
Definition: System.cpp:1072
void free(UserPtr ptr)
Definition: System.cpp:1327
#define USERSIZE_FROM_USERPTR(u)
Definition: System.cpp:962
UserPtr malloc(MemBlock *pool, int &poolSize, size_t bytes)
Definition: System.cpp:1107
bool inTinyHeap(UserPtr ptr)
Definition: System.cpp:1066

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

std::string G3D::BufferPool::status ( ) const
inline
1390  {
1391  return format("preallocated shared buffers: %5d/%d x %db",
1393  }
Definition: System.cpp:979
int tinyPoolSize
Definition: System.cpp:1018
std::string __cdecl format(const char *fmt...) G3D_CHECK_PRINTF_ARGS
Definition: System.cpp:988

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void G3D::BufferPool::tinyFree ( UserPtr  ptr)
inlineprivate
1072  {
1073  assert(ptr);
1074  assert(tinyPoolSize < maxTinyBuffers);
1075  // "Tried to free a tiny pool buffer when the tiny pool freelist is full.");
1076 
1077 # ifdef G3D_DEBUG
1078  if (tinyPoolSize > 0) {
1079  UserPtr prevOnHeap = tinyPool[tinyPoolSize - 1];
1080  assert(prevOnHeap != ptr);
1081 // "System::malloc heap corruption detected: "
1082 // "the last two pointers on the freelist are identical (during tinyFree).");
1083  }
1084 # endif
1085 
1086  assert(tinyPool[tinyPoolSize] == NULL);
1087 
1088  // Put the pointer back into the free list
1089  tinyPool[tinyPoolSize] = ptr;
1090  ++tinyPoolSize;
1091 
1092  }
void * tinyPool[maxTinyBuffers]
Definition: System.cpp:1017
void * UserPtr
Definition: System.cpp:993
int tinyPoolSize
Definition: System.cpp:1018
arena_t NULL
Definition: jemalloc_internal.h:624
Definition: System.cpp:988

+ Here is the caller graph for this function:

UserPtr G3D::BufferPool::tinyMalloc ( size_t  bytes)
inlineprivate

Malloc out of the tiny heap. Returns NULL if allocation failed.

1036  {
1037  // Note that we ignore the actual byte size
1038  // and create a constant size block.
1039  (void)bytes;
1040  assert(tinyBufferSize >= bytes);
1041 
1042  UserPtr ptr = NULL;
1043 
1044  if (tinyPoolSize > 0) {
1045  --tinyPoolSize;
1046 
1047  // Return the old last pointer from the freelist
1048  ptr = tinyPool[tinyPoolSize];
1049 
1050 # ifdef G3D_DEBUG
1051  if (tinyPoolSize > 0) {
1052  assert(tinyPool[tinyPoolSize - 1] != ptr);
1053  // "System::malloc heap corruption detected: "
1054  // "the last two pointers on the freelist are identical (during tinyMalloc).");
1055  }
1056 # endif
1057 
1058  // NULL out the entry to help detect corruption
1060  }
1061 
1062  return ptr;
1063  }
Definition: System.cpp:979
void * tinyPool[maxTinyBuffers]
Definition: System.cpp:1017
void * UserPtr
Definition: System.cpp:993
int tinyPoolSize
Definition: System.cpp:1018
arena_t NULL
Definition: jemalloc_internal.h:624

+ Here is the caller graph for this function:

void G3D::BufferPool::unlock ( )
inlineprivate
1029  {
1030  m_lock.unlock();
1031  }
Spinlock m_lock
Definition: System.cpp:1023
void unlock()
Definition: GMutex.h:65

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Member Data Documentation

volatile size_t G3D::BufferPool::bytesAllocated

Amount of memory currently allocated (according to the application). This does not count the memory still remaining in the buffer pool, but does count extra memory required for rounding off to the size of a buffer. Primarily useful for detecting leaks.

Spinlock G3D::BufferPool::m_lock
private
int G3D::BufferPool::mallocsFromMedPool
int G3D::BufferPool::mallocsFromSmallPool
int G3D::BufferPool::mallocsFromTinyPool
MemBlock G3D::BufferPool::medPool[maxMedBuffers]
private
int G3D::BufferPool::medPoolSize
private
MemBlock G3D::BufferPool::smallPool[maxSmallBuffers]
private
int G3D::BufferPool::smallPoolSize
private
void* G3D::BufferPool::tinyHeap
private

Pointer to the data in the tiny pool

void* G3D::BufferPool::tinyPool[maxTinyBuffers]
private

The tiny pool is a single block of storage into which all tiny objects are allocated. This provides better locality for small objects and avoids the search time, since all tiny blocks are exactly the same size.

int G3D::BufferPool::tinyPoolSize
private
int G3D::BufferPool::totalMallocs

Count of memory allocations that have occurred.


The documentation for this class was generated from the following file: